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