第九篇 -- cpu的学习

CPU的核数关系:

总核数 = 物理CPU个数 X 每颗物理CPU的核数 
总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数

Linux中查看CPU数

# 查看物理CPU个数
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l

# 查看每个物理CPU中core的个数(即核数)
cat /proc/cpuinfo| grep "cpu cores"| uniq

# 查看逻辑CPU的个数
cat /proc/cpuinfo| grep "processor"| wc -l

C++获取系统中CPU的总逻辑CPU数:

// CPUCoreNumber.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "pch.h"
#include <iostream>
#include "windows.h"
using namespace std;

/****************************************************函数声明部分*******************************************************/
void GetCPUCoreNum();


/****************************************************主函数,即入口函数**************************************************/
int main()
{
    //1. 获取CPU的逻辑核数
    GetCPUCoreNum();
}


/***********************************************************************************************************************/
/*                                                   普通函数                                                           */
/***********************************************************************************************************************/

//获取CPU的总核心数
void GetCPUCoreNum() {
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    printf("now system cpu num is %d
", sysInfo.dwNumberOfProcessors);
}
View Code

检测方法:

在cmd命令中输入“wmic”,然后在出现的新窗口中输入“cpu get *”

NumberOfCores:表示CPU核心数

NumberOfLogicalProcessors:表示CPU线程数,也可以说是逻辑处理器的个数

根据上面的检测方法,可以获取CPU的物理个数

C++获取系统中CPU的物理CPU数

// CPUCoreNumber.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "pch.h"
#include <iostream>
#include "windows.h"
using namespace std;

/****************************************************函数声明部分*******************************************************/
void GetCPUCoreNum();
int GetPhyCpuNum(int &num);


/****************************************************主函数,即入口函数**************************************************/
int main()
{
    //1. 获取CPU的逻辑核数
    //GetCPUCoreNum();

    //2. 获取CPU物理个数
    int num = 0;
    GetPhyCpuNum(num);
    cout << num << endl;
}


/***********************************************************************************************************************/
/*                                                   普通函数                                                           */
/***********************************************************************************************************************/

//获取CPU的总核心数
void GetCPUCoreNum() {
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    printf("now system cpu num is %d
", sysInfo.dwNumberOfProcessors);
}

//获取CPU物理个数
int GetPhyCpuNum(int &num)
{
    // -------------------- 得到当前路径 ---------------------
    char path[256] = { 0 };
    char exePath[256] = { 0 };
    GetModuleFileName(NULL, exePath, sizeof(exePath));
    printf("%s
",exePath);

    int len = 0;
    len = strlen(exePath);


    int i;
    for (i = len - 1; i > 0; i--)
    {
        if (exePath[i] == '\')
            break;
    }
    if (i == 0)
        return -1;
    else
    {
        strncpy_s(path, exePath, i + 1);
        strcat_s(path, "cpuinfo.txt");
    }

    // ------------------- 发送wmic命令查询 结果放到文件中-------------------
    //printf("%s
",path);
    char cmd[512] = { 0 };
    sprintf_s(cmd, 512, "wmic cpu get > %s", path);//printf("%s
",cmd);
    system(cmd);
    Sleep(3000);


    // ------------------- 读文件内容到数组中 -------------------
    FILE *fp = NULL;
    int fileLen;


    fopen_s(&fp, path, "r");
    if (fp == NULL)
    {
        return -2;
    }
    fseek(fp, 0, SEEK_END); // 定位到文件末
    fileLen = ftell(fp); // 得到文件大小 
    if (fileLen == 0)
    {
        fclose(fp);
        return -3;
    }
    fseek(fp, 0L, SEEK_SET); // 定位到文件开头
    char *buffer = new char[fileLen + 1];
    fread(buffer, fileLen, 1, fp); // 一次性读取全部文件内容
    buffer[fileLen] = ''; // 字符串结束标志
    fclose(fp);


    // ------------------- 查询行数 -----------------------------
    i = 0;
    int n = 0;
    while (i < fileLen)
    {
        if (buffer[i] == '
')
            n++;
        i++;
    }


    num = n - 1; // 第一行是列名,要减去
    delete buffer;
    return 0;
}
View Code

看到这里可以发现,CPU的逻辑数,物理数都可以用第二种方法得到。

关于CPU MMX/SSE参考链接:

https://www.cnblogs.com/dragon2012/p/3731931.html

https://blog.csdn.net/thinkwell12/article/details/4466423

 关于CPU的寄存器理解:

汇编语言里 eax, ebx, ecx, edx, esi, edi, ebp, esp这些都是什么意思啊?

eax, ebx, ecx, edx, esi, edi, ebp, esp等都是X86 汇编语言中CPU上的通用寄存器的名称,是32位的寄存器。如果用C语言来解释,可以把这些寄存器当作变量看待。

EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。

EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址。

ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。

EDX 则总是被用来放整数除法产生的余数。

ESI/EDI分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.

EBP是"基址指针"(BASE POINTER), 它最经常被用作高级语言函数调用的"框架指针"(frame pointer). 在破解的时候,经常可以看见一个标准的函数起始代码:

  push ebp ;保存当前ebp
  mov ebp,esp ;EBP设为当前堆栈指针
  sub esp, xxx ;预留xxx字节给函数临时变量.
  ...

这样一来,EBP 构成了该函数的一个框架, 在EBP上方分别是原来的EBP, 返回地址和参数. EBP下方则是临时变量. 函数返回时作 mov esp,ebp/pop ebp/ret 即可.

ESP 专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。在32位平台上,ESP每次减少4字节。

386部分寄存器:

状态和控制寄存器组除了EFLAGS、IP ,还有四个32位的控制寄存器,它们是CR0,CR1,CR2和CR3。

这几个寄存器中保存全局性和任务无关的机器状态。

CR0中包含了6个预定义标志,0位是保护允许位PE(Protedted Enable),用于启动保护模式,如果PE位置1,则保护模式启动,如果PE=0,则在实模式下运行。1位是监控协处理位MP(Moniter coprocessor),它与第3位一起决定:当TS=1时操作码WAIT是否产生一个“协处理器不能使用”的出错信号。第3位是任务转换位(Task Switch),当一个任务转换完成之后,自动将它置1。随着TS=1,就不能使用协处理器。CR0的第2位是模拟协处理器位 EM (Emulate coprocessor),如果EM=1,则不能使用协处理器,如果EM=0,则允许使用协处理器。第4位是微处理器的扩展类型位ET(Processor Extension Type),其内保存着处理器扩展类型的信息,如果ET=0,则标识系统使用的是287协处理器,如果 ET=1,则表示系统使用的是387浮点协处理器。CR0的第31位是分页允许位(Paging Enable),它表示芯片上的分页部件是否允许工作。

CR1是未定义的控制寄存器,供将来的处理器使用。

CR2是页故障线性地址寄存器,保存最后一次出现页故障的全32位线性地址。

CR3是页目录基址寄存器,保存页目录表的物理地址,页目录表总是放在以4K字节为单位的存储器边界上,因此,它的地址的低12位总为0,不起作用,即使写上内容,也不会被理会。

这几个寄存器是与分页机制密切相关的,因此,在进程管理及虚拟内存管理中会涉及到这几个寄存器,读者要记住CR0、CR2及CR3这三个寄存器的内容。

当输入0x1时,EDX返回的扩展信息解释如下:

位  标号    解释
0  FPU  Floating Point Unit On-Chip. CPU是否内置浮点计算单元
1  VME  Virtual 8086 Mode Enhancements. 是否支持虚拟8086模式
2  DE  Debugging Extensions. 是否支持调试功能.
3  PSE  Page Size Extension. 是否支持大于4MB的分页.
4  TSC  Time Stamp Counter. 是否支持RDTSC指令.(注:RDTSC指令可以计算出CPU的频率)
5  MSR  Module Specific Registers RDMSR and WRMSR Instructions. 是否支持RDMSR与WRMSR (*注1)
6  PAE  Physical Address Extension. 是否支持大于32bit的物理地址.
7  MCE  Machine Check Exception. (*注2)
8  CX8  CMPXCHG8B Instruction. 是否支持8bytes(64bit)数的比较与交换指令.
9  APIC  APIC On-Chip.是否支持APIC(Advanced Programmable Interrupt Controller)
10  保留
11  SEP  SYSENTER and SYSEXIT Instructions.是否支持SYSENTER与SYSEXIT指令.(*注3)
12  MTRR  Memory Type Range Registers. 是否支持MTTR(*注4)
13  PGE  PTE Global Bit. 是否支持全局页面目录入口标志位 (global bit in page directory entries)
14  MCA  Machine Check Architecture. 是否支持MCA,MCA是Pentium4,Xeon,P6级处理器的一个错误报告机制
15  CMOV  Conditional Move Instructions. CMOV指令是否可用.(请问谁可以解释一下CMOV是什么命令?)
16  PAT  Page Attribute Table. 是否支持PAT,PAT允许操作系统指定4K大小的线性内存空间
17  PSE-36  32-bit Page Size Extension. 是否支持4GB的扩展内存
18  PSN  Processor Serial Number. 是否支持处理器序列号.(P3有效)
19  CLFSH  CLFLUSH Instruction.是否支持CLFLUSH.(*注5)
20  保留
21  DS  Debug Store. 是否支持把调试信息写入缓存,
22  ACPI  ACPI Processor Performance Modulation Registers. 处理器使用特别的寄存器以允许软件控制处理器的运行周期.
23   MMX  Inter MMX Technology.是否支持MMX
24  FXSR  FXSAVE and FXRSTOR Instructions. FXSAVE与FXRSTOR指令是否可用(*注6)
25  SSE  SSE.是否支持SSE.
26  SSE2  是否支持SSE2.
27  SS  Self Snoop. 处理器是否支持总线监视,以防止储存器冲突.
28  保留
29  TM  Thermal Monitor.CPU是否支持温度控制.

30 & 31  保留

解释

physical processor packages:物理处理器封装个数,即俗称的“物理CPU数”。例如一块“Intel Core i3-2310M”只有1个“物理处理器封装个数”。若对于有多个处理器插槽的服务器,“物理处理器封装个数”很可能会大于1。
processor cores:处理器核心数,即俗称的“CPU核心数”。例如“Intel Core i3-2310M”是双核处理器,它有2个“处理器核心数”。
logical processors:逻辑处理器数,即俗称的“逻辑CPU数”。例如“Intel Core i3-2310M”支持超线程,一个物理核心能模拟为两个逻辑处理器,即一块“Intel Core i3-2310M”有4个“逻辑处理器数”。

另外,学习小提示

1. 可以谷歌搜索资料,关于CPUID部分,资料会比百度上多一些。https://c9x.me/x86/html/file_module_x86_id_45.html

2. 可以进入Intel官网,查到相关CPU,然后点击datasheet,里面会有关于CPU的文档,并且可以将代码得到的结果与官网上进行比较,可以初步判断代码是否有误。

i7-7700的资料:https://ark.intel.com/content/www/us/en/ark/products/97128/intel-core-i7-7700-processor-8m-cache-up-to-4-20-ghz.html

 3.中文翻译部分文档:http://scc.qibebt.cas.cn/docs/optimization/VTune(TM)%20User%27s%20Guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/instruct32_hh/vc46.htm

 2019/7/10

学习CPU进程线程相关:https://blog.csdn.net/flyingleo1981/article/details/15812141

可以调用GetProcessAffinityMask函数来取得一个进程相关性屏蔽信息。

BOOL GetProcessAffinityMask(
   HANDLE hProcess,
   PDWORD_PTR pdwProcessAffinityMask,
   PDWORD_PTR pdwSystemAffinityMask);

该函数通过第二个参数返回指定进程的CPU的相关性信息,同时可以通过第三个参数返回系统相关性信息。系统相关性指明系统的哪些CPU可以处理线程,进程的相关性始终是系统相关性的子集。


原文地址:https://www.cnblogs.com/smart-zihan/p/11081916.html