Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.

Commit bd4d5de

Browse files
authored
Add cpuinfo to help check cpu instruction (#611)
Co-authored-by: Hien To <tominhhien97@gmail.com>
1 parent deb2600 commit bd4d5de

File tree

7 files changed

+346
-1
lines changed

7 files changed

+346
-1
lines changed

cortex-js/cpuinfo/README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# CPU Info
2+
3+
This source code provides a simple C++ program to retrieve and display information about the CPU, including the vendor, brand, number of cores, number of logical processors (threads), and supported instruction sets (e.g., SSE, AVX, AVX512).
4+
5+
## Files
6+
7+
### CPUID.h
8+
9+
This header file contains the CPUID class, which abstracts the CPUID instruction. The class provides methods to retrieve the values of the EAX, EBX, ECX, and EDX registers after calling the CPUID instruction with a given function ID.
10+
11+
### cpuinfo.cpp
12+
13+
This source file implements the CPUInfo class, which uses the CPUID class to gather various CPU-related information. The main function prints this information in JSON format.
14+
15+
## Building
16+
17+
### Windows
18+
19+
To build the project on Windows, you can use Microsoft Visual Studio or the Visual Studio Developer Command Prompt.
20+
21+
**Using Visual Studio Developer Command Prompt**
22+
23+
1. Open the Developer Command Prompt for Visual Studio.
24+
25+
2. Navigate to the project directory:
26+
```cmd
27+
cd path\to\your\project\directory
28+
```
29+
30+
3. Compile the source code using the following command:
31+
```cmd
32+
cl cpuinfo.cpp /EHsc
33+
```
34+
35+
This will create the executable cpuinfo.exe in the current directory.
36+
37+
### Linux
38+
39+
To build the project on Linux, you need g++ (the GNU C++ compiler).
40+
41+
1. Open a terminal.
42+
43+
2. Navigate to the project directory:
44+
```bash
45+
cd path/to/your/project/directory
46+
```
47+
48+
3. Compile the code:
49+
```bash
50+
g++ cpuinfo.cpp -o cpuinfo
51+
```
52+
53+
This will create the executable cpuinfo in the current directory.
54+
55+
## Running the Program
56+
57+
### Windows
58+
59+
After building the project, you can run the executable from the command prompt:
60+
61+
```cmd
62+
cpuinfo.exe
63+
```
64+
65+
### Linux
66+
67+
After building the project, you can run the executable from the terminal:
68+
69+
```bash
70+
./cpuinfo
71+
```
72+
73+
## Example Output
74+
75+
The program prints the CPU information in JSON format. Example output:
76+
77+
```json
78+
{
79+
"vendor": "GenuineIntel",
80+
"brand": "12th Gen Intel(R) Core(TM) i5-12400F",
81+
"cores": 6,
82+
"threads": 12,
83+
"is_hyperthreading": true,
84+
"instructions": {
85+
"SSE": true,
86+
"SSE2": true,
87+
"SSE3": true,
88+
"SSE41": true,
89+
"SSE42": true,
90+
"AVX": true,
91+
"AVX2": true,
92+
"AVX512": true
93+
}
94+
}
95+
```
96+
97+
## Notes
98+
- Ensure that your environment is properly set up for compiling C++ code. On Windows, this typically involves installing Visual Studio with the C++ build tools. On Linux, you need to have g++ installed.
99+
- The JSON output format is designed to be easy to parse and read.
100+
- In the `bin` directory, there are pre-built outputs. For Windows, the code is signed with our certificate. You can download and use it directly or build from source.

cortex-js/cpuinfo/bin/cpuinfo

23.4 KB
Binary file not shown.

cortex-js/cpuinfo/bin/cpuinfo.exe

218 KB
Binary file not shown.

cortex-js/cpuinfo/src/CPUID.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef CPUID_H
2+
#define CPUID_H
3+
4+
#ifdef _WIN32
5+
#include <limits.h>
6+
#include <intrin.h>
7+
typedef unsigned __int32 uint32_t;
8+
#else
9+
#include <stdint.h>
10+
#endif
11+
12+
class CPUID {
13+
uint32_t regs[4];
14+
15+
public:
16+
explicit CPUID(unsigned i) {
17+
#ifdef _WIN32
18+
__cpuid((int *)regs, (int)i);
19+
#else
20+
asm volatile
21+
("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
22+
: "a" (i), "c" (0));
23+
// ECX is set to zero for CPUID function 4
24+
#endif
25+
}
26+
27+
const uint32_t &EAX() const {return regs[0];}
28+
const uint32_t &EBX() const {return regs[1];}
29+
const uint32_t &ECX() const {return regs[2];}
30+
const uint32_t &EDX() const {return regs[3];}
31+
};
32+
33+
#endif // CPUID_H

cortex-js/cpuinfo/src/cpuinfo.cpp

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
#include <algorithm>
2+
#include <iostream>
3+
#include <string>
4+
5+
#ifdef _WIN32
6+
#include <limits.h>
7+
#include <intrin.h>
8+
typedef unsigned __int32 uint32_t;
9+
#else
10+
#include <stdint.h>
11+
#endif
12+
13+
using namespace std;
14+
15+
#define MAX_INTEL_TOP_LVL 4
16+
17+
class CPUID {
18+
uint32_t regs[4];
19+
20+
public:
21+
explicit CPUID(unsigned funcId, unsigned subFuncId) {
22+
#ifdef _WIN32
23+
__cpuidex((int *)regs, (int)funcId, (int)subFuncId);
24+
25+
#else
26+
asm volatile
27+
("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
28+
: "a" (funcId), "c" (subFuncId));
29+
// ECX is set to zero for CPUID function 4
30+
#endif
31+
}
32+
33+
const uint32_t &EAX() const {return regs[0];}
34+
const uint32_t &EBX() const {return regs[1];}
35+
const uint32_t &ECX() const {return regs[2];}
36+
const uint32_t &EDX() const {return regs[3];}
37+
};
38+
39+
class CPUInfo {
40+
public:
41+
CPUInfo();
42+
string vendor() const { return mVendorId; }
43+
string model() const { return mModelName; }
44+
int cores() const { return mNumCores; }
45+
float cpuSpeedInMHz() const { return mCPUMHz; }
46+
bool isSSE() const { return mIsSSE; }
47+
bool isSSE2() const { return mIsSSE2; }
48+
bool isSSE3() const { return mIsSSE3; }
49+
bool isSSE41() const { return mIsSSE41; }
50+
bool isSSE42() const { return mIsSSE42; }
51+
bool isAVX() const { return mIsAVX; }
52+
bool isAVX2() const { return mIsAVX2; }
53+
bool isAVX512() const { return mIsAVX512; }
54+
bool isHyperThreaded() const { return mIsHTT; }
55+
int logicalCpus() const { return mNumLogCpus; }
56+
57+
private:
58+
// Bit positions for data extractions
59+
static const uint32_t SSE_POS = 0x02000000;
60+
static const uint32_t SSE2_POS = 0x04000000;
61+
static const uint32_t SSE3_POS = 0x00000001;
62+
static const uint32_t SSE41_POS = 0x00080000;
63+
static const uint32_t SSE42_POS = 0x00100000;
64+
static const uint32_t AVX_POS = 0x10000000;
65+
static const uint32_t AVX2_POS = 0x00000020;
66+
static const uint32_t AVX512_POS = 0x00010000; // AVX-512F bit in EBX from CPUID function 7
67+
static const uint32_t LVL_NUM = 0x000000FF;
68+
static const uint32_t LVL_TYPE = 0x0000FF00;
69+
static const uint32_t LVL_CORES = 0x0000FFFF;
70+
71+
// Attributes
72+
string mVendorId;
73+
string mModelName;
74+
int mNumSMT;
75+
int mNumCores;
76+
int mNumLogCpus;
77+
float mCPUMHz;
78+
bool mIsHTT;
79+
bool mIsSSE;
80+
bool mIsSSE2;
81+
bool mIsSSE3;
82+
bool mIsSSE41;
83+
bool mIsSSE42;
84+
bool mIsAVX;
85+
bool mIsAVX2;
86+
bool mIsAVX512;
87+
};
88+
89+
CPUInfo::CPUInfo()
90+
{
91+
// Get vendor name EAX=0
92+
CPUID cpuID0(0, 0);
93+
uint32_t HFS = cpuID0.EAX();
94+
mVendorId += string((const char *)&cpuID0.EBX(), 4);
95+
mVendorId += string((const char *)&cpuID0.EDX(), 4);
96+
mVendorId += string((const char *)&cpuID0.ECX(), 4);
97+
// Get SSE instructions availability
98+
CPUID cpuID1(1, 0);
99+
mIsHTT = cpuID1.EDX() & AVX_POS;
100+
mIsSSE = cpuID1.EDX() & SSE_POS;
101+
mIsSSE2 = cpuID1.EDX() & SSE2_POS;
102+
mIsSSE3 = cpuID1.ECX() & SSE3_POS;
103+
mIsSSE41 = cpuID1.ECX() & SSE41_POS;
104+
mIsSSE42 = cpuID1.ECX() & SSE41_POS;
105+
mIsAVX = cpuID1.ECX() & AVX_POS;
106+
// Get AVX2 and AVX512 instructions availability
107+
CPUID cpuID7(7, 0);
108+
mIsAVX2 = cpuID7.EBX() & AVX2_POS;
109+
mIsAVX512 = cpuID7.EBX() & AVX512_POS;
110+
111+
string upVId = mVendorId;
112+
for_each(upVId.begin(), upVId.end(), [](char& in) { in = ::toupper(in); });
113+
// Get num of cores
114+
if (upVId.find("INTEL") != std::string::npos) {
115+
if(HFS >= 11) {
116+
for (int lvl=0; lvl<MAX_INTEL_TOP_LVL; ++lvl) {
117+
CPUID cpuID4(0x0B, lvl);
118+
uint32_t currLevel = (LVL_TYPE & cpuID4.ECX())>>8;
119+
switch(currLevel) {
120+
case 0x01: mNumSMT = LVL_CORES & cpuID4.EBX(); break;
121+
case 0x02: mNumLogCpus = LVL_CORES & cpuID4.EBX(); break;
122+
default: break;
123+
}
124+
}
125+
mNumCores = mNumLogCpus/mNumSMT;
126+
} else {
127+
if (HFS>=1) {
128+
mNumLogCpus = (cpuID1.EBX() >> 16) & 0xFF;
129+
if (HFS>=4) {
130+
mNumCores = 1 + (CPUID(4, 0).EAX() >> 26) & 0x3F;
131+
}
132+
}
133+
if (mIsHTT) {
134+
if (!(mNumCores>1)) {
135+
mNumCores = 1;
136+
mNumLogCpus = (mNumLogCpus >= 2 ? mNumLogCpus : 2);
137+
}
138+
} else {
139+
mNumCores = mNumLogCpus = 1;
140+
}
141+
}
142+
} else if (upVId.find("AMD") != std::string::npos) {
143+
if (HFS>=1) {
144+
mNumLogCpus = (cpuID1.EBX() >> 16) & 0xFF;
145+
if (CPUID(0x80000000, 0).EAX() >=8) {
146+
mNumCores = 1 + (CPUID(0x80000008, 0).ECX() & 0xFF);
147+
}
148+
}
149+
if (mIsHTT) {
150+
if (!(mNumCores>1)) {
151+
mNumCores = 1;
152+
mNumLogCpus = (mNumLogCpus >= 2 ? mNumLogCpus : 2);
153+
}
154+
} else {
155+
mNumCores = mNumLogCpus = 1;
156+
}
157+
} else {
158+
cout<< "Unexpected vendor id" <<endl;
159+
}
160+
// Get processor brand string
161+
// This seems to be working for both Intel & AMD vendors
162+
for(int i=0x80000002; i<0x80000005; ++i) {
163+
CPUID cpuID(i, 0);
164+
mModelName += string((const char*)&cpuID.EAX(), 4);
165+
mModelName += string((const char*)&cpuID.EBX(), 4);
166+
mModelName += string((const char*)&cpuID.ECX(), 4);
167+
mModelName += string((const char*)&cpuID.EDX(), 4);
168+
}
169+
}
170+
171+
int main(int argc, char *argv[])
172+
{
173+
CPUInfo cinfo;
174+
175+
cout << "{\n";
176+
cout << " \"vendor\": \"" << cinfo.vendor() << "\",\n";
177+
cout << " \"brand\": \"" << cinfo.model() << "\",\n";
178+
cout << " \"cores\": " << cinfo.cores() << ",\n";
179+
cout << " \"threads\": " << cinfo.logicalCpus() << ",\n";
180+
cout << " \"is_hyperthreading\": " << (cinfo.isHyperThreaded() ? "true" : "false") << ",\n";
181+
cout << " \"instructions\": {\n";
182+
cout << " \"SSE\": " << (cinfo.isSSE() ? "true" : "false") << ",\n";
183+
cout << " \"SSE2\": " << (cinfo.isSSE2() ? "true" : "false") << ",\n";
184+
cout << " \"SSE3\": " << (cinfo.isSSE3() ? "true" : "false") << ",\n";
185+
cout << " \"SSE41\": " << (cinfo.isSSE41() ? "true" : "false") << ",\n";
186+
cout << " \"SSE42\": " << (cinfo.isSSE42() ? "true" : "false") << ",\n";
187+
cout << " \"AVX\": " << (cinfo.isAVX() ? "true" : "false") << ",\n";
188+
cout << " \"AVX2\": " << (cinfo.isAVX2() ? "true" : "false") << ",\n";
189+
cout << " \"AVX512\": " << (cinfo.isAVX512() ? "true" : "false") << "\n";
190+
cout << " }\n";
191+
cout << "}\n";
192+
193+
return 0;
194+
}

cortex-js/cpuinfo/src/example.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"vendor": "GenuineIntel",
3+
"brand": "12th Gen Intel(R) Core(TM) i5-12400F",
4+
"cores": 6,
5+
"threads": 12,
6+
"is_hyperthreading": true,
7+
"instructions":
8+
{
9+
"SSE": true,
10+
"SSE2": true,
11+
"SSE3": true,
12+
"SSE41": true,
13+
"SSE42": true,
14+
"AVX": true,
15+
"AVX2": true,
16+
"AVX512": true
17+
}
18+
}

cortex-js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
},
1010
"scripts": {
1111
"dev": "nest dev",
12-
"build": "yarn build:extensions && nest build",
12+
"build": "yarn build:extensions && nest build && cp -r cpuinfo/bin ./dist/",
1313
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
1414
"build:extensions": "for dir in ./src/extensions/*/; do (cd \"$dir\" && yarn && yarn build); done",
1515
"start": "nest start",

0 commit comments

Comments
 (0)