CPUID获取本机CPU信息

本文介绍了一个使用VisualStudio编写的控制台程序,该程序通过CPUID指令获取本机CPU的制造商、商标、序列号、核心数、Hyper-Threading状态以及缓存信息,并能将这些信息存储到INI格式的文本中。此外,程序还能读取并打印这些存储的CPU信息。
摘要由CSDN通过智能技术生成

CPUID获取本机CPU信息

问题

请使用Visual Studio编写一个控制台程序,功能如下:

一、使用命令CPUInfo.exe -C读取本机CPU信息,并存储到INI格式文本中:
示例如下:
[CPU]
Manufacturer = AuthenticAMD
BrandID = AMD Athlon Gold 3150U with Radeon Graphics
CPUID = 0F81
Cores = 2
HyperThread = True
MainClock = 2396MHZ

L1CacheSize = 192KB
L2CacheSize = 1024KB
L3CacheSize = 4096KB

二、使用命令CPUInfo.exe -r 读取INI文本中的CPU信息,并打印在控制台上;

分析

cpuid使用eax作为输入参数,eax,ebx,ecx,edx作为输出参数。

1、获取CPU的制造商信息
把eax = 0作为输入参数,可以得到CPU的制造商信息。
cpuid指令执行以后,会返回一个12字符的制造商信息,前四个字符的ASC码按低位到高位放在ebx,中间四个放在edx,最后四个字符放在ecx。

2、获取CPU商标信息(Brand String)
由于商标的字符串很长(48个字符),所以不能在一次cpuid指令执行时全部得到,所以intel把它分成了3个操作,eax的输入参数分别是0x80000002,0x80000003,0x80000004,每次返回的16个字符,按照从低位到高位的顺序依次放在eax, ebx, ecx, edx。因此,可以用循环的方式,每次执行完以后保存结果,然后执行下一次cpuid。

3、检测CPU特性(Hyper-Threading)
数是eax = 1,返回值放在edx,edx的bit 28代表是否支持Hyper-Threading

4、获得cpu的缓存(cache)
缓存信息包括:第几级缓存(level),缓存大小(size),通道数(way),吞吐量(line size)。因此可以使用一个结构体来存储缓存信息。

缓存信息可以通过eax = 2的cpuid来得到
返回值在eax(高24位), ebx, ecx和edx,总共15个BYTE的信息

5、获取cpu的序列号
CPU的序列号用一个96bit的串表示,格式是连续的6个WORD值:XXXX-XXXX-XXXX-XXX-XXXX-XXXX。
获得序列号需要两个步骤,首先用eax = 1做参数,返回的eax中存储序列号的高两个WORD。用eax = 3做参数,返回ecx和edx按从低位到高位的顺序存储前4个WORD。

参考:c++获得cpu厂商_在C++中使用cpuid指令获得CPU信息

代码

软件实现过程:

1、定义三个结构体,分别存储缓存信息、序列号和CPU信息。
2、定义一个类,获取CPU制造商,商标、id序列号信息,是否支持Hyper Thread,定义四个DWORD变量,分别存储返回的eax、ebx、ecx、edx。在类的重构函数中定义临时变量,并且将临时变量的内容放入类成员变量作为初始化。
3、编写功能函数,获取CPU信息,并且将信息写入ini格式文本存储,并且可以读取和清除ini文本内容,在存储文本路径中使用函数获取当前执行文件的路径,方便ini格式文本的创建和读取等操作。
4、测试程序。

// ReadCpuInfo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
/*
请使用Visual Studio编写一个控制台程序,功能如下:

一、使用命令CPUInfo.exe -C读取本机CPU信息,并存储到INI格式文本中:
示例如下:
[CPU]
Manufacturer = AuthenticAMD

BrandID = AMD Athlon Gold 3150U with Radeon Graphics
CPUID = 0F81
Cores = 2
HyperThread = True
MainClock = 2396MHZ
L1CacheSize = 192KB
L2CacheSize = 1024KB
L3CacheSize = 4096KB

二、使用命令CPUInfo.exe -r 读取INI文本中的CPU信息,并打印在控制台上;

wmic cpu get processorid   ----------powershell查看CPUID
dxdiag ----------------DirectX诊断工具查看电脑配置
systeminfo查看电脑配置


*/
#include <iostream>
#include<string>
#include<map>
#include<Windows.h>
#include<intrin.h>
#include<thread>
#include <vector>
#include<sstream>
#include<fstream>
#include<algorithm>
#include<iomanip>
#include <atlstr.h>

using namespace std;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;

typedef BOOL(WINAPI* LPFN_GLPI)(LOGICAL_PROCESSOR_RELATIONSHIP,
    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD);

//缓存信息
struct CacheInfo
{
    int level;    // 第几级缓存
    int size;    // 缓存大小,单位KB

    CacheInfo()    // 构造函数
    {
        level = 0;
        size = 0;

    }

    CacheInfo(int clevel, int csize)  // 构造函数
    {
        level = clevel;
        size = csize;

    }

};

//序列号/ID号
struct Serialnumber {  
    WORD nibble[6];
    Serialnumber() {
        memset(nibble, 0, sizeof(nibble));  //复制字符串
    }
};

//cpu信息
struct CpuInfo
{
    string vID;
    string bID;
    string SeriNum;
    int cores;
    string HThread;
    double Mainclock;
};

class CPUID
{
public:
    static CPUID* Instance();
    static CPUID* m_pInstance;
    map<int, CacheInfo> m_cache; // Cache information table

    virtual ~CPUID();
    string GetVID();                //获取CPU制造商信息
    string GetBrand();              //获取CPU商标信息
    string Getserialnumber();      //获取ID序列号
    string IsHyperThreading();           //是否支持HyperThread

private:
    void Executecpuid(DWORD eax); // 用来实现cpuid
    DWORD m_eax;   // 存储返回的eax
    DWORD m_ebx;   // 存储返回的ebx
    DWORD m_ecx;   // 存储返回的ecx
    DWORD m_edx;   // 存储返回的edx

};

CPUID* CPUID::m_pInstance = NULL;

CPUID* CPUID::Instance()
{
    if (NULL == m_pInstance)		// if instance is not present, create a new instance
    {
        m_pInstance = new CPUID();
    }

    return m_pInstance;
}

CPUID::~CPUID()
{
    delete m_pInstance;		// delete instance
    m_pInstance = NULL;		// set the pointer to NULL
}

void CPUID::Executecpuid(DWORD veax)
{
    // 因为嵌入式的汇编代码不能识别 类成员变量
    // 所以定义四个临时变量作为过渡
    DWORD deax;
    DWORD debx;
    DWORD decx;
    DWORD dedx;

    __asm
    {
        mov eax, veax;// 将输入参数移入eax
        cpuid;         // 执行cpuid
        mov deax, eax; //以下四行代码把寄存器中的变量存入临时变量
        mov debx, ebx;
        mov decx, ecx;
        mov dedx, edx;
    }

    m_eax = deax; // 把临时变量中的内容放入类成员变量
    m_ebx = debx;
    m_ecx = decx;
    m_edx = dedx;

}

//获取cpu核心数
int GetCores()
{
    //注释:因为这里HyperThread的缘故,所以4核读成8核心
    //方式一
    //SYSTEM_INFO sysInfo;
    //GetSystemInfo(&sysInfo);
    //cout << "Cores = " << sysInfo.dwNumberOfProcessors /2 << endl;

    //方式二
    unsigned int nCpu = max(std::thread::hardware_concurrency(), (unsigned int)1);
  //  cout << "Cores = " << nCpu / 2 << endl;
    return (nCpu);
}

//获取cpu的主频信息
double GetMainClock()
{

    static int time[2];              //定义一个整型数组time
    int  a = 0;                   //定义整形变量a=0(在后面的运算中用来存商)
    int  b = 0;                   //定义整形变量b=0(在后面的运算中用来存余数)
    double sum = 0;
    __asm {
        rdtsc;                    //RDTSC指令,意思是读取时间标记计数器(Read Time-Stamp Counter)
        mov ecx, offset time;          //将time的偏移地址存入ecx
        mov[ecx + 0], edx;            //把TSC的值的高32位存入[ecx+0]中
        mov[ecx + 4], eax;            //把TSC的值的低32位存入[ecx+4]中
    }
    Sleep(1000);                  //延时1秒
    __asm {
        rdtsc;
        mov ebx, offset time;            //将time的偏移地址存入ebx
        sub eax, [ebx + 4];             //把延时1秒后的TSC值的高32位减去1秒前的TSC值的高32位
        sbb edx, [ebx + 0];             //把延时1秒后的TSC值的低32位减去1秒前的TSC值的低32位
        mov ecx, 1000000000;
        div ecx;               //将2次TSC差值除以1,000,000,000
        mov a, eax;
        mov b, edx;
    }
    b = b / 100000000;
    b = b * 10;
   // cout << "MainClock = " << a << "." << b << "GHz" << endl;
    sum = (a * 100 + b);
    sum = sum / 100;
    //cout << sum << endl;
    return sum;
}

//初始化除cpu三级缓存之外的其它信息
CpuInfo* init()
{
    CpuInfo* CInfo = new CpuInfo[2];
    CPUID* info = CPUID::Instance();

        CInfo[0].vID = info->GetVID();
        CInfo[0].bID = info->GetBrand();
        CInfo[0].SeriNum = info->Getserialnumber();
        CInfo[0].cores = GetCores();
        CInfo[0].HThread = info->IsHyperThreading();
        CInfo[0].Mainclock = GetMainClock();

    return CInfo;
}

//获得CPU的制造商信息(Vender ID String)
//把eax = 0作为输入参数,可以得到CPU的制造商信息。
string CPUID::GetVID()
{
    char cVID[13];   // 字符串,用来存储制造商信息
    memset(cVID, 0, 13);  // 把数组清0
    Executecpuid(0);  // 执行cpuid指令,使用输入参数 eax = 0
    memcpy(cVID, &m_ebx, 4); // 复制前四个字符到数组
    memcpy(cVID + 4, &m_edx, 4); // 复制中间四个字符到数组
    memcpy(cVID + 8, &m_ecx, 4); // 复制最后四个字符到数组
    return string(cVID);  // 以string的形式返回
}

//获得CPU商标信息(Brand String)
string CPUID::GetBrand()
{
    const DWORD BRANDID = 0x80000002;  // 从0x80000002开始,到0x80000004结束
    char cBrand[49];    // 用来存储商标字符串,48个字符
    memset(cBrand, 0, 49);    // 初始化为0

    for (DWORD i = 0; i < 3; i++)   // 依次执行3个指令
    {
        Executecpuid(BRANDID + i);
        memcpy(cBrand + i * 16, &m_eax, 16); // 每次执行结束后,保存四个寄存器里的asc码到数组
    }      // 由于在内存中,m_eax, m_ebx, m_ecx, m_edx是连续排列
          // 所以可以直接以内存copy的方式进行保存
    return string(cBrand);  // 以string的形式返回
}

//获取ID序列号
string CPUID::Getserialnumber() {

    string serialnumber;
    char num[32];
    memset(num, 0, 32);
    Executecpuid(1);
    sprintf_s(num, 32, "%08X", m_edx);
    serialnumber = serialnumber + num;
    //memcpy(&serial.nibble[4], &m_eax, 4);
    sprintf_s(num, 32, "%08X", m_eax);
    serialnumber = serialnumber + num;
    //memcpy(&serial.nibble[0], &m_ecx, 8);

    return serialnumber;
}

// 判断是否支持hyper-threading
string CPUID::IsHyperThreading()
{
    bool HyperThread;
    string str;
    Executecpuid(1);  // 执行cpuid指令,使用输入参数 eax = 1
    HyperThread = (m_edx & (1 << 28));
    if (!HyperThread)
    {
     //   cout << "HyperThread = False" << endl;
        str = "False";
        return str;
    }
    else
    {
      //  cout << "HyperThread = Ture" << endl;
        str = "Ture";
        return str;
    }
   // return m_edx & (1 << 28);  // 返回edx的bit 28
}

//获取cpu三级缓存信息
CacheInfo*  GetCacheInfo()
{
    CacheInfo* cpuCache = new CacheInfo[3];
    int L1 = 0;
    int L2 = 0;
    int L3 = 0;

    LPFN_GLPI glpi = (LPFN_GLPI)GetProcAddress(
        GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformationEx");

    if (!glpi)
        return NULL;

    DWORD bytes = 0;
    glpi(RelationAll, 0, &bytes);
    vector<char> buffer(bytes);
    SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* info;

    if (!glpi(RelationAll, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)&buffer[0], &bytes))
        return NULL;

    for (size_t i = 0; i < bytes; i += info->Size)
    {
        info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)&buffer[i];

        if (info->Relationship == RelationCache &&
            (info->Cache.Type == CacheData ||
                info->Cache.Type == CacheUnified))
        {
            if ((int)info->Cache.Level == 1)
            {

                L1 += (int)info->Cache.CacheSize;

            }
            if ((int)info->Cache.Level == 2)
            {
                L2 += (int)info->Cache.CacheSize;
            }
            if ((int)info->Cache.Level == 3)
            {
                L3 += (int)info->Cache.CacheSize;
            }
        }
    }
    //cout << "L1CacheSize = " << L1 * 2 / 1024 << "KB" << endl;
    //cout << "L2CacheSize = " << L2 / 1024 << "KB" << endl;
    //cout << "L3CacheSize = " << L3 / 1024 << "KB" << endl;

    cpuCache[0].level = 1;
    cpuCache[0].size = L1 * 2 / 1024;
    cpuCache[1].level = 2;
    cpuCache[1].size = L2 / 1024;
    cpuCache[2].level = 3;
    cpuCache[2].size = L3 / 1024;

    return cpuCache;
}

//将获取的cpu信息写进INI文档
void WriteInfo(CpuInfo *CInfo,CacheInfo* cpuCache)
{
    int i = 0;
    //自动获取文本地址
    CString path;
    GetModuleFileName(NULL, path.GetBufferSetLength(MAX_PATH + 1), MAX_PATH);
    path.ReleaseBuffer();
    int pos = path.ReverseFind('\\');
    path = path.Left(pos);
    path = path + L"\\cpuINfoTest.ini";
    ofstream ofs;
    ofs.open(path, ios::out | ios::app);
    if (!ofs)
    {
        cout << "Open file error" << endl;
        return;
    }
    ofs << "[CPU]" << endl;
    ofs << "Manufacturer = " << CInfo[i].vID << endl;
    ofs << "BrandID = " << CInfo[i].bID << endl;
    ofs << "CPUID = " << CInfo[i].SeriNum << endl;
    ofs << "Cores = " << CInfo[i].cores << endl;
    ofs << "HyperThread =" << CInfo[i].HThread << endl;
    ofs.setf(ios::fixed);
    ofs << "MainClock = " << fixed << setprecision(2) << CInfo[i].Mainclock << "GHz" << endl;  //保留两位小数点
    ofs << "L" << cpuCache[0].level << "CacheSize = " << cpuCache[0].size << "KB" << endl;
    ofs << "L" << cpuCache[1].level << "CacheSize = " << cpuCache[1].size << "KB" << endl;
    ofs << "L" << cpuCache[2].level << "CacheSize = " << cpuCache[2].size << "KB" << endl;

    ofs << "\n";
    cout << "\n ini file write success!" << endl;
    ofs.close();
    return;
}

//从INI格式文本中读取内容
void ReadInfo(CpuInfo* CInfo, CacheInfo* cpuCache)
{
    int n = 0;
    ifstream ifs;

    CString path;
    GetModuleFileName(NULL, path.GetBufferSetLength(MAX_PATH + 1), MAX_PATH);
    path.ReleaseBuffer();
    int pos = path.ReverseFind('\\');
    path = path.Left(pos);
    path = path + L"\\cpuINfoTest.ini";

    ifs.open(path, ios::in);
    if (!ifs)
    {
        cout << "Open file error" << endl;
        return;
    }
    string str;
    while (!ifs.eof())           //读到文件结束
    {
        getline(ifs, str);
        cout << str << endl;
    }
    cout << "\n" << endl;
    cout << "read file success" << endl;
    ifs.close();
    return;
}

//打印需要获取的CPU信息
void display(CpuInfo* CInfo, CacheInfo* cpuCache)
{
    int i = 0;
    cout << "[CPU]" << endl;
    cout << "Manufacturer = " << CInfo[i].vID << endl;
    cout << "BrandID = " << CInfo[i].bID << endl;
    cout << "CPUID = " << CInfo[i].SeriNum << endl;
    cout << "Cores = " << CInfo[i].cores << endl;
    cout << "HyperThread =" << CInfo[i].HThread << endl;
    cout.setf(ios::fixed);                            
    cout << "MainClock = " << fixed << setprecision(2) << CInfo[i].Mainclock  << "GHz" << endl;  //保留两位小数点
    cout << "L" << cpuCache[0].level << "CacheSize = " << cpuCache[0].size << "KB" << endl;
    cout << "L" << cpuCache[1].level << "CacheSize = " << cpuCache[1].size << "KB" << endl;
    cout << "L" << cpuCache[2].level << "CacheSize = " << cpuCache[2].size << "KB" << endl;

    return;
}

//清空INI文本内容
void fileEmpty()
{
    CString path;
    GetModuleFileName(NULL, path.GetBufferSetLength(MAX_PATH + 1), MAX_PATH);
    path.ReleaseBuffer();
    int pos = path.ReverseFind('\\');
    path = path.Left(pos);
    path = path + L"\\cpuINfoTest.ini";

    fstream file;
    fstream open(path, ios::out | ios::binary);
    cout << "INI文本内容已成功清除内容" << endl;
    return;
}

//用户提示功能
void showhelp()
{
    cout << "--------------------------------------------" << endl;
    cout << "欢迎使用本系统" << endl;
    cout << "需要按照以下提示输入才可以实现对应功能\n" << endl;
    cout << "C: 读取本机CPU信息,并存储到INI格式文本" << endl;
    cout << "R:读取INI文本中的CPU信息,并显示" << endl;
    cout << "L: 清空存储CPU信息的INI文本内容" << endl;
    cout << "exit: 退出系统" << endl;
    cout << "--------------------------------------------" << endl;
    cout << "\n";
}

int main(int argc, char* argv[])
{

    CpuInfo* cpuInfo =  init();
    CacheInfo* cache = GetCacheInfo();
    showhelp();
    if (argc == 2)
    {

        if (strcmp(argv[1], "C") == 0 || strcmp(argv[1], "c") == 0)
        {
            display(cpuInfo, cache);
            WriteInfo(cpuInfo, cache);
        }
        else if (strcmp(argv[1], "R") == 0 || strcmp(argv[1], "r") == 0)
        {
            ReadInfo(cpuInfo, cache);
        }
        else if (strcmp(argv[1], "L") == 0 || strcmp(argv[1], "l") == 0)
        {
            fileEmpty();
        }
        else if (strcmp(argv[1], "exit") == 0)
        {
            //return -1;
            exit(0);
        }
        else
        {
            cout << "输入错误,请根据showhelp提示输入 " << endl;
            return 0;
         //   showhelp();
         //   system("pause");
        }
    }
    else
    {
        cout << "输入错误,请根据showhelp提示输入 " << endl;
       // showhelp();
        system("pause");
    }
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

运行结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看到这里就结束了,希望你今天仍然美好

需要cpuid.pdf的读者可私信

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值