GNU Linux-libre 5.19-rc6-gnu
[releases.git] / tools / perf / util / smt.c
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  */
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
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 }