gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 14:07:34 25 4
gpt4 key购买 nike

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

我查看了 Microarchitecture 的 Agner 优化指南和 Assembly , Instruction Performance Table和英特尔的 Optimization Reference Manual .

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

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

我还尝试切换到 32 位模式并将整个计数器保留在一个未使用的寄存器对中以消除任何内存访问,但在读入一点后我意识到这十位将立即被缓存,并且 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

我的问题是 - 我该怎么做才能实现所需的速度提升?我还可以学习哪些其他 Material 来更好地理解基本概念?

注意:这个 学校作业。虽然直接回答肯定会有所帮助,但我更希望得到相关研究 Material 的解释或指示,因为我们没有得到任何答复。

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

最佳答案

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

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

  • 此外,我已将代码更改为 COM 二进制文件,以便于测试。将其重新转换为引导加载程序留给读者作为练习。一旦它成为引导加载程序,您可以做的一件事是修复代码,使 CSSS 具有 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)。在现代系统上进行测试会有点困难,但我会尝试找到解决方案。

    关于assembly - 优化第 7 代英特尔酷睿视频 RAM 中递增的 ASCII 十进制计数器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61460126/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com