C/C++ 测量 CPU 时钟周期

VS2022 上的代码实现

cputimer.h

#ifndef CPUTIMER
#define CPUTIMER

#if defined(__linux__)
// Linux系统
#include<unistd.h>
#elif defined(_WIN32)
// Windows系统
#include<windows.h>
#endif

/*单位:毫秒*/
inline void sleep(int time) {
    
    
#if defined(__linux__)
	// Linux系统
	usleep(time * 1000);
#elif defined(_WIN32)
	// Windows系统
	Sleep(time);
#endif
}

/*
unsigned long long _get_cpu_counts_() {
    // 以下三种方法,是等价的(只在 x86 上运行,而 x64 不支持内联汇编)

    // 1.
    __asm {
        rdtsc;
        shl edx, 32;
        or eax, edx;
    }

    // 2.
    _asm RDTSC;

    // 3.
    __asm _emit 0x0F
    __asm _emit 0x31
}
*/
unsigned long long  __stdcall cputimer();   // 独立汇编代码

// 测量 CPU 主频
inline unsigned long long GetFrequency() {
    
    
	unsigned long long t1 = cputimer();
	sleep(1000);
	unsigned long long t2 = cputimer();
	return t2 - t1;
}

#endif

cputimer.asm

.code 
align 16

cputimer proc
	rdtsc
	shl rdx, 32
	or  rax, rdx
	ret
cputimer endp

end

main.c

#include <stdio.h>
#include "cputimer.h"

#include <time.h>
time_t TM_start, TM_end;
#define Timer(code) TM_start = clock(); code; TM_end = clock(); printf("time = %d ms\n", TM_end - TM_start); //对code部分计时
#define Loop(loop, code) Timer(for(int ind=0; ind<loop; ind++) {
      
      code;})

int main()
{
    
    
    int64 freq = GetFrequency();
    printf("CPU Frequency = %lld\n\n", freq);

    int n = 1;
    int64 t1 = cputimer();
    Loop(100000000, n+=n*n);
    int64 t2 = cputimer();
    printf("CPU Cycles: %lld\n", t2 - t1);

    return 0;
}

C/C++ 与 asm 联合编译

右击项目,选择 生成依赖项,选择 生成自定义,然后勾选 masm

在这里插入图片描述

右击 cputimer.asm,选择 属性,将 常规 中的 项类型 设置为 Microsoft Macro Assembler:

在这里插入图片描述

(感觉 VS 有 Bug,如果死活找不到 Microsoft Macro Assembler 选项,而直接复制进去则显示 此项目不支持,那么可以重启 VS 再重新设置 masm 试一下)

执行结果

编译执行:

CPU Frequency = 2954621661

time = 95 ms
CPU Cycles: 278007609

使用 GCC 时的更简单写法

首先建议查看 如何用 GCC, CMake 和 Make 编译C/C++代码

此时,汇编代码的写法不太一样:

align 16

_cputimer:
rdtsc
shl rdx, 32
or rax, rdx
ret

另外由于 GCC 支持内联汇编,因此可以直接只一个 .h 文件:

#ifndef CPUTIMER
#define CPUTIMER

#if defined(__linux__)
// Linux系统
#include <unistd.h>
#elif defined(_WIN32)
// Windows系统
#include <intrin.h>
#include <windows.h>
#endif

/*单位:毫秒*/
void sleepms(int time) {
    
    
#if defined(__linux__)
	// Linux系统
	usleep(time * 1000);
#elif defined(_WIN32)
	// Windows系统
	Sleep(time);
#endif
}

/* Needs echo 2 > /sys/devices/cpu/rdpmc */
unsigned long long cputimer() {
    
    
    // 以下三种方法,是等价的(只在 x86 上运行,而 x64 不支持内联汇编)

    // 1.
    /*__asm {
        rdtsc;
        shl edx, 32;
        or eax, edx;
    }*/

    // 2.
    //__asm RDTSC;

    // 3.
    /*__asm _emit 0x0F
    __asm _emit 0x31*/

#if _WIN32
    return __rdtsc();
#else
    unsigned int lo, hi;
    __asm__ volatile ("rdtsc" : "=a" (lo), "=d" (hi));
    return ((uint64_t)hi << 32) | lo;
#endif
}
//unsigned long long cputimer();   // 独立汇编代码
/*
    align 16

    _cputimer:
    rdtsc
    shl rdx, 32
    or rax, rdx
    ret
*/

unsigned long long CPUFrequency;

// 测量 CPU 主频
unsigned long long GetFrequency() {
    
    
    unsigned long long t1 = cputimer();
	sleepms(1000);
    unsigned long long t2 = cputimer();
    CPUFrequency = t2 - t1;
	return CPUFrequency;
}

unsigned long long TM_start, TM_end;
#define Timer(code) TM_start = cputimer(); code; TM_end = cputimer(); \
    printf("time = %d cycles (%f s)\n", TM_end - TM_start, (double)(TM_end - TM_start)/CPUFrequency); //对code部分计时
#define Loop(loop, code) Timer(for(int i=0; i<loop; i++) {
      
      code;})

#define pn printf("\n\n");

#endif

猜你喜欢

转载自blog.csdn.net/weixin_44885334/article/details/129214688
今日推荐