More robust FreeBSD topology detection (#249)
Possibly fix #248
diff --git a/README.md b/README.md
index 82cadea..ec05f53 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
## Features
- **Cross-platform** availability:
- - Linux, Windows, macOS, Android, and iOS operating systems
+ - Linux, Windows, macOS, Android, iOS and FreeBSD operating systems
- x86, x86-64, ARM, and ARM64 architectures
- Modern **C/C++ interface**
- Thread-safe
@@ -258,6 +258,8 @@
- [x] x86
- [x] x86-64
- [x] arm64
+- [x] FreeBSD
+ - [x] x86-64
## Methods
diff --git a/src/freebsd/topology.c b/src/freebsd/topology.c
index da941e9..675a81f 100644
--- a/src/freebsd/topology.c
+++ b/src/freebsd/topology.c
@@ -24,8 +24,10 @@
size_t value_size = 0;
if (sysctlbyname(name, NULL, &value_size, NULL, 0) != 0) {
cpuinfo_log_error("sysctlbyname(\"%s\") failed: %s", name, strerror(errno));
+ return NULL;
} else if (value_size <= 0) {
cpuinfo_log_error("sysctlbyname(\"%s\") returned invalid value size %zu", name, value_size);
+ return NULL;
}
value_size += 1;
char* value = calloc(value_size, 1);
@@ -52,29 +54,22 @@
if (!topology_spec) {
return topology;
}
- const char* group_tag = "<group level=\"1\" cache-level=\"0\">";
- char* p = strstr(topology_spec, group_tag);
- while (p) {
- const char* cpu_tag = "cpu count=\"";
- char* q = strstr(p, cpu_tag);
- if (q) {
- p = q + strlen(cpu_tag);
- topology.packages += atoi(p);
- } else {
- break;
- }
- }
- if (topology.packages == 0) {
- const char* group_tag = "<group level=\"1\"";
+ const char* group_tags[] = {"<group level=\"2\" cache-level=\"0\">", "<group level=\"1\" "};
+ for (size_t i = 0; i < sizeof(group_tags) / sizeof(group_tags[0]); i++) {
+ const char* group_tag = group_tags[i];
char* p = strstr(topology_spec, group_tag);
while (p) {
topology.packages += 1;
p++;
p = strstr(p, group_tag);
}
+ if (topology.packages > 0) {
+ break;
+ }
}
+
if (topology.packages == 0) {
- cpuinfo_log_error("failed to parse topology_spec:%s", topology_spec);
+ cpuinfo_log_error("failed to parse topology_spec: %s", topology_spec);
free(topology_spec);
goto fail;
}
@@ -84,6 +79,7 @@
goto fail;
}
if (topology.cores < topology.packages) {
+ cpuinfo_log_error("invalid numbers of package and core: %d %d", topology.packages, topology.cores);
goto fail;
}
topology.threads_per_core = sysctl_int("kern.smp.threads_per_core");
diff --git a/src/x86/freebsd/init.c b/src/x86/freebsd/init.c
index c6c6d75..797fa24 100644
--- a/src/x86/freebsd/init.c
+++ b/src/x86/freebsd/init.c
@@ -135,6 +135,10 @@
if (x86_processor.cache.l1i.size != 0 || x86_processor.cache.l1d.size != 0) {
/* Assume that threads on the same core share L1 */
threads_per_l1 = freebsd_topology.threads / freebsd_topology.cores;
+ if (threads_per_l1 == 0) {
+ cpuinfo_log_error("failed to detect threads_per_l1");
+ goto cleanup;
+ }
cpuinfo_log_warning(
"freebsd kernel did not report number of "
"threads sharing L1 cache; assume %" PRIu32,
@@ -154,6 +158,10 @@
* the same package share L2 */
threads_per_l2 = freebsd_topology.threads / freebsd_topology.packages;
}
+ if (threads_per_l2 == 0) {
+ cpuinfo_log_error("failed to detect threads_per_l1");
+ goto cleanup;
+ }
cpuinfo_log_warning(
"freebsd kernel did not report number of "
"threads sharing L2 cache; assume %" PRIu32,
@@ -170,6 +178,10 @@
* may be L4 cache as well)
*/
threads_per_l3 = freebsd_topology.threads / freebsd_topology.packages;
+ if (threads_per_l3 == 0) {
+ cpuinfo_log_error("failed to detect threads_per_l3");
+ goto cleanup;
+ }
cpuinfo_log_warning(
"freebsd kernel did not report number of "
"threads sharing L3 cache; assume %" PRIu32,
@@ -187,6 +199,10 @@
* shared L4 (like on IBM POWER8).
*/
threads_per_l4 = freebsd_topology.threads;
+ if (threads_per_l4 == 0) {
+ cpuinfo_log_error("failed to detect threads_per_l4");
+ goto cleanup;
+ }
cpuinfo_log_warning(
"freebsd kernel did not report number of "
"threads sharing L4 cache; assume %" PRIu32,
@@ -203,7 +219,7 @@
"%" PRIu32 " L1I caches",
l1_count * sizeof(struct cpuinfo_cache),
l1_count);
- return;
+ goto cleanup;
}
for (uint32_t c = 0; c < l1_count; c++) {
l1i[c] = (struct cpuinfo_cache){
@@ -230,7 +246,7 @@
"%" PRIu32 " L1D caches",
l1_count * sizeof(struct cpuinfo_cache),
l1_count);
- return;
+ goto cleanup;
}
for (uint32_t c = 0; c < l1_count; c++) {
l1d[c] = (struct cpuinfo_cache){
@@ -257,7 +273,7 @@
"%" PRIu32 " L2 caches",
l2_count * sizeof(struct cpuinfo_cache),
l2_count);
- return;
+ goto cleanup;
}
for (uint32_t c = 0; c < l2_count; c++) {
l2[c] = (struct cpuinfo_cache){
@@ -284,7 +300,7 @@
"%" PRIu32 " L3 caches",
l3_count * sizeof(struct cpuinfo_cache),
l3_count);
- return;
+ goto cleanup;
}
for (uint32_t c = 0; c < l3_count; c++) {
l3[c] = (struct cpuinfo_cache){
@@ -311,7 +327,7 @@
"%" PRIu32 " L4 caches",
l4_count * sizeof(struct cpuinfo_cache),
l4_count);
- return;
+ goto cleanup;
}
for (uint32_t c = 0; c < l4_count; c++) {
l4[c] = (struct cpuinfo_cache){