Skip to content

Commit 9b39ea3

Browse files
committed
Add FreeBSD support
1 parent f42f5ea commit 9b39ea3

File tree

7 files changed

+556
-2
lines changed

7 files changed

+556
-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(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

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

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)