最近要实现一个功能,获取系统的cpu信息,查阅网上的资料,如果是在VS20XX中可以用如下代码实现:
using namespace std;
//用来存储信息
DWORD deax, debx, decx, dedx;
static void ExeCPUID(DWORD veax) // 初始化CPU
{
__asm
{
mov eax,veax
cpuid
mov deax,eax
mov debx,ebx
mov decx,ecx
mov dedx,edx
}
}
static float GetCPUFreq() // 获取CPU频率,单位: MHZ
{
int start1,start2;
_asm rdtsc
_asm mov start1, eax
Sleep(50);
_asm rdtsc
_asm mov start2, eax
return ((start2 - start1) / 50) / (1000);
}
static string GetManID() // 获取制造商信息
{
char ID[25]; // 存储制造商信息
memset(ID, 0, sizeof(ID)); // 先清空数组 ID
ExeCPUID(0); // 初始化
memcpy(ID + 0, &debx, 4); // 制造商信息前四个字符复制到数组
memcpy(ID + 4, &dedx, 4); // 中间四个
memcpy(ID + 8, &decx, 4); // 最后四个
return string(ID);
}
static string GetCPUType()
{
const DWORD id = 0x80000002; // 从0x80000002开始,到0x80000004结束
char CPUType[49]; // 用来存储CPU型号信息
memset(CPUType, 0, sizeof(CPUType)); // 初始化数组
for(DWORD t = 0; t < 3; t++)
{
ExeCPUID(id + t);
// 每次循环结束,保存信息到数组
memcpy(CPUType + 16 * t + 0, &deax, 4);
memcpy(CPUType + 16 * t + 4, &debx, 4);
memcpy(CPUType + 16 * t + 8, &decx, 4);
memcpy(CPUType + 16 * t + 12, &dedx, 4);
}
return string(CPUType);
}
可是这段代码在VSCODE中却编译不过,提示__asm找不到,这是因为VSCODE用的编译器可能是g++,g++内嵌汇编语言的写法应该是:
DWORD deax, debx, decx, dedx;
int start1,start2;
static void ExeCPUID(DWORD veax) // 初始化CPU
{
asm
(
"mov %eax,$veax\n\r" // 这里编译不过
"cpuid\n\r"
"mov $deax,%eax\n\r"
"mov $debx,%ebx\n\r"
"mov $decx,%ecx\n\r"
"mov $dedx,%edx\n\r"
);
}
static float GetCPUFreq() // 获取CPU频率,单位: MHZ
{
asm( // 这asm指令执行并不生效 获取不到eax的值
"rdtsc\n\r"
"mov $start1, %eax\n\r"
);
Sleep(50);
asm( // 这些asm指令执行并不生效 获取不到eax的值
"rdtsc\n\r"
"mov $start2, %eax\n\r"
);
return ((start2 - start1) / 50) / (1024);
}
注意点:参考(https://blog.csdn.net/ichuangxin/article/details/84275004)
1.std命名空间下,不能使用_asm_
2.寄存器要在前面加上%,多个命令时,命令以\n\r结尾,使得在将汇编代码插入目标文件时会换行
3.立即数前加$
4.不要定义局部变量,变量定义在函数外部,否则链接找不到?
可是即使这样还是编译不过,GetCPUFreq能编译过,但是执行结果不对
编译报错在cpuid的上一句指令,
报错内容为:Error: unsupported instruction `mov’
看起来不像是语法问题,而是和cpuid有关(待进一步确认)。
再次查询资料,如果要用g++,可以#include <cpuid.h>
#include <iostream>
#include <string>
#include <stdint.h>
#include <iostream>
#include <windows.h>
#include <cpuid.h>
static void cpuid(uint32_t func, uint32_t sub, uint32_t data[4])
{
__cpuid_count(func, sub, data[0], data[1], data[2], data[3]);
}
static string GetManID() // 获取制造商信息
{
uint32_t data[4];
char ID[25]; // 存储制造商信息
memset(ID, 0, sizeof(ID)); // 先清空数组 ID
cpuid(0, 0, data); // 初始化
memcpy(ID + 0, &data[1], 4); // 制造商信息前四个字符复制到数组
memcpy(ID + 4, &data[3], 4); // 中间四个
memcpy(ID + 8, &data[2], 4); // 最后四个
return string(ID);
}
static string GetCPUType()
{
uint32_t data[4];
char str[48];
for(int i = 0; i < 3; ++i)
{
cpuid(0x80000002 + i, 0, data);
for(int j = 0; j < 4; ++j)
{
reinterpret_cast<uint32_t*>(str)[i * 4 + j] = data[j];
}
}
return string(str);
}
inline int64_t timt()
{
int64_t p;
int &a = *(((int*)&p) + 1);
__asm__ __volatile__("rdtsc":"=a"(p),"=d"(a));
return p;
}
static float GetCPUFreq() // 获取CPU频率,单位: MHZ
{
start1 = timt();
Sleep(50); // 將線程掛起片刻 由於windows的Sleep函數有大約15毫秒的误差 所以其实这个函数算出来的频率并不准
start2 = timt();
cout << "start1: " << start1 << " start2: " << start2 << endl;
return ((start2 - start1) / 50) / (1000); 誤差,故以windows的精確計時為準
}
实现结果:(参考:https://blog.csdn.net/weixin_43731933/article/details/102734964)
在windows arm64平台中,intrin.h不支持cpuid
__MACHINEX86_X64(void __cpuid(int[4], int))
__MACHINEX86_X64(void __cpuidex(int[4], int, int))
可从注册表中得到cpu型号:
const int BUFSIZ= 65; // For easy adjustment of limits, if required
char answer[BUFSIZ] = "Error Reading CPU Name from Registry!", inBuffer[BUFSIZ] = "";
const char *csName = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
HKEY hKey; DWORD gotType, gotSize = BUFSIZ;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, csName, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
if (!RegQueryValueExA(hKey, "ProcessorNameString", nullptr, &gotType, (PBYTE)(inBuffer), &gotSize)) {
if ((gotType == REG_SZ) && strlen(inBuffer)) strcpy(answer, inBuffer);
}
RegCloseKey(hKey);
}