Skip to content

Commit fa1c679

Browse files
authored
More robust FreeBSD topology detection (#249)
Possibly fix #248
1 parent 4611eb9 commit fa1c679

File tree

3 files changed

+35
-21
lines changed

3 files changed

+35
-21
lines changed

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ cpuinfo is a library to detect essential for performance optimization informatio
99
## Features
1010

1111
- **Cross-platform** availability:
12-
- Linux, Windows, macOS, Android, and iOS operating systems
12+
- Linux, Windows, macOS, Android, iOS and FreeBSD operating systems
1313
- x86, x86-64, ARM, and ARM64 architectures
1414
- Modern **C/C++ interface**
1515
- Thread-safe
@@ -258,6 +258,8 @@ LDFLAGS+= $(pkg-config --libs libcpuinfo)
258258
- [x] x86
259259
- [x] x86-64
260260
- [x] arm64
261+
- [x] FreeBSD
262+
- [x] x86-64
261263

262264
## Methods
263265

src/freebsd/topology.c

+11-15
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ static char* sysctl_str(const char* name) {
2424
size_t value_size = 0;
2525
if (sysctlbyname(name, NULL, &value_size, NULL, 0) != 0) {
2626
cpuinfo_log_error("sysctlbyname(\"%s\") failed: %s", name, strerror(errno));
27+
return NULL;
2728
} else if (value_size <= 0) {
2829
cpuinfo_log_error("sysctlbyname(\"%s\") returned invalid value size %zu", name, value_size);
30+
return NULL;
2931
}
3032
value_size += 1;
3133
char* value = calloc(value_size, 1);
@@ -52,29 +54,22 @@ struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void) {
5254
if (!topology_spec) {
5355
return topology;
5456
}
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\"";
57+
const char* group_tags[] = {"<group level=\"2\" cache-level=\"0\">", "<group level=\"1\" "};
58+
for (size_t i = 0; i < sizeof(group_tags) / sizeof(group_tags[0]); i++) {
59+
const char* group_tag = group_tags[i];
6960
char* p = strstr(topology_spec, group_tag);
7061
while (p) {
7162
topology.packages += 1;
7263
p++;
7364
p = strstr(p, group_tag);
7465
}
66+
if (topology.packages > 0) {
67+
break;
68+
}
7569
}
70+
7671
if (topology.packages == 0) {
77-
cpuinfo_log_error("failed to parse topology_spec:%s", topology_spec);
72+
cpuinfo_log_error("failed to parse topology_spec: %s", topology_spec);
7873
free(topology_spec);
7974
goto fail;
8075
}
@@ -84,6 +79,7 @@ struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void) {
8479
goto fail;
8580
}
8681
if (topology.cores < topology.packages) {
82+
cpuinfo_log_error("invalid numbers of package and core: %d %d", topology.packages, topology.cores);
8783
goto fail;
8884
}
8985
topology.threads_per_core = sysctl_int("kern.smp.threads_per_core");

src/x86/freebsd/init.c

+21-5
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ void cpuinfo_x86_freebsd_init(void) {
135135
if (x86_processor.cache.l1i.size != 0 || x86_processor.cache.l1d.size != 0) {
136136
/* Assume that threads on the same core share L1 */
137137
threads_per_l1 = freebsd_topology.threads / freebsd_topology.cores;
138+
if (threads_per_l1 == 0) {
139+
cpuinfo_log_error("failed to detect threads_per_l1");
140+
goto cleanup;
141+
}
138142
cpuinfo_log_warning(
139143
"freebsd kernel did not report number of "
140144
"threads sharing L1 cache; assume %" PRIu32,
@@ -154,6 +158,10 @@ void cpuinfo_x86_freebsd_init(void) {
154158
* the same package share L2 */
155159
threads_per_l2 = freebsd_topology.threads / freebsd_topology.packages;
156160
}
161+
if (threads_per_l2 == 0) {
162+
cpuinfo_log_error("failed to detect threads_per_l1");
163+
goto cleanup;
164+
}
157165
cpuinfo_log_warning(
158166
"freebsd kernel did not report number of "
159167
"threads sharing L2 cache; assume %" PRIu32,
@@ -170,6 +178,10 @@ void cpuinfo_x86_freebsd_init(void) {
170178
* may be L4 cache as well)
171179
*/
172180
threads_per_l3 = freebsd_topology.threads / freebsd_topology.packages;
181+
if (threads_per_l3 == 0) {
182+
cpuinfo_log_error("failed to detect threads_per_l3");
183+
goto cleanup;
184+
}
173185
cpuinfo_log_warning(
174186
"freebsd kernel did not report number of "
175187
"threads sharing L3 cache; assume %" PRIu32,
@@ -187,6 +199,10 @@ void cpuinfo_x86_freebsd_init(void) {
187199
* shared L4 (like on IBM POWER8).
188200
*/
189201
threads_per_l4 = freebsd_topology.threads;
202+
if (threads_per_l4 == 0) {
203+
cpuinfo_log_error("failed to detect threads_per_l4");
204+
goto cleanup;
205+
}
190206
cpuinfo_log_warning(
191207
"freebsd kernel did not report number of "
192208
"threads sharing L4 cache; assume %" PRIu32,
@@ -203,7 +219,7 @@ void cpuinfo_x86_freebsd_init(void) {
203219
"%" PRIu32 " L1I caches",
204220
l1_count * sizeof(struct cpuinfo_cache),
205221
l1_count);
206-
return;
222+
goto cleanup;
207223
}
208224
for (uint32_t c = 0; c < l1_count; c++) {
209225
l1i[c] = (struct cpuinfo_cache){
@@ -230,7 +246,7 @@ void cpuinfo_x86_freebsd_init(void) {
230246
"%" PRIu32 " L1D caches",
231247
l1_count * sizeof(struct cpuinfo_cache),
232248
l1_count);
233-
return;
249+
goto cleanup;
234250
}
235251
for (uint32_t c = 0; c < l1_count; c++) {
236252
l1d[c] = (struct cpuinfo_cache){
@@ -257,7 +273,7 @@ void cpuinfo_x86_freebsd_init(void) {
257273
"%" PRIu32 " L2 caches",
258274
l2_count * sizeof(struct cpuinfo_cache),
259275
l2_count);
260-
return;
276+
goto cleanup;
261277
}
262278
for (uint32_t c = 0; c < l2_count; c++) {
263279
l2[c] = (struct cpuinfo_cache){
@@ -284,7 +300,7 @@ void cpuinfo_x86_freebsd_init(void) {
284300
"%" PRIu32 " L3 caches",
285301
l3_count * sizeof(struct cpuinfo_cache),
286302
l3_count);
287-
return;
303+
goto cleanup;
288304
}
289305
for (uint32_t c = 0; c < l3_count; c++) {
290306
l3[c] = (struct cpuinfo_cache){
@@ -311,7 +327,7 @@ void cpuinfo_x86_freebsd_init(void) {
311327
"%" PRIu32 " L4 caches",
312328
l4_count * sizeof(struct cpuinfo_cache),
313329
l4_count);
314-
return;
330+
goto cleanup;
315331
}
316332
for (uint32_t c = 0; c < l4_count; c++) {
317333
l4[c] = (struct cpuinfo_cache){

0 commit comments

Comments
 (0)