You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 22:24:57