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