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