Skip to content

Commit

Permalink
Merge branch 'dev' of github.com:janhq/nitro into feat/python-runtime…
Browse files Browse the repository at this point in the history
…-engine
  • Loading branch information
vansangpfiev committed May 28, 2024
2 parents 861e754 + 08d6682 commit 490762c
Show file tree
Hide file tree
Showing 68 changed files with 12,667 additions and 155 deletions.
100 changes: 100 additions & 0 deletions cortex-js/cpuinfo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# CPU Info

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).

## Files

### CPUID.h

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.

### cpuinfo.cpp

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.

## Building

### Windows

To build the project on Windows, you can use Microsoft Visual Studio or the Visual Studio Developer Command Prompt.

**Using Visual Studio Developer Command Prompt**

1. Open the Developer Command Prompt for Visual Studio.

2. Navigate to the project directory:
```cmd
cd path\to\your\project\directory
```
3. Compile the source code using the following command:
```cmd
cl cpuinfo.cpp /EHsc
```
This will create the executable cpuinfo.exe in the current directory.
### Linux
To build the project on Linux, you need g++ (the GNU C++ compiler).
1. Open a terminal.
2. Navigate to the project directory:
```bash
cd path/to/your/project/directory
```
3. Compile the code:
```bash
g++ cpuinfo.cpp -o cpuinfo
```
This will create the executable cpuinfo in the current directory.
## Running the Program
### Windows
After building the project, you can run the executable from the command prompt:
```cmd
cpuinfo.exe
```

### Linux

After building the project, you can run the executable from the terminal:

```bash
./cpuinfo
```

## Example Output

The program prints the CPU information in JSON format. Example output:

```json
{
"vendor": "GenuineIntel",
"brand": "12th Gen Intel(R) Core(TM) i5-12400F",
"cores": 6,
"threads": 12,
"is_hyperthreading": true,
"instructions": {
"SSE": true,
"SSE2": true,
"SSE3": true,
"SSE41": true,
"SSE42": true,
"AVX": true,
"AVX2": true,
"AVX512": true
}
}
```

## Notes
- 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.
- The JSON output format is designed to be easy to parse and read.
- 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.
Binary file added cortex-js/cpuinfo/bin/cpuinfo
Binary file not shown.
Binary file added cortex-js/cpuinfo/bin/cpuinfo.exe
Binary file not shown.
33 changes: 33 additions & 0 deletions cortex-js/cpuinfo/src/CPUID.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#ifndef CPUID_H
#define CPUID_H

#ifdef _WIN32
#include <limits.h>
#include <intrin.h>
typedef unsigned __int32 uint32_t;
#else
#include <stdint.h>
#endif

class CPUID {
uint32_t regs[4];

public:
explicit CPUID(unsigned i) {
#ifdef _WIN32
__cpuid((int *)regs, (int)i);
#else
asm volatile
("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
: "a" (i), "c" (0));
// ECX is set to zero for CPUID function 4
#endif
}

const uint32_t &EAX() const {return regs[0];}
const uint32_t &EBX() const {return regs[1];}
const uint32_t &ECX() const {return regs[2];}
const uint32_t &EDX() const {return regs[3];}
};

#endif // CPUID_H
194 changes: 194 additions & 0 deletions cortex-js/cpuinfo/src/cpuinfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#include <algorithm>
#include <iostream>
#include <string>

#ifdef _WIN32
#include <limits.h>
#include <intrin.h>
typedef unsigned __int32 uint32_t;
#else
#include <stdint.h>
#endif

using namespace std;

#define MAX_INTEL_TOP_LVL 4

class CPUID {
uint32_t regs[4];

public:
explicit CPUID(unsigned funcId, unsigned subFuncId) {
#ifdef _WIN32
__cpuidex((int *)regs, (int)funcId, (int)subFuncId);

#else
asm volatile
("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
: "a" (funcId), "c" (subFuncId));
// ECX is set to zero for CPUID function 4
#endif
}

const uint32_t &EAX() const {return regs[0];}
const uint32_t &EBX() const {return regs[1];}
const uint32_t &ECX() const {return regs[2];}
const uint32_t &EDX() const {return regs[3];}
};

class CPUInfo {
public:
CPUInfo();
string vendor() const { return mVendorId; }
string model() const { return mModelName; }
int cores() const { return mNumCores; }
float cpuSpeedInMHz() const { return mCPUMHz; }
bool isSSE() const { return mIsSSE; }
bool isSSE2() const { return mIsSSE2; }
bool isSSE3() const { return mIsSSE3; }
bool isSSE41() const { return mIsSSE41; }
bool isSSE42() const { return mIsSSE42; }
bool isAVX() const { return mIsAVX; }
bool isAVX2() const { return mIsAVX2; }
bool isAVX512() const { return mIsAVX512; }
bool isHyperThreaded() const { return mIsHTT; }
int logicalCpus() const { return mNumLogCpus; }

private:
// Bit positions for data extractions
static const uint32_t SSE_POS = 0x02000000;
static const uint32_t SSE2_POS = 0x04000000;
static const uint32_t SSE3_POS = 0x00000001;
static const uint32_t SSE41_POS = 0x00080000;
static const uint32_t SSE42_POS = 0x00100000;
static const uint32_t AVX_POS = 0x10000000;
static const uint32_t AVX2_POS = 0x00000020;
static const uint32_t AVX512_POS = 0x00010000; // AVX-512F bit in EBX from CPUID function 7
static const uint32_t LVL_NUM = 0x000000FF;
static const uint32_t LVL_TYPE = 0x0000FF00;
static const uint32_t LVL_CORES = 0x0000FFFF;

// Attributes
string mVendorId;
string mModelName;
int mNumSMT;
int mNumCores;
int mNumLogCpus;
float mCPUMHz;
bool mIsHTT;
bool mIsSSE;
bool mIsSSE2;
bool mIsSSE3;
bool mIsSSE41;
bool mIsSSE42;
bool mIsAVX;
bool mIsAVX2;
bool mIsAVX512;
};

CPUInfo::CPUInfo()
{
// Get vendor name EAX=0
CPUID cpuID0(0, 0);
uint32_t HFS = cpuID0.EAX();
mVendorId += string((const char *)&cpuID0.EBX(), 4);
mVendorId += string((const char *)&cpuID0.EDX(), 4);
mVendorId += string((const char *)&cpuID0.ECX(), 4);
// Get SSE instructions availability
CPUID cpuID1(1, 0);
mIsHTT = cpuID1.EDX() & AVX_POS;
mIsSSE = cpuID1.EDX() & SSE_POS;
mIsSSE2 = cpuID1.EDX() & SSE2_POS;
mIsSSE3 = cpuID1.ECX() & SSE3_POS;
mIsSSE41 = cpuID1.ECX() & SSE41_POS;
mIsSSE42 = cpuID1.ECX() & SSE41_POS;
mIsAVX = cpuID1.ECX() & AVX_POS;
// Get AVX2 and AVX512 instructions availability
CPUID cpuID7(7, 0);
mIsAVX2 = cpuID7.EBX() & AVX2_POS;
mIsAVX512 = cpuID7.EBX() & AVX512_POS;

string upVId = mVendorId;
for_each(upVId.begin(), upVId.end(), [](char& in) { in = ::toupper(in); });
// Get num of cores
if (upVId.find("INTEL") != std::string::npos) {
if(HFS >= 11) {
for (int lvl=0; lvl<MAX_INTEL_TOP_LVL; ++lvl) {
CPUID cpuID4(0x0B, lvl);
uint32_t currLevel = (LVL_TYPE & cpuID4.ECX())>>8;
switch(currLevel) {
case 0x01: mNumSMT = LVL_CORES & cpuID4.EBX(); break;
case 0x02: mNumLogCpus = LVL_CORES & cpuID4.EBX(); break;
default: break;
}
}
mNumCores = mNumLogCpus/mNumSMT;
} else {
if (HFS>=1) {
mNumLogCpus = (cpuID1.EBX() >> 16) & 0xFF;
if (HFS>=4) {
mNumCores = 1 + (CPUID(4, 0).EAX() >> 26) & 0x3F;
}
}
if (mIsHTT) {
if (!(mNumCores>1)) {
mNumCores = 1;
mNumLogCpus = (mNumLogCpus >= 2 ? mNumLogCpus : 2);
}
} else {
mNumCores = mNumLogCpus = 1;
}
}
} else if (upVId.find("AMD") != std::string::npos) {
if (HFS>=1) {
mNumLogCpus = (cpuID1.EBX() >> 16) & 0xFF;
if (CPUID(0x80000000, 0).EAX() >=8) {
mNumCores = 1 + (CPUID(0x80000008, 0).ECX() & 0xFF);
}
}
if (mIsHTT) {
if (!(mNumCores>1)) {
mNumCores = 1;
mNumLogCpus = (mNumLogCpus >= 2 ? mNumLogCpus : 2);
}
} else {
mNumCores = mNumLogCpus = 1;
}
} else {
cout<< "Unexpected vendor id" <<endl;
}
// Get processor brand string
// This seems to be working for both Intel & AMD vendors
for(int i=0x80000002; i<0x80000005; ++i) {
CPUID cpuID(i, 0);
mModelName += string((const char*)&cpuID.EAX(), 4);
mModelName += string((const char*)&cpuID.EBX(), 4);
mModelName += string((const char*)&cpuID.ECX(), 4);
mModelName += string((const char*)&cpuID.EDX(), 4);
}
}

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

cout << "{\n";
cout << " \"vendor\": \"" << cinfo.vendor() << "\",\n";
cout << " \"brand\": \"" << cinfo.model() << "\",\n";
cout << " \"cores\": " << cinfo.cores() << ",\n";
cout << " \"threads\": " << cinfo.logicalCpus() << ",\n";
cout << " \"is_hyperthreading\": " << (cinfo.isHyperThreaded() ? "true" : "false") << ",\n";
cout << " \"instructions\": {\n";
cout << " \"SSE\": " << (cinfo.isSSE() ? "true" : "false") << ",\n";
cout << " \"SSE2\": " << (cinfo.isSSE2() ? "true" : "false") << ",\n";
cout << " \"SSE3\": " << (cinfo.isSSE3() ? "true" : "false") << ",\n";
cout << " \"SSE41\": " << (cinfo.isSSE41() ? "true" : "false") << ",\n";
cout << " \"SSE42\": " << (cinfo.isSSE42() ? "true" : "false") << ",\n";
cout << " \"AVX\": " << (cinfo.isAVX() ? "true" : "false") << ",\n";
cout << " \"AVX2\": " << (cinfo.isAVX2() ? "true" : "false") << ",\n";
cout << " \"AVX512\": " << (cinfo.isAVX512() ? "true" : "false") << "\n";
cout << " }\n";
cout << "}\n";

return 0;
}
18 changes: 18 additions & 0 deletions cortex-js/cpuinfo/src/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"vendor": "GenuineIntel",
"brand": "12th Gen Intel(R) Core(TM) i5-12400F",
"cores": 6,
"threads": 12,
"is_hyperthreading": true,
"instructions":
{
"SSE": true,
"SSE2": true,
"SSE3": true,
"SSE41": true,
"SSE42": true,
"AVX": true,
"AVX2": true,
"AVX512": true
}
}
Loading

0 comments on commit 490762c

Please sign in to comment.