优化第七代英特尔酷睿视频 RAM 中的递增 ASCII 十进制计数器

2023-11-27

我正在尝试针对特定的 Kaby Lake CPU (i5-7300HQ) 优化以下子例程,理想情况下使代码比其原始形式至少快 10 倍。该代码在 16 位实模式下作为软盘式引导加载程序运行。它在屏幕上显示一个十位十进制计数器,计数 0 - 9999999999,然后停止。

我看过 Agner 的优化指南微架构 and Assembly, 指令性能表和英特尔的优化参考手册.

到目前为止我能做的唯一明智的优化就是交换loop指令dec + jnz, 解释here.

另一种可能的优化可能是交换lodsb for mov + dec,但我发现的相关信息是相互矛盾的,有些人说它略有帮助,而另一些人则说它实际上可能会损害现代 CPU 的性能。

我还尝试切换到 32 位模式,并将整个计数器保留在未使用的寄存器对中,以消除任何内存访问,但在阅读了一些内容后,我意识到这 10 位将立即被缓存,并且 L1 缓存之间的延迟差异和寄存器大约只有三倍,所以绝对不值得以这种格式使用计数器的额外开销。

(编者注:add reg延迟为1个周期,add [mem]延迟约为 6 个周期,包括 5 个周期的存储转发延迟。或者更糟糕的是如果[mem]与视频 RAM 一样不可缓存。)

org 7c00h

pos equ 2*(2*80-2)  ;address on screen

;init
cli
mov ax,3
int 10h
mov ax,0b800h
mov es,ax
jmp 0:start

start:
    push cs
    pop ds
    std

    mov ah, 4Eh
    xor cx, cx
    mov bl,'9'

countloop:
    mov cl,10           ;number of digits to add to
    mov si,counter+9    ;start of counter
    mov di,pos          ;screen position

    stc                 ;set carry for first adc
next_digit:
    lodsb               ;load digit
    adc al,0
    cmp bl, al
    jnc print
    add al,-10          ;propagate carry if resulting digit > 9
print:
    mov [si+1],al       ;save new digit
    stosw               ;print

    ;replaced loop with a faster equivalent
    ;loop next_digit
    dec cl
    jnz next_digit

    jnc countloop

    jmp $

counter:
    times 10 db '0'

    times 510-($-$$) db 0
    dw 0aa55h

我的问题是 - 我该怎么做才能达到预期的速度提升?我还可以学习哪些其他材料来更好地理解基本概念?

注:这个is学校作业。虽然直接的答案肯定会有所帮助,但我更希望得到相关学习材料的解释或指示,因为我们没有得到任何解释或指示。

编辑:将代码更改为最小的可重现示例


这是我的看法。已应用以下优化:

  • 为了获得最佳性能,最低有效数字已完全展开
  • 剩余的数字已展开为每个数字的一​​个部分
  • BCD 算术已用于将代码减少为每个数字一个条件分支
  • 段的使用已被重新调整,以减少使用的前缀数量
  • 指令顺序经过优化,可将长延迟指令移出关键路径

此外,我已将代码更改为 COM 二进制文件,以便于测试。将其变回引导加载程序作为读者的练习。一旦它是引导加载程序,您可以做的一件事就是修复代码,以便CS and SS段基数为0000。这避免了对某些微架构的加载和存储的惩罚。

        org     100h

pos     equ     2*(2*80-12)             ; address on screen

        mov     ax, 3                   ; set up video mode
        int     10h
        mov     ax, 0b800h
        mov     ds, ax
        mov     es, ax

        mov     di, pos
        mov     ax, 4e30h               ; '0' + attribute byte 4e
        mov     cx, 10
        cld
        rep     stosw                   ; set up initial display

        xor     ax, ax
        sub     sp, 10
        push    ax
        push    ax
        push    ax
        push    ax
        push    ax
        mov     bp, sp                  ; set up counter

        dec     di
        dec     di                      ; di points to the last digit on screen
        mov     bx, digits              ; translation table

        jmp     countloop

%macro  docarry 1                       ; digits other than the last one
        mov     al, [bp+%1]             ; second to last digit
        inc     ax                      ; add carry to al
        aaa                             ; generate BCD carry
        mov     [bp+%1], al             ; desposit to counter
        cs xlat                         ; generate ASCII digit
        mov     [di-2*9+2*%1], al       ; display digit
        jnc     countloop               ; exit when carry dies
%endm

docarry2:                               ; place this here so jumps are in range
        docarry 2
        docarry 1
        docarry 0
        int     20h

        align   16                      ; for performance
countloop:
        mov     [di], byte '0'          ; treat last digit separately
        mov     [di], byte '1'
        mov     [di], byte '2'
        mov     [di], byte '3'
        mov     [di], byte '4'
        mov     [di], byte '5'
        mov     [di], byte '6'
        mov     [di], byte '7'
        mov     [di], byte '8'
        mov     [di], byte '9'

        docarry 8
        docarry 7
        docarry 6
        docarry 5
        docarry 4
        docarry 3
        jmp     docarry2

digits:
        db      '0123456789'

与我基于 8 MHz 80286 的机器上的原始代码相比,这将速度提高了约 30 倍,并设法使计数器每秒增加约 329000 次(每个数字约 3.04 µs)。在现代系统上进行测试会有点困难,但我会尝试找到解决方案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

优化第七代英特尔酷睿视频 RAM 中的递增 ASCII 十进制计数器 的相关文章

随机推荐

  • 如何从 Node.js Lambda 函数调用步骤函数?

    我正在尝试从 Node js lambda 函数调用步骤函数 我尝试了该解决方案并更新了实现thread 显示错误响应的解决方案 但更新后的代码显示成功响应 但更新后的代码没有调用step函数 My Code console log Loa
  • Coldfusion:通过 url 将结构作为字符串传递

    有没有一种简单的方法可以将单级结构序列化为字符串以在 url 中使用 例如 key1 val1 key2 val2
  • 找不到 ionic.config.json 文件

    当我跑步时ionic build android 我收到这个错误 Couldn t find ionic config json file Are you in an Ionic project 我在项目文件夹中 请问有人吗 转到 ioni
  • (2006,'MySQL 服务器已经消失')在 WSGI django 中

    我在 WSGI 下有一个 MySQL 和 Django 一起消失了 我在 stackoverflow 上找到了这个问题的条目 但没有专门针对 Django 的 除了解决方法 例如每隔一段时间轮询一次网站 或增加数据库超时 之外 谷歌没有提供
  • 使用 .NET CLI 将 NuGet 包推送到 VSTS

    我正在尝试将 NuGet 包发布到私有 VSTS 源 我想使用来实现这一点only NET CLI 无需创建或修改 nuget config 文件 我尝试过这样做 dotnet nuget push
  • 片段和活动之间的通信 - 最佳实践

    这个问题主要是为了征求有关处理我的应用程序的最佳方式的意见 我有一个活动正在处理三个片段 片段 A 有 1 个可点击元素 照片 片段 B 有 4 个可点击元素 按钮 另一个片段仅在单击照片时显示详细信息 我正在使用 ActionBarShe
  • QML 中的forceActiveFocus() 与 focus = true

    我阅读了有关以下内容的文档 focus财产 activeFocus财产 forceActiveFocus method FocusScope object 和 QtQuick 中的键盘焦点 但仍不清楚何时应该使用forceActiveFoc
  • 无法在 redux-form w 中设置默认值。反应

    我无法设置带有 redux form 的表单的默认值 我正在寻找的结果是一个可编辑的文本字段 稍后提交到数据库 即更新电子邮件地址 我尝试将表单中的属性设置为value or 默认值 注意 我删除了重复的代码 以便仅使用 名称 字段就可以更
  • 用于从 select row_number() over() 中选择的 JPQL

    我在 AS 400 上使用 Db2 并且尝试执行 JPQL 查询 该查询将返回从行 x 到行 y 的结果 在 SQL 中 这是有效的 select cur from SELECT ROW NUMBER OVER AS ROWNUM FROM
  • 调用serve_forever() 时打印语句不起作用? [复制]

    这个问题在这里已经有答案了 我有以下小 python 脚本来运行本地服务器来测试一些 html print opened from http server import HTTPServer SimpleHTTPRequestHandler
  • 如何在 App Engine 上实现服务器亲和性或粘性会话?

    我的申请希望有 自动扩展 我希望 App Engine 在流量增加时启动应用程序的新实例 当实例空闲时 我希望 App Engine 将其关闭 客户端 服务器关联性 在初始客户端 gt 服务器 HTTP 请求之后 我想要客户端 能够连接到同
  • iPhone 上的单元测试如何进行?

    我是否需要为此使用特殊的库 或者我可以创建一个巨大的类来尝试实例化项目的每个对象并测试其中的所有方法吗 理论上是如何实现的 谷歌搜索 iPhone 单元测试 给出这个优秀的链接作为第一击 综上所述 Google Toolbox 为 iPho
  • Django 模板:为页面使用不同的 css

    刚接触 Django 我想对不同的页面使用不同的 css 文件 即 page1 css 用于 page1 html page2 css 用于 page2 html 有没有办法在扩展 base html 的同时做到这一点 在base html
  • 计算字符串中特定字符的数量

    抱歉 由于我的问题 我刚刚发现了一个新问题 获取字符串中特定字符串的数量 我一直在努力 如何找到字符串中特定字符的数量 案子是这样的 function get num chars char string 120201M 121212M 1
  • 使用 DAO 和 Web 服务的数据库插入方法的 Junit 测试用例

    我正在实施一个基于网络服务的大学管理系统 该系统将某些课程添加到数据库中 下面是我正在使用的代码 课程 java public class Course private String courseName private String lo
  • 如何在 Json.NET Silverlight 中使用 TypeNameHandling.Objects 进行反序列化?

    尝试在 Silverlight 中反序列化时出现异常 Test1 失败 而 Test2 成功 我还尝试过 TypeNameAssemblyFormat 到 Simple 和 Full 但得到相同的结果 Test2可以解析程序集 为什么Jso
  • 采用函数式语言的 Kernighan & Ritchie 字数统计示例程序

    我最近在网上阅读了一些有关函数式编程的内容 我想我对其背后的概念有了基本的了解 我很好奇涉及某种状态的日常编程问题是如何用纯函数式编程语言解决的 例如 C 编程语言 一书中的字数统计程序如何用纯函数语言实现 只要解决方案是纯函数式的 我们欢
  • 如何迭代通配符泛型?

    如何迭代通配符泛型 基本上我想内联以下方法 private
  • 浏览器引擎是否会压缩大型重复对象数组中的键名?

    本着这两个问题的精神 是否值得努力尝试减小 JSON 大小 JSON 响应对象 漂亮 的键和较大的响应 还是短的键和较小的响应 浏览器如何处理相同对象类型的大型数组 它们的键名是否以某种方式压缩在内存中 我曾经使用过一个图形库 并通过缩短对
  • 优化第七代英特尔酷睿视频 RAM 中的递增 ASCII 十进制计数器

    我正在尝试针对特定的 Kaby Lake CPU i5 7300HQ 优化以下子例程 理想情况下使代码比其原始形式至少快 10 倍 该代码在 16 位实模式下作为软盘式引导加载程序运行 它在屏幕上显示一个十位十进制计数器 计数 0 9999