一开始,这可能是部分讨论部分解决问题。无意冒犯那里的任何人。
我已经用64位汇编编写了算法,以生成64位的基于MT Prime的随机数发生器。此生成器函数需要调用80亿次来填充大小为2048x2048x2048的数组,并在1..small_value(通常为32)之间生成随机数
现在我有两个下一步的可能性:
(a)继续生成数字,与限制[1..32]进行比较,并丢弃那些不在其中的数字。该逻辑的运行时间为181,817 ms,通过调用clock()函数来测量。
(b)在RAX中输出64位随机数,并使用FPU将其缩放到[0..1]之间,然后将其放大到所需范围[1..32]这如下:
mov word ptr initialize_random_number_scaling,dx
fnclex ; clears status flag
call generate_fp_random_number ; returns a random number in ST(0) between [0..1]
fimul word ptr initialize_random_number_scaling ; Mults ST(0) & stores back in ST(0)
mov word ptr initialize_random_number_base,ax ; Saves base to a memory
fiadd word ptr initialize_random_number_base ; adds the base to the scaled fp number
frndint ; rounds off the ST(0)
fist word ptr initialize_random_number_result ; and stores this number to result.
ffree st(0) ; releases ST(0)
fincstp ; Logically pops the FPU
mov ax, word ptr initialize_random_number_result ; and saves it to AX
generate_fp_random_number中的指令如下:
shl rax,1 ; RAX gets the original 64 bit random number using MT prime algorithm
shr ax,1 ; Clear top bit
mov qword ptr random_number_generator_act_number,rax ; Save the number in memory as we cannot move to ST(0) a number from register
fild qword ptr random_number_generator_max_number ; Load 0x7FFFFFFFFFFFFFFFH
fild qword ptr random_number_generator_act_number ; Load our number
fdiv st(0),st(1) ; We return the value through ST(0) itself, divide our random number with max possible number
fabs
ffree st(1) ; release the st(1)
fld1 ; push to top of stack a 1.0
fcomip st(0), st(1) ; compares our number in ST(1) with ST(0) and sets CF.
jc generate_fp_random_get_next_no ; if ST(0) (=1.0) < ST(1) (our no), we need a new no
fldz ; push to top of stack a 0.0
fcomip st(0),st(1) ; if ST(0) (=0.0) >ST(1) (our no) clears CF
jnc generate_fp_random_get_next_no ; so if the number is above zero the CF will be set
fclex
问题是,只需添加这些指令,运行时就可以达到惊人的5,633,963毫秒!我已经使用xmm寄存器作为替代编写了上述内容,差别绝对是微不足道的。 (5,633,703 ms)。
有人会指导我这些附加指令对总运行时间的影响程度吗? FPU真的很慢吗?还是我错过了一招?一如既往,欢迎所有想法,并感谢您的时间和精力。
环境:英特尔2700K CPU上的Windows 7 64位超频至VS 2012 Express环境中调试的4.4 GHz 16 GB RAM
答案 0 :(得分:0)
“mov word ptr initialize_random_number_base,ax;将base保存到内存中”
如果你想要最高速度,你必须找出如何分离写指令和将数据写入内存的不同部分
在缓存的同一区域重写数据会产生“自修改代码”情况
您的编译器可能会执行此操作,但可能不会。 您需要知道这一点,因为未经优化的汇编代码运行速度要慢10到50倍
“所有现代处理器都会缓存代码和数据存储器以提高效率。如果将数据写入与执行代码的内存相同的内存块,则汇编语言代码的性能会受到严重影响,因为它可能会导致CPU反复重新加载指令缓存(这是为了确保自我修改代码正常工作)。为了避免这种情况,你应该确保代码和(可写)数据不占用相同的2 KB内存块。“
答案 1 :(得分:0)
您的代码中有大量内容我无法理解。如果有原因,请随意纠正我,否则这是我的替代方案:
对于generate_fp_random_number
shl rax, 1
shr rax, 1
mov qword ptr act_number, rax
fild qword ptr max_number
fild qword ptr act_number
fdivrp ; divide actual by max and pop
; and that's it. It's already within bounds.
; It can't be outside [0, 1] by construction.
; It can't be < 0 because we just divided two positive number,
; and it can't be > 1 because we divided by the max it could be
另一件事:
mov word ptr scaling, dx
mov word ptr base, ax
call generate_fp_random_number
fimul word ptr scaling
fiadd word ptr base
fistp word ptr result ; just save that thing
mov ax, word ptr result
; the default rounding mode is round to nearest,
; so the slow frndint is unnecessary
还要注意完全没有ffree
等。通过弹出正确的指令,一切都刚刚解决了。它通常会。