| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <linux/bitops.h> |
| #include "api/fs/fs.h" |
| #include "smt.h" |
| |
| /** |
| * hweight_str - Returns the number of bits set in str. Stops at first non-hex |
| * or ',' character. |
| */ |
| static int hweight_str(char *str) |
| { |
| int result = 0; |
| |
| while (*str) { |
| switch (*str++) { |
| case '0': |
| case ',': |
| break; |
| case '1': |
| case '2': |
| case '4': |
| case '8': |
| result++; |
| break; |
| case '3': |
| case '5': |
| case '6': |
| case '9': |
| case 'a': |
| case 'A': |
| case 'c': |
| case 'C': |
| result += 2; |
| break; |
| case '7': |
| case 'b': |
| case 'B': |
| case 'd': |
| case 'D': |
| case 'e': |
| case 'E': |
| result += 3; |
| break; |
| case 'f': |
| case 'F': |
| result += 4; |
| break; |
| default: |
| goto done; |
| } |
| } |
| done: |
| return result; |
| } |
| |
| int smt_on(void) |
| { |
| static bool cached; |
| static int cached_result; |
| int cpu; |
| int ncpu; |
| |
| if (cached) |
| return cached_result; |
| |
| if (sysfs__read_int("devices/system/cpu/smt/active", &cached_result) >= 0) { |
| cached = true; |
| return cached_result; |
| } |
| |
| cached_result = 0; |
| ncpu = sysconf(_SC_NPROCESSORS_CONF); |
| for (cpu = 0; cpu < ncpu; cpu++) { |
| unsigned long long siblings; |
| char *str; |
| size_t strlen; |
| char fn[256]; |
| |
| snprintf(fn, sizeof fn, |
| "devices/system/cpu/cpu%d/topology/thread_siblings", cpu); |
| if (sysfs__read_str(fn, &str, &strlen) < 0) { |
| snprintf(fn, sizeof fn, |
| "devices/system/cpu/cpu%d/topology/core_cpus", cpu); |
| if (sysfs__read_str(fn, &str, &strlen) < 0) |
| continue; |
| } |
| /* Entry is hex, but does not have 0x, so need custom parser */ |
| siblings = hweight_str(str); |
| free(str); |
| if (siblings > 1) { |
| cached_result = 1; |
| break; |
| } |
| } |
| cached = true; |
| return cached_result; |
| } |