1*2b54f0dbSXin Li #include <string.h>
2*2b54f0dbSXin Li #include <alloca.h>
3*2b54f0dbSXin Li #include <errno.h>
4*2b54f0dbSXin Li
5*2b54f0dbSXin Li #include <sys/types.h>
6*2b54f0dbSXin Li #include <sys/sysctl.h>
7*2b54f0dbSXin Li
8*2b54f0dbSXin Li #include <cpuinfo/log.h>
9*2b54f0dbSXin Li #include <mach/api.h>
10*2b54f0dbSXin Li
11*2b54f0dbSXin Li #include <TargetConditionals.h>
12*2b54f0dbSXin Li
13*2b54f0dbSXin Li
cpuinfo_mach_detect_topology(void)14*2b54f0dbSXin Li struct cpuinfo_mach_topology cpuinfo_mach_detect_topology(void) {
15*2b54f0dbSXin Li int cores = 1;
16*2b54f0dbSXin Li size_t sizeof_cores = sizeof(cores);
17*2b54f0dbSXin Li if (sysctlbyname("hw.physicalcpu_max", &cores, &sizeof_cores, NULL, 0) != 0) {
18*2b54f0dbSXin Li cpuinfo_log_error("sysctlbyname(\"hw.physicalcpu_max\") failed: %s", strerror(errno));
19*2b54f0dbSXin Li } else if (cores <= 0) {
20*2b54f0dbSXin Li cpuinfo_log_error("sysctlbyname(\"hw.physicalcpu_max\") returned invalid value %d", cores);
21*2b54f0dbSXin Li cores = 1;
22*2b54f0dbSXin Li }
23*2b54f0dbSXin Li
24*2b54f0dbSXin Li int threads = 1;
25*2b54f0dbSXin Li size_t sizeof_threads = sizeof(threads);
26*2b54f0dbSXin Li if (sysctlbyname("hw.logicalcpu_max", &threads, &sizeof_threads, NULL, 0) != 0) {
27*2b54f0dbSXin Li cpuinfo_log_error("sysctlbyname(\"hw.logicalcpu_max\") failed: %s", strerror(errno));
28*2b54f0dbSXin Li } else if (threads <= 0) {
29*2b54f0dbSXin Li cpuinfo_log_error("sysctlbyname(\"hw.logicalcpu_max\") returned invalid value %d", threads);
30*2b54f0dbSXin Li threads = cores;
31*2b54f0dbSXin Li }
32*2b54f0dbSXin Li
33*2b54f0dbSXin Li int packages = 1;
34*2b54f0dbSXin Li #if !TARGET_OS_IPHONE
35*2b54f0dbSXin Li size_t sizeof_packages = sizeof(packages);
36*2b54f0dbSXin Li if (sysctlbyname("hw.packages", &packages, &sizeof_packages, NULL, 0) != 0) {
37*2b54f0dbSXin Li cpuinfo_log_error("sysctlbyname(\"hw.packages\") failed: %s", strerror(errno));
38*2b54f0dbSXin Li } else if (packages <= 0) {
39*2b54f0dbSXin Li cpuinfo_log_error("sysctlbyname(\"hw.packages\") returned invalid value %d", packages);
40*2b54f0dbSXin Li packages = 1;
41*2b54f0dbSXin Li }
42*2b54f0dbSXin Li #endif
43*2b54f0dbSXin Li
44*2b54f0dbSXin Li cpuinfo_log_debug("mach topology: packages = %d, cores = %d, threads = %d", packages, (int) cores, (int) threads);
45*2b54f0dbSXin Li struct cpuinfo_mach_topology topology = {
46*2b54f0dbSXin Li .packages = (uint32_t) packages,
47*2b54f0dbSXin Li .cores = (uint32_t) cores,
48*2b54f0dbSXin Li .threads = (uint32_t) threads
49*2b54f0dbSXin Li };
50*2b54f0dbSXin Li
51*2b54f0dbSXin Li #if !TARGET_OS_IPHONE
52*2b54f0dbSXin Li size_t cacheconfig_size = 0;
53*2b54f0dbSXin Li if (sysctlbyname("hw.cacheconfig", NULL, &cacheconfig_size, NULL, 0) != 0) {
54*2b54f0dbSXin Li cpuinfo_log_error("sysctlbyname(\"hw.cacheconfig\") failed: %s", strerror(errno));
55*2b54f0dbSXin Li } else {
56*2b54f0dbSXin Li uint64_t* cacheconfig = alloca(cacheconfig_size);
57*2b54f0dbSXin Li if (sysctlbyname("hw.cacheconfig", cacheconfig, &cacheconfig_size, NULL, 0) != 0) {
58*2b54f0dbSXin Li cpuinfo_log_error("sysctlbyname(\"hw.cacheconfig\") failed: %s", strerror(errno));
59*2b54f0dbSXin Li } else {
60*2b54f0dbSXin Li size_t cache_configs = cacheconfig_size / sizeof(uint64_t);
61*2b54f0dbSXin Li cpuinfo_log_debug("mach hw.cacheconfig count: %zu", cache_configs);
62*2b54f0dbSXin Li if (cache_configs > CPUINFO_MACH_MAX_CACHE_LEVELS) {
63*2b54f0dbSXin Li cache_configs = CPUINFO_MACH_MAX_CACHE_LEVELS;
64*2b54f0dbSXin Li }
65*2b54f0dbSXin Li for (size_t i = 0; i < cache_configs; i++) {
66*2b54f0dbSXin Li cpuinfo_log_debug("mach hw.cacheconfig[%zu]: %"PRIu64, i, cacheconfig[i]);
67*2b54f0dbSXin Li topology.threads_per_cache[i] = cacheconfig[i];
68*2b54f0dbSXin Li }
69*2b54f0dbSXin Li }
70*2b54f0dbSXin Li }
71*2b54f0dbSXin Li #endif
72*2b54f0dbSXin Li return topology;
73*2b54f0dbSXin Li }
74