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

Commit 50abbea

Browse files
authored
feat: cpu instruction set detection (#570)
1 parent 739d544 commit 50abbea

File tree

16 files changed

+923
-7
lines changed

16 files changed

+923
-7
lines changed

cortex-cpp/CMakeLists.txt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,28 @@ endif()
5959

6060
add_compile_definitions(CORTEX_CPP_VERSION="${CORTEX_CPP_VERSION}")
6161

62+
if(LLAMA_CUDA)
63+
add_compile_definitions(CORTEX_CUDA)
64+
endif()
65+
66+
if(LLAMA_AVX512)
67+
add_compile_definitions(CORTEX_AVX512)
68+
endif()
69+
70+
if(LLAMA_AVX2)
71+
add_compile_definitions(CORTEX_AVX2)
72+
endif()
73+
74+
if(LLAMA_VULKAN)
75+
add_compile_definitions(CORTEX_VULKAN)
76+
endif()
77+
6278
add_subdirectory(test)
6379

64-
add_executable(${PROJECT_NAME} main.cc)
80+
add_executable(${PROJECT_NAME} main.cc
81+
${CMAKE_CURRENT_SOURCE_DIR}/utils/cpuid/cpu_info.cc
82+
${CMAKE_CURRENT_SOURCE_DIR}/utils/cpuid/cpu_validation.cc
83+
)
6584

6685
# ##############################################################################
6786
# If you include the drogon source code locally in your project, use this method

cortex-cpp/Makefile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ endif
3939

4040
pre-package:
4141
ifeq ($(OS),Windows_NT)
42-
@powershell -Command "mkdir -p cortex-cpp\engines\cortex.llamacpp\; cp -r build\engines\cortex.llamacpp\engine.dll cortex-cpp\engines\cortex.llamacpp\;"
43-
@powershell -Command "cp -r build\Release\cortex-cpp.exe .\cortex-cpp\;"
44-
@powershell -Command "cp -r build-deps\_install\bin\zlib.dll .\cortex-cpp\;"
45-
@powershell -Command "cp -r ..\.github\patches\windows\msvcp140.dll .\cortex-cpp\;"
46-
@powershell -Command "cp -r ..\.github\patches\windows\vcruntime140_1.dll .\cortex-cpp\;"
47-
@powershell -Command "cp -r ..\.github\patches\windows\vcruntime140.dll .\cortex-cpp\;"
42+
@powershell -Command "mkdir -p cortex-cpp\engines\cortex.llamacpp\; cp build\engines\cortex.llamacpp\engine.dll cortex-cpp\engines\cortex.llamacpp\;"
43+
@powershell -Command "cp build\Release\cortex-cpp.exe .\cortex-cpp\;"
44+
@powershell -Command "cp build-deps\_install\bin\zlib.dll .\cortex-cpp\;"
45+
@powershell -Command "cp ..\.github\patches\windows\msvcp140.dll .\cortex-cpp\;"
46+
@powershell -Command "cp ..\.github\patches\windows\vcruntime140_1.dll .\cortex-cpp\;"
47+
@powershell -Command "cp ..\.github\patches\windows\vcruntime140.dll .\cortex-cpp\;"
4848
else ifeq ($(shell uname -s),Linux)
4949
@mkdir -p cortex-cpp/engines/cortex.llamacpp; \
5050
cp build/engines/cortex.llamacpp/libengine.so cortex-cpp/engines/cortex.llamacpp/; \

cortex-cpp/controllers/server.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#include "trantor/utils/Logger.h"
88
#include "utils/cortex_utils.h"
9+
#include "utils/cpuid/cpu_info.h"
10+
#include "utils/cpuid/cpu_validation.h"
911
#include "utils/logging_utils.h"
1012

1113
using namespace inferences;
@@ -265,6 +267,15 @@ void server::LoadModel(const HttpRequestPtr& req,
265267
};
266268

267269
try {
270+
if (engine_type == kLlamaEngine) {
271+
cortex::cpuid::CpuInfo cpu_info;
272+
LOG_INFO << "CPU instruction set: " << cpu_info.to_string();
273+
if (auto [res, err] = cortex::cpuid::llamacpp::IsValidInstructions();
274+
!res) {
275+
LOG_WARN << err;
276+
}
277+
}
278+
268279
std::string abs_path =
269280
cortex_utils::GetCurrentPath() + get_engine_path(engine_type);
270281
engines_[engine_type].dl =

cortex-cpp/utils/cpuid/cpu_info.cc

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
// Copyright (c) 2013 Steinwurf ApS
2+
// All Rights Reserved
3+
// Inspired by https://github.com/steinwurf/cpuid
4+
#include "platform.h"
5+
6+
#include "cpu_info.h"
7+
#include "detail/cpu_info_impl.h"
8+
9+
#if defined(PLATFORM_GCC_COMPATIBLE_X86)
10+
#include "detail/init_gcc_x86.h"
11+
#elif defined(PLATFORM_MSVC_X86) && !defined(PLATFORM_WINDOWS_PHONE)
12+
#include "detail/init_msvc_x86.h"
13+
#elif defined(PLATFORM_MSVC_ARM)
14+
#include "detail/init_msvc_arm.h"
15+
#elif defined(PLATFORM_CLANG_ARM) && defined(PLATFORM_IOS)
16+
#include "detail/init_ios_clang_arm.h"
17+
#elif defined(PLATFORM_GCC_COMPATIBLE_ARM) && defined(PLATFORM_LINUX)
18+
#include "detail/init_linux_gcc_arm.h"
19+
#else
20+
#include "detail/init_unknown.h"
21+
#endif
22+
23+
namespace cortex::cpuid {
24+
25+
CpuInfo::CpuInfo() : impl(new Impl()) {
26+
init_cpuinfo(*impl);
27+
}
28+
29+
CpuInfo::~CpuInfo() {}
30+
31+
// x86 member functions
32+
bool CpuInfo::has_fpu() const {
33+
return impl->has_fpu;
34+
}
35+
36+
bool CpuInfo::has_mmx() const {
37+
return impl->has_mmx;
38+
}
39+
40+
bool CpuInfo::has_sse() const {
41+
return impl->has_sse;
42+
}
43+
44+
bool CpuInfo::has_sse2() const {
45+
return impl->has_sse2;
46+
}
47+
48+
bool CpuInfo::has_sse3() const {
49+
return impl->has_sse3;
50+
}
51+
52+
bool CpuInfo::has_ssse3() const {
53+
return impl->has_ssse3;
54+
}
55+
56+
bool CpuInfo::has_sse4_1() const {
57+
return impl->has_sse4_1;
58+
}
59+
60+
bool CpuInfo::has_sse4_2() const {
61+
return impl->has_sse4_2;
62+
}
63+
64+
bool CpuInfo::has_pclmulqdq() const {
65+
return impl->has_pclmulqdq;
66+
}
67+
68+
bool CpuInfo::has_avx() const {
69+
return impl->has_avx;
70+
}
71+
72+
bool CpuInfo::has_avx2() const {
73+
return impl->has_avx2;
74+
}
75+
76+
bool CpuInfo::has_avx512_f() const {
77+
return impl->has_avx512_f;
78+
}
79+
80+
bool CpuInfo::has_avx512_dq() const {
81+
return impl->has_avx512_dq;
82+
}
83+
84+
bool CpuInfo::has_avx512_ifma() const {
85+
return impl->has_avx512_ifma;
86+
}
87+
88+
bool CpuInfo::has_avx512_pf() const {
89+
return impl->has_avx512_pf;
90+
}
91+
92+
bool CpuInfo::has_avx512_er() const {
93+
return impl->has_avx512_er;
94+
}
95+
96+
bool CpuInfo::has_avx512_cd() const {
97+
return impl->has_avx512_cd;
98+
}
99+
100+
bool CpuInfo::has_avx512_bw() const {
101+
return impl->has_avx512_bw;
102+
}
103+
104+
bool CpuInfo::has_avx512_vl() const {
105+
return impl->has_avx512_vl;
106+
}
107+
108+
bool CpuInfo::has_avx512_vbmi() const {
109+
return impl->has_avx512_vbmi;
110+
}
111+
112+
bool CpuInfo::has_avx512_vbmi2() const {
113+
return impl->has_avx512_vbmi2;
114+
}
115+
116+
bool CpuInfo::has_avx512_vnni() const {
117+
return impl->has_avx512_vnni;
118+
}
119+
120+
bool CpuInfo::has_avx512_bitalg() const {
121+
return impl->has_avx512_bitalg;
122+
}
123+
124+
bool CpuInfo::has_avx512_vpopcntdq() const {
125+
return impl->has_avx512_vpopcntdq;
126+
}
127+
128+
bool CpuInfo::has_avx512_4vnniw() const {
129+
return impl->has_avx512_4vnniw;
130+
}
131+
132+
bool CpuInfo::has_avx512_4fmaps() const {
133+
return impl->has_avx512_4fmaps;
134+
}
135+
136+
bool CpuInfo::has_avx512_vp2intersect() const {
137+
return impl->has_avx512_vp2intersect;
138+
}
139+
140+
bool CpuInfo::has_f16c() const {
141+
return impl->has_f16c;
142+
}
143+
144+
bool CpuInfo::has_aes() const {
145+
return impl->has_aes;
146+
}
147+
148+
// ARM member functions
149+
bool CpuInfo::has_neon() const {
150+
return impl->has_neon;
151+
}
152+
153+
std::string CpuInfo::to_string() {
154+
std::string s;
155+
auto get = [](bool flag) -> std::string {
156+
return flag ? "1" : "0";
157+
};
158+
s += "fpu = " + get(impl->has_fpu) + "| ";
159+
s += "mmx = " + get(impl->has_mmx) + "| ";
160+
s += "sse = " + get(impl->has_sse) + "| ";
161+
s += "sse2 = " + get(impl->has_sse2) + "| ";
162+
s += "sse3 = " + get(impl->has_sse3) + "| ";
163+
s += "ssse3 = " + get(impl->has_ssse3) + "| ";
164+
s += "sse4_1 = " + get(impl->has_sse4_1) + "| ";
165+
s += "sse4_2 = " + get(impl->has_sse4_2) + "| ";
166+
s += "pclmulqdq = " + get(impl->has_pclmulqdq) + "| ";
167+
s += "avx = " + get(impl->has_avx) + "| ";
168+
s += "avx2 = " + get(impl->has_avx2) + "| ";
169+
s += "avx512_f = " + get(impl->has_avx512_f) + "| ";
170+
s += "avx512_dq = " + get(impl->has_avx512_dq) + "| ";
171+
s += "avx512_ifma = " + get(impl->has_avx512_ifma) + "| ";
172+
s += "avx512_pf = " + get(impl->has_avx512_pf) + "| ";
173+
s += "avx512_er = " + get(impl->has_avx512_er) + "| ";
174+
s += "avx512_cd = " + get(impl->has_avx512_cd) + "| ";
175+
s += "avx512_bw = " + get(impl->has_avx512_bw) + "| ";
176+
s += "has_avx512_vl = " + get(impl->has_avx512_vl) + "| ";
177+
s += "has_avx512_vbmi = " + get(impl->has_avx512_vbmi) + "| ";
178+
s += "has_avx512_vbmi2 = " + get(impl->has_avx512_vbmi2) + "| ";
179+
s += "avx512_vnni = " + get(impl->has_avx512_vnni) + "| ";
180+
s += "avx512_bitalg = " + get(impl->has_avx512_bitalg) + "| ";
181+
s += "avx512_vpopcntdq = " + get(impl->has_avx512_vpopcntdq) + "| ";
182+
s += "avx512_4vnniw = " + get(impl->has_avx512_4vnniw) + "| ";
183+
s += "avx512_4fmaps = " + get(impl->has_avx512_4fmaps) + "| ";
184+
s += "avx512_vp2intersect = " + get(impl->has_avx512_vp2intersect) + "| ";
185+
s += "aes = " + get(impl->has_aes) + "| ";
186+
s += "f16c = " + get(impl->has_f16c) + "|";
187+
return s;
188+
}
189+
190+
} // namespace cpuid

cortex-cpp/utils/cpuid/cpu_info.h

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright (c) 2013 Steinwurf ApS
2+
// All Rights Reserved
3+
// Inspired by https://github.com/steinwurf/cpuid
4+
#pragma once
5+
6+
#include <memory>
7+
#include <string>
8+
9+
namespace cortex::cpuid {
10+
/// The CpuInfo object extract information about which, if any, additional
11+
/// instructions are supported by the CPU.
12+
class CpuInfo {
13+
public:
14+
/// Constructor for feature detection with default values
15+
CpuInfo();
16+
17+
/// Destructor
18+
~CpuInfo();
19+
20+
/// Return true if the CPU supports x87 Floating-Point Unit
21+
bool has_fpu() const;
22+
23+
/// Return true if the CPU supports MMX
24+
bool has_mmx() const;
25+
26+
/// Return true if the CPU supports Streaming SIMD Extensions
27+
bool has_sse() const;
28+
29+
/// Return true if the CPU supports Streaming SIMD Extensions 2
30+
bool has_sse2() const;
31+
32+
/// Return true if the CPU supports Streaming SIMD Extensions 3
33+
bool has_sse3() const;
34+
35+
/// Return true if the CPU supports Supplemental Streaming SIMD Extensions 3
36+
bool has_ssse3() const;
37+
38+
/// Return true if the CPU supports Streaming SIMD Extensions 4.1
39+
bool has_sse4_1() const;
40+
41+
/// Return true if the CPU supports Streaming SIMD Extensions 4.2
42+
bool has_sse4_2() const;
43+
44+
/// Return true if the CPU supports carry-less multiplication of two 64-bit
45+
/// polynomials over the finite field GF(2)
46+
bool has_pclmulqdq() const;
47+
48+
/// Return true if the CPU supports Advanced Vector Extensions
49+
bool has_avx() const;
50+
51+
/// Return true if the CPU supports Advanced Vector Extensions 2
52+
bool has_avx2() const;
53+
54+
/// Return true if the CPU supports AVX-512 Foundation
55+
bool has_avx512_f() const;
56+
57+
/// Return true if the CPU supports AVX-512 Doubleword and Quadword
58+
/// Instructions
59+
bool has_avx512_dq() const;
60+
61+
/// Return true if the CPU supports AVX-512 Integer Fused Multiply Add
62+
bool has_avx512_ifma() const;
63+
64+
/// Return true if the CPU supports AVX-512 Prefetch Instructions
65+
bool has_avx512_pf() const;
66+
67+
/// Return true if the CPU supports AVX-512 Exponential and Reciprocal
68+
/// Instructions
69+
bool has_avx512_er() const;
70+
71+
/// Return true if the CPU supports AVX-512 Conflict Detection Instructions
72+
bool has_avx512_cd() const;
73+
74+
/// Return true if the CPU supports AVX-512 Byte and Word Instructions
75+
bool has_avx512_bw() const;
76+
77+
/// Return true if the CPU supports AVX-512 Vector Length Extensions
78+
bool has_avx512_vl() const;
79+
80+
/// Return true if the CPU supports AVX-512 Vector Byte Manipulation
81+
/// Instructions
82+
bool has_avx512_vbmi() const;
83+
84+
/// Return true if the CPU supports AVX-512 Vector Byte Manipulation
85+
/// Instructions 2
86+
bool has_avx512_vbmi2() const;
87+
88+
/// Return true if the CPU supports AVX-512 Vector Neural Network
89+
/// Instructions
90+
bool has_avx512_vnni() const;
91+
92+
/// Return true if the CPU supports AVX-512 Bit Algorithms
93+
bool has_avx512_bitalg() const;
94+
95+
/// Return true if the CPU supports Vector population count instruction
96+
bool has_avx512_vpopcntdq() const;
97+
98+
/// Return true if the CPU supports AVX-512 Vector Neural Network
99+
/// Instructions Word variable precision
100+
bool has_avx512_4vnniw() const;
101+
102+
/// Return true if the CPU supports AVX-512 Fused Multiply Accumulation
103+
/// Packed Single precision
104+
bool has_avx512_4fmaps() const;
105+
106+
/// Return true if the CPU supports AVX-512 Vector Pair Intersection to a
107+
/// Pair of Mask Registers
108+
bool has_avx512_vp2intersect() const;
109+
110+
/// Return true if the CPU supports converting between half-precision and
111+
/// standard IEEE single-precision floating-point formats
112+
bool has_f16c() const;
113+
114+
/// Return true if the CPU supports Advanced Encryption Standard instruction
115+
/// set
116+
bool has_aes() const;
117+
118+
/// Return true if the CPU supports ARM Advanced SIMD
119+
bool has_neon() const;
120+
121+
std::string to_string();
122+
123+
public:
124+
/// Private implementation
125+
struct Impl;
126+
127+
private:
128+
/// Pimpl pointer
129+
std::unique_ptr<Impl> impl;
130+
};
131+
} // namespace cortex::cpuid

0 commit comments

Comments
 (0)