Andi Kleen | de5077c | 2017-08-11 16:26:22 -0700 | [diff] [blame] | 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 | |
Ian Rogers | 0ce0578 | 2021-11-23 16:12:30 -0800 | [diff] [blame] | 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 | |
Andi Kleen | de5077c | 2017-08-11 16:26:22 -0700 | [diff] [blame] | 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 | |
Ian Rogers | 0ce0578 | 2021-11-23 16:12:30 -0800 | [diff] [blame] | 68 | if (sysfs__read_int("devices/system/cpu/smt/active", &cached_result) >= 0) { |
| 69 | cached = true; |
| 70 | return cached_result; |
| 71 | } |
Konstantin Khlebnikov | bb62948 | 2020-04-29 19:23:41 +0300 | [diff] [blame] | 72 | |
Ian Rogers | 0ce0578 | 2021-11-23 16:12:30 -0800 | [diff] [blame] | 73 | cached_result = 0; |
Andi Kleen | de5077c | 2017-08-11 16:26:22 -0700 | [diff] [blame] | 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, |
Ian Rogers | 6dd8646 | 2021-11-23 16:12:31 -0800 | [diff] [blame] | 82 | "devices/system/cpu/cpu%d/topology/thread_siblings", cpu); |
Konstantin Khlebnikov | 846de43 | 2020-04-29 19:19:47 +0300 | [diff] [blame] | 83 | if (sysfs__read_str(fn, &str, &strlen) < 0) { |
Kan Liang | 0ccdb84 | 2019-06-04 15:50:44 -0700 | [diff] [blame] | 84 | snprintf(fn, sizeof fn, |
Ian Rogers | 6dd8646 | 2021-11-23 16:12:31 -0800 | [diff] [blame] | 85 | "devices/system/cpu/cpu%d/topology/core_cpus", cpu); |
Konstantin Khlebnikov | 846de43 | 2020-04-29 19:19:47 +0300 | [diff] [blame] | 86 | if (sysfs__read_str(fn, &str, &strlen) < 0) |
| 87 | continue; |
Kan Liang | 0ccdb84 | 2019-06-04 15:50:44 -0700 | [diff] [blame] | 88 | } |
Andi Kleen | de5077c | 2017-08-11 16:26:22 -0700 | [diff] [blame] | 89 | /* Entry is hex, but does not have 0x, so need custom parser */ |
Ian Rogers | 0ce0578 | 2021-11-23 16:12:30 -0800 | [diff] [blame] | 90 | siblings = hweight_str(str); |
Andi Kleen | de5077c | 2017-08-11 16:26:22 -0700 | [diff] [blame] | 91 | free(str); |
Ian Rogers | 0ce0578 | 2021-11-23 16:12:30 -0800 | [diff] [blame] | 92 | if (siblings > 1) { |
Andi Kleen | de5077c | 2017-08-11 16:26:22 -0700 | [diff] [blame] | 93 | cached_result = 1; |
Andi Kleen | de5077c | 2017-08-11 16:26:22 -0700 | [diff] [blame] | 94 | break; |
| 95 | } |
| 96 | } |
Ian Rogers | 0ce0578 | 2021-11-23 16:12:30 -0800 | [diff] [blame] | 97 | cached = true; |
Andi Kleen | de5077c | 2017-08-11 16:26:22 -0700 | [diff] [blame] | 98 | return cached_result; |
| 99 | } |