使用RDTSC和CPUID指令测量执行时间为何输出始终为0?
问题:使用G++内联汇编测量内存分配时间输出始终为0的原因及解决办法
我是一名C学生,被要求使用G编译器的内联汇编中的CPUID和RDTSC指令,测量1000000个整数的内存分配时间。将Windows Visual Studio的汇编语法适配为G++语法后写出如下代码:
#include <iostream> using namespace std; int main() { unsigned cycles_high1=0, cycles_low1=0, cpuid_time=0; unsigned cycles_high2=0, cycles_low2=0; unsigned temp_cycles1=0, temp_cycles2=0; unsigned total_cycles=0; asm volatile( "cpuid\n\t" "rdtsc\n\t" "mov %0, %%edx\n\t" "mov %1, %%eax\n\t" "cpuid\n\t" "rdtsc\n\t" "cpuid\n\t" "rdtsc\n\t" "mov %0, %%edx\n\t" "mov %1, %%eax\n\t" "cpuid\n\t" "rdtsc\n\t" "cpuid\n\t" "rdtsc\n\t" "mov %0, %%edx\n\t" "mov %1, %%eax\n\t" "cpuid\n\t" "rdtsc\n\t" "sub %%eax, %1\n\t" "mov %2, %%eax\n\t" : "=r" (cycles_high1), "=r" (cycles_low1), "=r" (cpuid_time) : : "%rax", "%rbx", "%rcx", "%rdx" ); cycles_high1=0; cycles_low1=0; asm( "cpuid\n\t" "rdtsc\n\t" "mov %0, %%edx\n\t" "mov %1, %%eax\n\t" : "=r" (cycles_high1), "=r" (cycles_low1) : : "%rax", "%rbx", "%rcx", "%rdx" ); int *p = (int*)malloc(sizeof(int) * 1000000); asm( "cpuid\n\t" "rdtsc\n\t" "mov %0, %%edx\n\t" "mov %1, %%eax\n\t" : "=r" (cycles_high2), "=r" (cycles_low2) : : "%rax", "%rbx", "%rcx", "%rdx" ); temp_cycles1 = ((unsigned long long)cycles_high1 << 32) | cycles_low1; temp_cycles2 = ((unsigned long long)cycles_high2 << 32) | cycles_low2; total_cycles = temp_cycles2 - temp_cycles1 - cpuid_time; cout << total_cycles; return 0; }
我先计算了CPUID的开销时间cpuid_time,并在最后从总测量时间中扣除,但输出始终为0,请问我哪里出错了?
错误分析与修正方案
1. CPUID开销计算逻辑完全错误
你第一段汇编的逻辑混乱,重复执行多次CPUID+RDTSC后没有正确计算单次CPUID的耗时,反而错误覆盖了cycles_high1和cycles_low1,后续手动将这两个变量置0更是让这段代码完全失效。正确的做法是单独测量两次空CPUID+RDTSC的差值作为基准开销。
2. 变量类型溢出导致结果异常
你用32位的unsigned存储64位时间戳拼接结果,temp_cycles1和temp_cycles2的类型应该是unsigned long long,否则64位值会被截断,计算差值时出现溢出,最终结果可能变为0。
3. 编译器优化消除了malloc调用
因为你没有使用分配的内存指针p,编译器会将malloc调用优化掉,相当于你测量的是空操作的时间,结果自然为0。需要通过volatile修饰指针或访问内存来阻止优化。
修正后的代码
#include <iostream> #include <cstdlib> using namespace std; // 读取时间戳(带CPUID序列化) static inline unsigned long long rdtsc() { unsigned int lo, hi; asm volatile ( "cpuid\n\t" "rdtsc\n\t" : "=a"(lo), "=d"(hi) : : "%rbx", "%rcx" ); return (unsigned long long)hi << 32 | lo; } // 测量空CPUID+RDTSC的开销 static inline unsigned long long measure_cpuid_overhead() { unsigned long long start = rdtsc(); unsigned long long end = rdtsc(); return end - start; } int main() { // 测量CPUID开销 unsigned long long cpuid_overhead = measure_cpuid_overhead(); // 测量内存分配前的时间 unsigned long long start = rdtsc(); // 分配内存,用volatile阻止编译器优化 volatile int *p = (volatile int*)malloc(sizeof(int) * 1000000); // 访问内存确保分配实际完成(避免系统懒加载) if (p) { p[0] = 1; } // 测量内存分配后的时间 unsigned long long end = rdtsc(); // 计算实际耗时:总时间 - 两次rdtsc的开销 unsigned long long total_cycles = end - start - cpuid_overhead; cout << "内存分配耗时:" << total_cycles << " 时钟周期" << endl; if (p) free((void*)p); return 0; }
内容的提问来源于stack exchange,提问作者Kudor
相关产品推荐
相关产品推荐

