1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <linux/bitops.h>
5 #include "api/fs/fs.h"
6 #include "smt.h"
7
8 /**
9 * hweight_str - Returns the number of bits set in str. Stops at first non-hex
10 * or ',' character.
11 */
hweight_str(char * str)12 static int hweight_str(char *str)
13 {
14 int result = 0;
15
16 while (*str) {
17 switch (*str++) {
18 case '0':
19 case ',':
20 break;
21 case '1':
22 case '2':
23 case '4':
24 case '8':
25 result++;
26 break;
27 case '3':
28 case '5':
29 case '6':
30 case '9':
31 case 'a':
32 case 'A':
33 case 'c':
34 case 'C':
35 result += 2;
36 break;
37 case '7':
38 case 'b':
39 case 'B':
40 case 'd':
41 case 'D':
42 case 'e':
43 case 'E':
44 result += 3;
45 break;
46 case 'f':
47 case 'F':
48 result += 4;
49 break;
50 default:
51 goto done;
52 }
53 }
54 done:
55 return result;
56 }
57
smt_on(void)58 int smt_on(void)
59 {
60 static bool cached;
61 static int cached_result;
62 int cpu;
63 int ncpu;
64
65 if (cached)
66 return cached_result;
67
68 if (sysfs__read_int("devices/system/cpu/smt/active", &cached_result) >= 0) {
69 cached = true;
70 return cached_result;
71 }
72
73 cached_result = 0;
74 ncpu = sysconf(_SC_NPROCESSORS_CONF);
75 for (cpu = 0; cpu < ncpu; cpu++) {
76 unsigned long long siblings;
77 char *str;
78 size_t strlen;
79 char fn[256];
80
81 snprintf(fn, sizeof fn,
82 "devices/system/cpu/cpu%d/topology/thread_siblings", cpu);
83 if (sysfs__read_str(fn, &str, &strlen) < 0) {
84 snprintf(fn, sizeof fn,
85 "devices/system/cpu/cpu%d/topology/core_cpus", cpu);
86 if (sysfs__read_str(fn, &str, &strlen) < 0)
87 continue;
88 }
89 /* Entry is hex, but does not have 0x, so need custom parser */
90 siblings = hweight_str(str);
91 free(str);
92 if (siblings > 1) {
93 cached_result = 1;
94 break;
95 }
96 }
97 cached = true;
98 return cached_result;
99 }
100