; ============================================================================ ; profiling.asm - 性能分析工具 (x86-64 MASM) ; 使用 RDTSC/RDTSCP 进行高精度计时 ; ============================================================================ include asm_macros.inc .DATA ALIGN 8 cpu_freq DQ 0 ; CPU 频率 (Hz) cpu_freq_init DB 0 ; 是否已初始化 .CODE ; ============================================================================ ; RDTSC 计时 ; ============================================================================ ; uint64_t prof_rdtsc(void) -> RAX ; 返回: TSC (Time Stamp Counter) 值 prof_rdtsc PROC ; 使用 RDTSCP 获取有序的 TSC rdtscp ; EDX:EAX = TSC shl rdx, 32 or rax, rdx ret prof_rdtsc ENDP ; uint64_t prof_get_freq(void) -> RAX ; 获取 CPU 频率 (通过 OS 或推断) prof_get_freq PROC ; 检查是否已初始化 cmp byte ptr [cpu_freq_init], 0 jnz prof_freq_return ; 初始化 CPU 频率 ; 方法: 使用 QueryPerformanceCounter 测量 RDTSC push rbx push rdi push rsi sub rsp, 40 ; 获取 QPC 频率 lea rcx, [rsp + 32] call QueryPerformanceFrequency ; 获取起始 QPC 和 TSC lea rcx, [rsp + 16] call QueryPerformanceCounter rdtscp shl rdx, 32 or rax, rdx mov rbx, rax ; rbx = 起始 TSC ; 等待约 10ms mov rcx, 10000 ; 10,000 微秒 call Sleep ; 获取结束 QPC 和 TSC lea rcx, [rsp] call QueryPerformanceCounter rdtscp shl rdx, 32 or rax, rdx mov rdi, rax ; rdi = 结束 TSC ; 计算经过的 QPC ticks mov rax, [rsp] sub rax, [rsp + 16] ; qpc_diff ; 计算 QPC 频率 (ticks/sec) mov rsi, [rsp + 32] ; TSC diff mov rax, rdi sub rax, rbx ; tsc_diff ; CPU freq = tsc_diff * qpc_freq / qpc_diff ; 但 qpc_diff 对应 10ms, 所以要 * 100 mov rdx, rsi mul rdx ; tsc_diff * qpc_freq ; rdx:rax = result div qword ptr [rsp + 16] ; / qpc_diff ; rax = freq * 100 (因为等待了 10ms) mov rcx, 100 mul rcx mov [cpu_freq], rax mov byte ptr [cpu_freq_init], 1 add rsp, 40 pop rsi pop rdi pop rbx prof_freq_return: mov rax, [cpu_freq] ret prof_get_freq ENDP ; double prof_cycles_to_ms(uint64_t cycles) -> XMM0 ; 将 TSC cycles 转换为毫秒 prof_cycles_to_ms PROC ; 先获取频率 call prof_get_freq ; rax = CPU freq (Hz) ; ms = cycles / (freq / 1000) ; 或: ms = cycles * 1000 / freq mov rdx, 1000 mul rdx ; freq * 1000 ; rdx:rax = freq * 1000 ; 转换为 double cvtsi2sd xmm0, qword ptr [rsp - 8] ; 需要栈存储 ; 简化: 使用整数除法再转 double mov rcx, rax mov rax, [cpu_freq] ; 重新计算 mov rax, rcx ; cycles * 1000 / freq ; 已经: rax = freq * 1000, 需要 cycles * 1000 / freq ; 调整: cycles * 1000 / freq = cycles / (freq/1000) ; 简化实现 cvtsi2sd xmm0, rcx ; cycles * 1000 (转 double) cvtsi2sd xmm1, rax ; freq (转 double) divsd xmm0, xmm1 ; (cycles*1000) / freq = ms ret prof_cycles_to_ms ENDP ; ============================================================================ ; 内联性能宏 (在 C 代码中使用) ; ============================================================================ ; 获取当前时间戳 (直接 RDTSC, 无函数调用开销) ; 在 C 中使用: __rdtsc() 内联函数 ; 高精度计时器结构 ; struct ProfTimer { ; uint64_t start; ; uint64_t end; ; double elapsed_ms; ; }; ; void prof_timer_start(ProfTimer* timer) prof_timer_start PROC rdtscp shl rdx, 32 or rax, rdx mov [rcx], rax ; timer->start = tsc ret prof_timer_start ENDP ; void prof_timer_stop(ProfTimer* timer) prof_timer_stop PROC rdtscp shl rdx, 32 or rax, rdx mov [rcx + 8], rax ; timer->end = tsc ; 计算 elapsed_ms mov rax, [rcx + 8] sub rax, [rcx] ; cycles ; 转换为 ms call prof_cycles_to_ms movsd qword ptr [rcx + 16], xmm0 ; timer->elapsed_ms ret prof_timer_stop ENDP END