Skip to content

Commit 38bd8cf

Browse files
committed
change sysctl of cpuinfo
1 parent cb64777 commit 38bd8cf

File tree

3 files changed

+107
-66
lines changed

3 files changed

+107
-66
lines changed

src/freebsd/api.h

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
#include <stdint.h>
44

5-
65
struct cpuinfo_freebsd_topology {
7-
uint32_t packages;
8-
uint32_t cores;
9-
uint32_t threads;
6+
uint32_t packages;
7+
uint32_t cores;
8+
uint32_t threads;
9+
uint32_t threads_per_core;
1010
};
1111

12-
1312
struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void);

src/freebsd/topology.c

+66-20
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,79 @@
1-
#include <string.h>
2-
#include <stdlib.h>
31
#include <errno.h>
2+
#include <stdlib.h>
3+
#include <string.h>
44

55
#include <sys/types.h>
66
#include <sys/sysctl.h>
77

88
#include <cpuinfo/log.h>
99
#include <freebsd/api.h>
1010

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",
18+
name, value, value_size);
19+
}
20+
return value;
21+
}
1122

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",
29+
name, value_size);
30+
}
31+
char *value = malloc(value_size + 1);
32+
if (!value) {
33+
cpuinfo_log_error("malloc %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+
}
1243

1344
struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void) {
14-
int threads = 1;
15-
size_t sizeof_threads = sizeof(threads);
16-
if (sysctlbyname("hw.ncpu", &threads, &sizeof_threads, NULL, 0) != 0) {
17-
cpuinfo_log_error("sysctlbyname(\"hw.ncpu\") failed: %s", strerror(errno));
18-
} else if (threads <= 0) {
19-
cpuinfo_log_error("sysctlbyname(\"hw.ncpu\") returned invalid value %d", threads);
20-
}
21-
22-
int cores = threads / 2;
23-
int packages = 1;
24-
25-
cpuinfo_log_debug("freebsd topology: packages = %d, cores = %d, threads = %d", packages, (int) cores, (int) threads);
26-
struct cpuinfo_freebsd_topology topology = {
27-
.packages = (uint32_t) packages,
28-
.cores = (uint32_t) cores,
29-
.threads = (uint32_t) threads
30-
};
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 *package_key = "<group level=\"1\"";
56+
char *p = strstr(topology_spec, package_key);
57+
while (p) {
58+
topology.packages += 1;
59+
p++;
60+
p = strstr(p, package_key);
61+
}
62+
free(topology_spec);
3163

32-
return topology;
64+
topology.cores = sysctl_int("kern.smp.cores");
65+
if (topology.cores <= 0) {
66+
topology.packages = 0;
67+
return topology;
68+
}
69+
topology.threads_per_core = sysctl_int("kern.smp.threads_per_core");
70+
if (topology.threads_per_core <= 0) {
71+
topology.packages = 0;
72+
return topology;
73+
}
74+
cpuinfo_log_debug(
75+
"freebsd topology: packages = %d, cores = %d, threads_per_core = %d",
76+
topology.packages, topology.cores, topology.threads_per_core);
77+
topology.threads = topology.threads_per_core * topology.cores;
78+
return topology;
3379
}

src/x86/freebsd/init.c

+37-41
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,32 @@ void cpuinfo_x86_freebsd_init(void) {
2929
struct cpuinfo_cache* l4 = NULL;
3030

3131
struct cpuinfo_freebsd_topology freebsd_topology = cpuinfo_freebsd_detect_topology();
32+
if (freebsd_topology.packages == 0) {
33+
cpuinfo_log_error("failed to detect topology");
34+
goto cleanup;
35+
}
3236
processors = calloc(freebsd_topology.threads, sizeof(struct cpuinfo_processor));
3337
if (processors == NULL) {
34-
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" logical processors",
38+
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" logical processors",
3539
freebsd_topology.threads * sizeof(struct cpuinfo_processor), freebsd_topology.threads);
3640
goto cleanup;
3741
}
3842
cores = calloc(freebsd_topology.cores, sizeof(struct cpuinfo_core));
3943
if (cores == NULL) {
40-
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" cores",
44+
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" cores",
4145
freebsd_topology.cores * sizeof(struct cpuinfo_core), freebsd_topology.cores);
4246
goto cleanup;
4347
}
4448
/* On x86 cluster of cores is a physical package */
4549
clusters = calloc(freebsd_topology.packages, sizeof(struct cpuinfo_cluster));
4650
if (clusters == NULL) {
47-
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" core clusters",
51+
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" core clusters",
4852
freebsd_topology.packages * sizeof(struct cpuinfo_cluster), freebsd_topology.packages);
4953
goto cleanup;
5054
}
5155
packages = calloc(freebsd_topology.packages, sizeof(struct cpuinfo_package));
5256
if (packages == NULL) {
53-
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" physical packages",
57+
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" physical packages",
5458
freebsd_topology.packages * sizeof(struct cpuinfo_package), freebsd_topology.packages);
5559
goto cleanup;
5660
}
@@ -61,7 +65,7 @@ void cpuinfo_x86_freebsd_init(void) {
6165
char brand_string[48];
6266
cpuinfo_x86_normalize_brand_string(x86_processor.brand_string, brand_string);
6367

64-
const uint32_t threads_per_core = freebsd_topology.threads / freebsd_topology.cores;
68+
const uint32_t threads_per_core = freebsd_topology.threads_per_core;
6569
const uint32_t threads_per_package = freebsd_topology.threads / freebsd_topology.packages;
6670
const uint32_t cores_per_package = freebsd_topology.cores / freebsd_topology.packages;
6771
for (uint32_t i = 0; i < freebsd_topology.packages; i++) {
@@ -122,60 +126,52 @@ void cpuinfo_x86_freebsd_init(void) {
122126

123127
uint32_t threads_per_l1 = 0, l1_count = 0;
124128
if (x86_processor.cache.l1i.size != 0 || x86_processor.cache.l1d.size != 0) {
125-
if (threads_per_l1 == 0) {
126-
/* Assume that threads on the same core share L1 */
127-
threads_per_l1 = freebsd_topology.threads / freebsd_topology.cores;
128-
cpuinfo_log_warning("freebsd kernel did not report number of threads sharing L1 cache; assume %"PRIu32,
129-
threads_per_l1);
130-
}
129+
/* Assume that threads on the same core share L1 */
130+
threads_per_l1 = freebsd_topology.threads / freebsd_topology.cores;
131+
cpuinfo_log_warning("freebsd kernel did not report number of threads sharing L1 cache; assume %"PRIu32,
132+
threads_per_l1);
131133
l1_count = freebsd_topology.threads / threads_per_l1;
132134
cpuinfo_log_debug("detected %"PRIu32" L1 caches", l1_count);
133135
}
134136

135137
uint32_t threads_per_l2 = 0, l2_count = 0;
136138
if (x86_processor.cache.l2.size != 0) {
137-
if (threads_per_l2 == 0) {
138-
if (x86_processor.cache.l3.size != 0) {
139-
/* This is not a last-level cache; assume that threads on the same core share L2 */
140-
threads_per_l2 = freebsd_topology.threads / freebsd_topology.cores;
141-
} else {
142-
/* This is a last-level cache; assume that threads on the same package share L2 */
143-
threads_per_l2 = freebsd_topology.threads / freebsd_topology.packages;
144-
}
145-
cpuinfo_log_warning("freebsd kernel did not report number of threads sharing L2 cache; assume %"PRIu32,
146-
threads_per_l2);
147-
}
139+
if (x86_processor.cache.l3.size != 0) {
140+
/* This is not a last-level cache; assume that threads on the same core share L2 */
141+
threads_per_l2 = freebsd_topology.threads / freebsd_topology.cores;
142+
} else {
143+
/* This is a last-level cache; assume that threads on the same package share L2 */
144+
threads_per_l2 = freebsd_topology.threads / freebsd_topology.packages;
145+
}
146+
cpuinfo_log_warning("freebsd kernel did not report number of threads sharing L2 cache; assume %"PRIu32,
147+
threads_per_l2);
148148
l2_count = freebsd_topology.threads / threads_per_l2;
149149
cpuinfo_log_debug("detected %"PRIu32" L2 caches", l2_count);
150150
}
151151

152152
uint32_t threads_per_l3 = 0, l3_count = 0;
153153
if (x86_processor.cache.l3.size != 0) {
154-
if (threads_per_l3 == 0) {
155-
/*
156-
* Assume that threads on the same package share L3.
157-
* However, is it not necessarily the last-level cache (there may be L4 cache as well)
158-
*/
159-
threads_per_l3 = freebsd_topology.threads / freebsd_topology.packages;
160-
cpuinfo_log_warning("freebsd kernel did not report number of threads sharing L3 cache; assume %"PRIu32,
161-
threads_per_l3);
162-
}
154+
/*
155+
* Assume that threads on the same package share L3.
156+
* However, is it not necessarily the last-level cache (there may be L4 cache as well)
157+
*/
158+
threads_per_l3 = freebsd_topology.threads / freebsd_topology.packages;
159+
cpuinfo_log_warning("freebsd kernel did not report number of threads sharing L3 cache; assume %"PRIu32,
160+
threads_per_l3);
163161
l3_count = freebsd_topology.threads / threads_per_l3;
164162
cpuinfo_log_debug("detected %"PRIu32" L3 caches", l3_count);
165163
}
166164

167165
uint32_t threads_per_l4 = 0, l4_count = 0;
168166
if (x86_processor.cache.l4.size != 0) {
169-
if (threads_per_l4 == 0) {
170-
/*
171-
* Assume that all threads share this L4.
172-
* As of now, L4 cache exists only on notebook x86 CPUs, which are single-package,
173-
* but multi-socket systems could have shared L4 (like on IBM POWER8).
174-
*/
175-
threads_per_l4 = freebsd_topology.threads;
176-
cpuinfo_log_warning("freebsd kernel did not report number of threads sharing L4 cache; assume %"PRIu32,
177-
threads_per_l4);
178-
}
167+
/*
168+
* Assume that all threads share this L4.
169+
* As of now, L4 cache exists only on notebook x86 CPUs, which are single-package,
170+
* but multi-socket systems could have shared L4 (like on IBM POWER8).
171+
*/
172+
threads_per_l4 = freebsd_topology.threads;
173+
cpuinfo_log_warning("freebsd kernel did not report number of threads sharing L4 cache; assume %"PRIu32,
174+
threads_per_l4);
179175
l4_count = freebsd_topology.threads / threads_per_l4;
180176
cpuinfo_log_debug("detected %"PRIu32" L4 caches", l4_count);
181177
}

0 commit comments

Comments
 (0)