Skip to content

Commit 05332fd

Browse files
authored
add FreeBSD support (#172)
1 parent 3c8b153 commit 05332fd

File tree

7 files changed

+530
-2
lines changed

7 files changed

+530
-2
lines changed

BUILD.bazel

+17
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ MACH_SRCS = [
6363
"src/mach/topology.c",
6464
]
6565

66+
FREEBSD_SRCS = [
67+
"src/freebsd/topology.c",
68+
]
69+
6670
EMSCRIPTEN_SRCS = [
6771
"src/emscripten/init.c",
6872
]
@@ -112,6 +116,10 @@ MACH_ARM_SRCS = [
112116
"src/arm/mach/init.c",
113117
]
114118

119+
FREEBSD_X86_SRCS = [
120+
"src/x86/freebsd/init.c",
121+
]
122+
115123
EMSCRIPTEN_SRCS = [
116124
"src/emscripten/init.c",
117125
]
@@ -132,6 +140,7 @@ cc_library(
132140
":macos_x86_64": COMMON_SRCS + X86_SRCS + MACH_SRCS + MACH_X86_SRCS,
133141
":macos_x86_64_legacy": COMMON_SRCS + X86_SRCS + MACH_SRCS + MACH_X86_SRCS,
134142
":macos_arm64": COMMON_SRCS + MACH_SRCS + MACH_ARM_SRCS,
143+
":freebsd_x86_64": COMMON_SRCS + X86_SRCS + FREEBSD_SRCS + FREEBSD_X86_SRCS,
135144
":windows_x86_64": COMMON_SRCS + X86_SRCS + WINDOWS_X86_SRCS,
136145
":windows_arm64": COMMON_SRCS + ARM_SRCS + WINDOWS_ARM_SRCS,
137146
":android_armv7": COMMON_SRCS + ARM_SRCS + LINUX_SRCS + LINUX_ARM32_SRCS + ANDROID_ARM_SRCS,
@@ -175,6 +184,7 @@ cc_library(
175184
# Headers must be in textual_hdrs to allow us to set the standard to C99
176185
textual_hdrs = [
177186
"include/cpuinfo.h",
187+
"src/freebsd/api.h",
178188
"src/linux/api.h",
179189
"src/mach/api.h",
180190
"src/cpuinfo/common.h",
@@ -463,3 +473,10 @@ config_setting(
463473
"cpu": "asmjs",
464474
},
465475
)
476+
477+
config_setting(
478+
name = "freebsd_x86_64",
479+
values = {
480+
"cpu": "freebsd",
481+
},
482+
)

CMakeLists.txt

+12-2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ ENDIF()
6767

6868
# -- [ Determine target processor
6969
SET(CPUINFO_TARGET_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}")
70+
IF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD" AND CPUINFO_TARGET_PROCESSOR STREQUAL "amd64")
71+
SET(CPUINFO_TARGET_PROCESSOR "AMD64")
72+
ENDIF()
7073
IF(IS_APPLE_OS AND CMAKE_OSX_ARCHITECTURES MATCHES "^(x86_64|arm64.*)$")
7174
SET(CPUINFO_TARGET_PROCESSOR "${CMAKE_OSX_ARCHITECTURES}")
7275
ELSEIF(CMAKE_GENERATOR MATCHES "^Visual Studio " AND CMAKE_VS_PLATFORM_NAME)
@@ -105,7 +108,7 @@ IF(NOT CMAKE_SYSTEM_NAME)
105108
"Target operating system is not specified. "
106109
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
107110
SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
108-
ELSEIF(NOT CMAKE_SYSTEM_NAME MATCHES "^(Windows|WindowsStore|CYGWIN|MSYS|Darwin|Linux|Android)$")
111+
ELSEIF(NOT CMAKE_SYSTEM_NAME MATCHES "^(Windows|WindowsStore|CYGWIN|MSYS|Darwin|Linux|Android|FreeBSD)$")
109112
IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14" AND NOT IS_APPLE_OS)
110113
MESSAGE(WARNING
111114
"Target operating system \"${CMAKE_SYSTEM_NAME}\" is not supported in cpuinfo. "
@@ -178,6 +181,8 @@ IF(CPUINFO_SUPPORTED_PLATFORM)
178181
LIST(APPEND CPUINFO_SRCS src/x86/mach/init.c)
179182
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "^(Windows|WindowsStore|CYGWIN|MSYS)$")
180183
LIST(APPEND CPUINFO_SRCS src/x86/windows/init.c)
184+
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
185+
LIST(APPEND CPUINFO_SRCS src/x86/freebsd/init.c)
181186
ENDIF()
182187
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "^Windows" AND CPUINFO_TARGET_PROCESSOR MATCHES "^(ARM64|arm64)$")
183188
LIST(APPEND CPUINFO_SRCS
@@ -234,9 +239,11 @@ IF(CPUINFO_SUPPORTED_PLATFORM)
234239
src/linux/processors.c)
235240
ELSEIF(IS_APPLE_OS)
236241
LIST(APPEND CPUINFO_SRCS src/mach/topology.c)
242+
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
243+
LIST(APPEND CPUINFO_SRCS src/freebsd/topology.c)
237244
ENDIF()
238245

239-
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
246+
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
240247
SET(CMAKE_THREAD_PREFER_PTHREAD TRUE)
241248
SET(THREADS_PREFER_PTHREAD_FLAG TRUE)
242249
FIND_PACKAGE(Threads REQUIRED)
@@ -301,6 +308,9 @@ IF(CPUINFO_SUPPORTED_PLATFORM)
301308
TARGET_LINK_LIBRARIES(cpuinfo_internals PUBLIC ${CMAKE_THREAD_LIBS_INIT})
302309
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE _GNU_SOURCE=1)
303310
TARGET_COMPILE_DEFINITIONS(cpuinfo_internals PRIVATE _GNU_SOURCE=1)
311+
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
312+
TARGET_LINK_LIBRARIES(cpuinfo PUBLIC ${CMAKE_THREAD_LIBS_INIT})
313+
TARGET_LINK_LIBRARIES(cpuinfo_internals PUBLIC ${CMAKE_THREAD_LIBS_INIT})
304314
ENDIF()
305315
ELSE()
306316
TARGET_COMPILE_DEFINITIONS(cpuinfo INTERFACE CPUINFO_SUPPORTED_PLATFORM=0)

src/cpuinfo/internal-api.h

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ extern CPUINFO_INTERNAL const struct cpuinfo_core** cpuinfo_linux_cpu_to_core_ma
4949

5050
CPUINFO_PRIVATE void cpuinfo_x86_mach_init(void);
5151
CPUINFO_PRIVATE void cpuinfo_x86_linux_init(void);
52+
CPUINFO_PRIVATE void cpuinfo_x86_freebsd_init(void);
5253
#if defined(_WIN32) || defined(__CYGWIN__)
5354
#if CPUINFO_ARCH_ARM64
5455
CPUINFO_PRIVATE BOOL CALLBACK cpuinfo_arm_windows_init(PINIT_ONCE init_once, PVOID parameter, PVOID* context);

src/freebsd/api.h

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
5+
struct cpuinfo_freebsd_topology {
6+
uint32_t packages;
7+
uint32_t cores;
8+
uint32_t threads;
9+
uint32_t threads_per_core;
10+
};
11+
12+
struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void);

src/freebsd/topology.c

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include <errno.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
#include <sys/sysctl.h>
6+
#include <sys/types.h>
7+
8+
#include <cpuinfo/log.h>
9+
#include <freebsd/api.h>
10+
11+
static int sysctl_int(const char* name) {
12+
int value = 0;
13+
size_t value_size = sizeof(value);
14+
if (sysctlbyname(name, &value, &value_size, NULL, 0) != 0) {
15+
cpuinfo_log_error("sysctlbyname(\"%s\") failed: %s", name, strerror(errno));
16+
} else if (value <= 0) {
17+
cpuinfo_log_error("sysctlbyname(\"%s\") returned invalid value %d %zu", name, value, value_size);
18+
value = 0;
19+
}
20+
return value;
21+
}
22+
23+
static char* sysctl_str(const char* name) {
24+
size_t value_size = 0;
25+
if (sysctlbyname(name, NULL, &value_size, NULL, 0) != 0) {
26+
cpuinfo_log_error("sysctlbyname(\"%s\") failed: %s", name, strerror(errno));
27+
} else if (value_size <= 0) {
28+
cpuinfo_log_error("sysctlbyname(\"%s\") returned invalid value size %zu", name, value_size);
29+
}
30+
value_size += 1;
31+
char* value = calloc(value_size, 1);
32+
if (!value) {
33+
cpuinfo_log_error("calloc %zu bytes failed", value_size);
34+
return NULL;
35+
}
36+
if (sysctlbyname(name, value, &value_size, NULL, 0) != 0) {
37+
cpuinfo_log_error("sysctlbyname(\"%s\") failed: %s", name, strerror(errno));
38+
free(value);
39+
return NULL;
40+
}
41+
return value;
42+
}
43+
44+
struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void) {
45+
struct cpuinfo_freebsd_topology topology = {
46+
.packages = 0,
47+
.cores = 0,
48+
.threads_per_core = 0,
49+
.threads = 0,
50+
};
51+
char* topology_spec = sysctl_str("kern.sched.topology_spec");
52+
if (!topology_spec) {
53+
return topology;
54+
}
55+
const char* group_tag = "<group level=\"1\" cache-level=\"0\">";
56+
char* p = strstr(topology_spec, group_tag);
57+
while (p) {
58+
const char* cpu_tag = "cpu count=\"";
59+
char* q = strstr(p, cpu_tag);
60+
if (q) {
61+
p = q + strlen(cpu_tag);
62+
topology.packages += atoi(p);
63+
} else {
64+
break;
65+
}
66+
}
67+
if (topology.packages == 0) {
68+
const char* group_tag = "<group level=\"1\"";
69+
char* p = strstr(topology_spec, group_tag);
70+
while (p) {
71+
topology.packages += 1;
72+
p++;
73+
p = strstr(p, group_tag);
74+
}
75+
}
76+
if (topology.packages == 0) {
77+
cpuinfo_log_error("failed to parse topology_spec:%s", topology_spec);
78+
free(topology_spec);
79+
goto fail;
80+
}
81+
free(topology_spec);
82+
topology.cores = sysctl_int("kern.smp.cores");
83+
if (topology.cores == 0) {
84+
goto fail;
85+
}
86+
if (topology.cores < topology.packages) {
87+
goto fail;
88+
}
89+
topology.threads_per_core = sysctl_int("kern.smp.threads_per_core");
90+
if (topology.threads_per_core == 0) {
91+
goto fail;
92+
}
93+
cpuinfo_log_debug(
94+
"freebsd topology: packages = %d, cores = %d, "
95+
"threads_per_core = %d",
96+
topology.packages,
97+
topology.cores,
98+
topology.threads_per_core);
99+
topology.threads = topology.threads_per_core * topology.cores;
100+
return topology;
101+
fail:
102+
topology.packages = 0;
103+
return topology;
104+
}

src/init.c

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ bool CPUINFO_ABI cpuinfo_initialize(void) {
2424
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
2525
#if defined(__MACH__) && defined(__APPLE__)
2626
pthread_once(&init_guard, &cpuinfo_x86_mach_init);
27+
#elif defined(__FreeBSD__)
28+
pthread_once(&init_guard, &cpuinfo_x86_freebsd_init);
2729
#elif defined(__linux__)
2830
pthread_once(&init_guard, &cpuinfo_x86_linux_init);
2931
#elif defined(_WIN32) || defined(__CYGWIN__)

0 commit comments

Comments
 (0)