英文:
How to get the runtime of a NASM assembly program?
问题
I'll provide the translation of the text you provided without the code part:
如何获取NASM程序的运行时间?
这是我想要获取运行时间的程序。这是一个使用NASM汇编来计算斐波那契数列的简单程序,所以我需要获取该程序的运行时间,以便与我的其他算法进行速度比较。
有没有特殊的系统调用可供调用?我尝试了谷歌和各种其他方法,但都没有成功。
英文:
How get the Runtime of a NASM Program?
This is the program that I want to get the runtime of it. It is a simple program to calculate the Fibonacci sequence using NASM assembly so, I need to get the runtime of the this program to compare the speed with my other algorithms:
;fib.asm
global main
extern printf
section .text
main:
push rbx
mov ecx, 90
xor rax, rax
xor rbx, rbx
inc rbx
print:
push rax
push rcx
mov rdi, format
mov rsi, rax
xor rax, rax
call printf
pop rcx
pop rax
mov rdx, rax
mov rax, rbx
add rbx, rdx
dec ecx
jnz print
pop rbx
ret
format:
db "%20ld", 10, 0
Is there any special syscall to invoke for that. I tried googling and various other methods but none of it worked for me.
答案1
得分: 1
以下是代码中需要翻译的部分:
如果您询问程序运行的时间,而不是一些运行时库的辅助函数,比如printf,那么要做的方法是使用与任何其他程序都可以使用来测量其CPU使用率的系统调用。在Microsoft Win64上,这是GetProcessTime() API,它接受以下64位参数,请记住先推送最后一个参数,并在寄存器中传递前4个参数。
以下代码片段直接写在这个答案中,没有经过任何测试
GetTimeSoFar PROC NEAR
; 栈现在按16的倍数对齐
sub rsp, 32 ; 用于返回变量和对齐的空间
push -1 ; 当前进程的64位句柄
sub rsp, 32 ; 用于4个参数的空间
lea r9, [rsp+40] ; 64位输出变量 creatTim 的地址
lea r8, [rsp+48] ; 64位临时变量 exitTim 的地址
lea rdx, [rsp+56] ; 64位输出变量 kernTim 的地址
lea rcx, [rsp+64] ; 64位输出变量 userTim 的地址
; 栈现在按16的倍数对齐,减去8
mov rax, [__imp_GetProcessTime]
call rax ; 或使用等效的 retpoline
; 栈现在按16的倍数对齐,减去8
add rsp, 40 ; 删除参数空间和一个推送的参数
pop r9 ; r9 现在是自1600年以来以100纳秒为单位的创建时间
pop r8 ; r8 现在是退出时间的无效数据占位符
pop rdx ; rdx 现在是以100纳秒为单位的NT内核系统调用的时间
pop rcx ; rcx 现在是程序CPU用户模式运行时间,以100纳秒为单位
; 栈现在按16的倍数对齐
ret ; 或跳转到 retpoline 进行返回
GetTimeSoFar ENDP
GetLastErrorWrap PROC NEAR
sub rsp, 40
; 栈现在按16的倍数对齐,减去8
mov rax, [__imp_GetLastError]
call rax ; 或使用等效的 retpoline
add rsp, 40
; 栈现在按16的倍数对齐
mov ecx, eax
shr ecx, 16
cmp cx, 8007h
jne notWin32AsHRESULT
movsx eax, cx
notWin32AsHRESULT:
test eax, eax
jne hasLastErr
mov eax, 1297 ; ERROR_UNIDENTIFIED_ERROR
hasLastErr:
; 栈现在按16的倍数对齐
ret ; 或跳转到 retpoline 进行返回
GetLastErrorWrap ENDP
; 在主函数的顶部
sub rsp, localvarssize
; 栈现在按16的倍数对齐
push rdx ; 对齐栈
; 栈现在按16的倍数对齐,减去8
call GetTimeSoFar
pop rdx ; 对齐栈
; 栈现在按16的倍数对齐
test rax, rax
jz failCheckLastErr;
mov [LocalVarWithValueBeforeRun], rcx
; TODO, TODO,在这里进行计算
push rdx ; 对齐栈
; 栈现在按16的倍数对齐,减去8
call GetTimeSoFar
pop rdx ; 对齐栈
; 栈现在按16的倍数对齐
test rax, rax
jz failCheckLastErr;
sub rcx, [LocalVarWithValueBeforeRun]
mov r8, 10000000
mov rax, rcx
xor rdx, rdx
div r8
; rdx 现在是花费的秒数
; rax 现在是十进制秒数,以精确的7位数字打印
mov r8, rax
lea rcx, StrTimePrintf ; "Runtime=%I64u.%07us\n"
sub rsp, 40
; 栈现在按16的倍数对齐,减去8
call printf
add rsp, 40
; 栈现在按16的倍数对齐
; 在这里返回成功
xor rax, rax
add rsp, localvarssize
; 栈现在按16的倍数对齐
ret ; 或跳转到 retpoline 进行返回
failCheckLastErr:
sub rsp, 40 ; 用于变量区域和对齐填充的空间
; 栈现在按16的倍数对齐,减去8
call GetLastErrorWrap
mov [rsp + 32], eax ; 在对齐填充区域保存错误代码
mov r8d, eax
mov edx, eax
lea rcx, StrTimeMeasFailed ; "\nGetProcesTime() failed err=%d(0x%08X)\n"
; 栈现在按16的倍数对齐,减去8
call printf
; 以系统退出代码返回错误代码
mov eax, [rsp + 32]
add rsp, localvarssize + 40
; 栈现在按16的倍数对齐
ret ; 或跳转到 retpoline 进行返回
英文:
If you are asking about the time the program runs, not some runtime library of helper functions such as printf, then the way to do that is to use the same system calls that any other program could use to measure its CPU usage. On Microsoft Win64, this is the GetProcessTime() API, which takes the following 64 bit arguments, remember to push the last argument first and to pass the first 4 arguments in registers
The following code snippet is written directly in this answer and not tested at all
GetTimeSoFar PROC NEAR
; Stack is now aligned at multiple of 16
sub rsp,32 ; Space for return vars and alignment
push -1 ; 64 bit handle for the current process
sub rsp,32 ; Space for 4 args
lea r9,[rsp+40] ; address of a 64 bit output var for creatTim
lea r8,[rsp+48] ; address of a 64 bit scratch var for exitTim
lea rdx,[rsp+56] ; address of a 64 bit output var for kernTim
lea rcx,[rsp+64] ; address of a 64 bit output var for userTim
; Stack is now aligned at multiple of 16 minus 8
mov rax,[__imp_GetProcesTime]
call rax ; Or use equivalent retpoline
; Stack is now aligned at multiple of 16 minus 8
add rsp,40 ; Remove arg space and one pushed arg
pop r9 ; r9 is now creation time in 100ns units since year 1600
pop r8 ; r8 is now invalid data placeholder for exit time
pop rdx ; rdx is now time spent in NT kernel syscalls in 100ns units
pop rcx ; rcx in now program CPU user mode runtime in 100ns units.
; Stack is now aligned at multiple of 16
ret ; Or jump to retpoline for return
GetTimeSoFar ENDP
GetLastErrorWrap PROC NEAR
sub rsp,40
; Stack is now aligned at multiple of 16 minus 8
mov rax,[__imp_GetLastError]
call rax ; Or use equivalent retpoline
add rsp,40
; Stack is now aligned at multiple of 16
mov ecx,eax
shr ecx,16
cmp cx,8007h
jne notWin32AsHRESULT
movsx eax,cx
notWin32AsHRESULT:
test eax,eax
jne hasLastErr
mov eax,1297 ; ERROR_UNIDENTIFIED_ERROR
hasLastErr:
; Stack is now aligned at multiple of 16
ret ; Or jump to retpoline for return
GetLastErrorWrap ENDP
; At top of main function
sub rsp,localvarssize
; Stack is now aligned at multiple of 16
push rdx ; Align stack
; Stack is now aligned at multiple of 16 minus 8
call GetTimeSoFar
pop rdx ; Align stack
; Stack is now aligned at multiple of 16
test rax,rax
jz failCheckLastErr;
mov [LocalVarWithValueBeforeRun], rcx
; TODO, TODO, Put calculations here
push rdx ; Align stack
; Stack is now aligned at multiple of 16 minus 8
call GetTimeSoFar
pop rdx ; Align stack
; Stack is now aligned at multiple of 16
test rax,rax
jz failCheckLastErr;
sub rcx,[LocalVarWithValueBeforeRun]
mov r8,10000000
mov rax,rcx
xor rdx,rdx
div r8
; rdx is now seconds spent
; rax is now decimal seconds spent, printf as exactly 7 digits
mov r8,rax
lea rcx,StrTimePrintf ; "Runtime=%I64u.%07us\n"
sub rsp,40
; Stack is now aligned at multiple of 16 minus 8
call printf
add rsp,40
; Stack is now aligned at multiple of 16
; Return success here
xor rax,rax
add rsp,localvarssize
; Stack is now aligned at multiple of 16
ret ; Or jump to retpoline for return
failCheckLastErr:
sub rsp,40 ; Scratch space for var area and alignment padding
; Stack is now aligned at multiple of 16 minus 8
call GetLastErrorWrap
mov [rsp + 32],eax ; Save error code in alignment pad area
mov r8d,eax
mov edx,eax
lea rcx,StrTimeMeasFailed ; "\nGetProcesTime() failed err=%d(0x%08X)\n"
; Stack is now aligned at multiple of 16 minus 8
call printf
; Return error code as system exit code
mov eax,[rsp + 32]
add rsp,localvarssize + 40
; Stack is now aligned at multiple of 16
ret ; Or jump to retpoline for return
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论