• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
sysctl_int(const char * name)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 
sysctl_str(const char * name)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 		return NULL;
28 	} else if (value_size <= 0) {
29 		cpuinfo_log_error("sysctlbyname(\"%s\") returned invalid value size %zu", name, value_size);
30 		return NULL;
31 	}
32 	value_size += 1;
33 	char* value = calloc(value_size, 1);
34 	if (!value) {
35 		cpuinfo_log_error("calloc %zu bytes failed", value_size);
36 		return NULL;
37 	}
38 	if (sysctlbyname(name, value, &value_size, NULL, 0) != 0) {
39 		cpuinfo_log_error("sysctlbyname(\"%s\") failed: %s", name, strerror(errno));
40 		free(value);
41 		return NULL;
42 	}
43 	return value;
44 }
45 
cpuinfo_freebsd_detect_topology(void)46 struct cpuinfo_freebsd_topology cpuinfo_freebsd_detect_topology(void) {
47 	struct cpuinfo_freebsd_topology topology = {
48 		.packages = 0,
49 		.cores = 0,
50 		.threads_per_core = 0,
51 		.threads = 0,
52 	};
53 	char* topology_spec = sysctl_str("kern.sched.topology_spec");
54 	if (!topology_spec) {
55 		return topology;
56 	}
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];
60 		char* p = strstr(topology_spec, group_tag);
61 		while (p) {
62 			topology.packages += 1;
63 			p++;
64 			p = strstr(p, group_tag);
65 		}
66 		if (topology.packages > 0) {
67 			break;
68 		}
69 	}
70 
71 	if (topology.packages == 0) {
72 		cpuinfo_log_error("failed to parse topology_spec: %s", topology_spec);
73 		free(topology_spec);
74 		goto fail;
75 	}
76 	free(topology_spec);
77 	topology.cores = sysctl_int("kern.smp.cores");
78 	if (topology.cores == 0) {
79 		goto fail;
80 	}
81 	if (topology.cores < topology.packages) {
82 		cpuinfo_log_error("invalid numbers of package and core: %d %d", topology.packages, topology.cores);
83 		goto fail;
84 	}
85 	topology.threads_per_core = sysctl_int("kern.smp.threads_per_core");
86 	if (topology.threads_per_core == 0) {
87 		goto fail;
88 	}
89 	cpuinfo_log_debug(
90 		"freebsd topology: packages = %d, cores = %d, "
91 		"threads_per_core = %d",
92 		topology.packages,
93 		topology.cores,
94 		topology.threads_per_core);
95 	topology.threads = topology.threads_per_core * topology.cores;
96 	return topology;
97 fail:
98 	topology.packages = 0;
99 	return topology;
100 }
101