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

如何测量现代x86平台上当前线程/程序的实际时钟周期数?

测量x86平台当前线程的实际时钟周期数

Windows 方案

方法1:结合RDTSC与CPU实际频率计算

现代x86 CPU的RDTSC指令通常以基准频率运行(而非动态变化的实际运行频率),因此要得到实际时钟周期,需先获取CPU当前实际运行频率,再结合RDTSC的差值计算:

  1. 通过GetLogicalProcessorInformationEx获取CPU基准频率(RDTSC的计数速率)和当前实际频率;
  2. 用__rdtscp指令记录起始、结束的TSC值,计算差值后乘以「实际频率/基准频率」得到实际周期数。

示例代码:

#include <windows.h>
#include <intrin.h>
#include <iostream>

// 获取CPU基准频率(单位:Hz)
ULONGLONG GetBaseFrequency() {
    SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* info = nullptr;
    DWORD bufferSize = 0;
    GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &bufferSize);
    info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(bufferSize);
    GetLogicalProcessorInformationEx(RelationProcessorCore, info, &bufferSize);
    
    ULONGLONG baseFreq = info->Processor.MaxMhz * 1000000ULL;
    free(info);
    return baseFreq;
}

// 获取CPU当前实际频率(单位:Hz)
ULONGLONG GetCurrentFrequency() {
    SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* info = nullptr;
    DWORD bufferSize = 0;
    GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &bufferSize);
    info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(bufferSize);
    GetLogicalProcessorInformationEx(RelationProcessorCore, info, &bufferSize);
    
    ULONGLONG currentFreq = info->Processor.CurrentMhz * 1000000ULL;
    free(info);
    return currentFreq;
}

int main() {
    ULONGLONG baseFreq = GetBaseFrequency();
    ULONGLONG currentFreq = GetCurrentFrequency();
    
    unsigned int dummy;
    ULONGLONG start = __rdtscp(&dummy);
    
    // 要测量的代码段
    for (int i = 0; i < 1000000; ++i) {}
    
    ULONGLONG end = __rdtscp(&dummy);
    ULONGLONG tscDiff = end - start;
    
    // 计算实际时钟周期数
    ULONGLONG actualCycles = tscDiff * currentFreq / baseFreq;
    
    std::cout << "实际时钟周期数:" << actualCycles << std::endl;
    return 0;
}

方法2:使用硬件性能计数器

Windows提供的性能计数器API可直接读取PERF_COUNTER_CPU_CYCLES,对应实际CPU周期:

#include <windows.h>
#include <iostream>

int main() {
    HANDLE hCounter = CreateEvent(nullptr, FALSE, FALSE, nullptr);
    PERF_COUNTER_INFO counterInfo = {0};
    counterInfo.CounterId = PERF_COUNTER_CPU_CYCLES;
    counterInfo.InstanceId = PERF_INSTANCE_ID_CURRENT;
    
    if (PerfQueryCounter(hCounter, &counterInfo, sizeof(counterInfo))) {
        ULONGLONG start, end;
        PerfReadCounter(hCounter, &start);
        
        // 要测量的代码段
        for (int i = 0; i < 1000000; ++i) {}
        
        PerfReadCounter(hCounter, &end);
        std::cout << "实际时钟周期数:" << (end - start) << std::endl;
    } else {
        std::cout << "无法获取性能计数器:" << GetLastError() << std::endl;
    }
    CloseHandle(hCounter);
    return 0;
}

Linux 方案

方法1:使用perf_event_open读取硬件计数器

通过perf_event_open系统调用直接获取PERF_COUNT_HW_CPU_CYCLES计数器,是最准确的实际CPU周期测量方式:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>
#include <string.h>

static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags) {
    return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
}

int main() {
    struct perf_event_attr pe;
    long long count;
    int fd;

    memset(&pe, 0, sizeof(struct perf_event_attr));
    pe.type = PERF_TYPE_HARDWARE;
    pe.size = sizeof(struct perf_event_attr);
    pe.config = PERF_COUNT_HW_CPU_CYCLES;
    pe.disabled = 1;
    pe.exclude_kernel = 1; // 可选:排除内核态周期
    pe.exclude_hv = 1;     // 可选:排除虚拟机监控器周期

    fd = perf_event_open(&pe, 0, -1, -1, 0);
    if (fd == -1) {
        fprintf(stderr, "perf_event_open failed\n");
        exit(EXIT_FAILURE);
    }

    ioctl(fd, PERF_EVENT_IOC_RESET, 0);
    ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

    // 要测量的代码段
    for (int i = 0; i < 1000000; ++i) {}

    ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
    read(fd, &count, sizeof(long long));

    printf("实际时钟周期数:%lld\n", count);

    close(fd);
    return 0;
}

编译需链接-lrt,运行可能需要sudo或调整系统性能权限。

方法2:结合RDTSC与CPU频率计算

读取系统文件获取CPU基准频率和当前频率,再用RDTSC差值计算实际周期:

#include <stdio.h>
#include <intrin.h>

// 读取当前CPU频率(单位:Hz)
unsigned long long get_current_cpu_freq() {
    FILE* f = fopen("/proc/cpuinfo", "r");
    char line[256];
    unsigned long long freq = 0;
    while (fgets(line, sizeof(line), f)) {
        if (sscanf(line, "cpu MHz : %llu", &freq) == 1) {
            break;
        }
    }
    fclose(f);
    return freq * 1000000ULL;
}

// 读取CPU基准频率(单位:Hz)
unsigned long long get_base_cpu_freq() {
    FILE* f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
    unsigned long long freq = 0;
    fscanf(f, "%llu", &freq);
    fclose(f);
    return freq * 1000ULL; // 文件中是kHz,转Hz
}

int main() {
    unsigned long long base_freq = get_base_cpu_freq();
    unsigned long long current_freq = get_current_cpu_freq();

    unsigned int dummy;
    unsigned long long start = __rdtscp(&dummy);

    // 要测量的代码段
    for (int i = 0; i < 1000000; ++i) {}

    unsigned long long end = __rdtscp(&dummy);
    unsigned long long tsc_diff = end - start;

    unsigned long long actual_cycles = tsc_diff * current_freq / base_freq;
    printf("实际时钟周期数:%llu\n", actual_cycles);

    return 0;
}

内容的提问来源于stack exchange,提问作者user541686

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 05:05:18