diff options
Diffstat (limited to 'tools/power/cpupower/utils/helpers/topology.c')
-rw-r--r-- | tools/power/cpupower/utils/helpers/topology.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c new file mode 100644 index 000000000000..385ee5c7570c --- /dev/null +++ b/tools/power/cpupower/utils/helpers/topology.c | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * ToDo: Needs to be done more properly for AMD/Intel specifics | ||
7 | */ | ||
8 | |||
9 | /* Helper struct for qsort, must be in sync with cpupower_topology.cpu_info */ | ||
10 | /* Be careful: Need to pass unsigned to the sort, so that offlined cores are | ||
11 | in the end, but double check for -1 for offlined cpus at other places */ | ||
12 | |||
13 | #include <stdlib.h> | ||
14 | #include <stdio.h> | ||
15 | #include <unistd.h> | ||
16 | #include <errno.h> | ||
17 | #include <fcntl.h> | ||
18 | |||
19 | #include <helpers/helpers.h> | ||
20 | #include <helpers/sysfs.h> | ||
21 | |||
22 | /* returns -1 on failure, 0 on success */ | ||
23 | int sysfs_topology_read_file(unsigned int cpu, const char *fname) | ||
24 | { | ||
25 | unsigned long value; | ||
26 | char linebuf[MAX_LINE_LEN]; | ||
27 | char *endp; | ||
28 | char path[SYSFS_PATH_MAX]; | ||
29 | |||
30 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s", | ||
31 | cpu, fname); | ||
32 | if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) | ||
33 | return -1; | ||
34 | value = strtoul(linebuf, &endp, 0); | ||
35 | if (endp == linebuf || errno == ERANGE) | ||
36 | return -1; | ||
37 | return value; | ||
38 | } | ||
39 | |||
40 | struct cpuid_core_info { | ||
41 | unsigned int pkg; | ||
42 | unsigned int thread; | ||
43 | unsigned int cpu; | ||
44 | }; | ||
45 | |||
46 | static int __compare(const void *t1, const void *t2) | ||
47 | { | ||
48 | struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; | ||
49 | struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2; | ||
50 | if (top1->pkg < top2->pkg) | ||
51 | return -1; | ||
52 | else if (top1->pkg > top2->pkg) | ||
53 | return 1; | ||
54 | else if (top1->thread < top2->thread) | ||
55 | return -1; | ||
56 | else if (top1->thread > top2->thread) | ||
57 | return 1; | ||
58 | else if (top1->cpu < top2->cpu) | ||
59 | return -1; | ||
60 | else if (top1->cpu > top2->cpu) | ||
61 | return 1; | ||
62 | else | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * Returns amount of cpus, negative on error, cpu_top must be | ||
68 | * passed to cpu_topology_release to free resources | ||
69 | * | ||
70 | * Array is sorted after ->pkg, ->core, then ->cpu | ||
71 | */ | ||
72 | int get_cpu_topology(struct cpupower_topology *cpu_top) | ||
73 | { | ||
74 | int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF); | ||
75 | |||
76 | cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus); | ||
77 | if (cpu_top->core_info == NULL) | ||
78 | return -ENOMEM; | ||
79 | cpu_top->pkgs = cpu_top->cores = 0; | ||
80 | for (cpu = 0; cpu < cpus; cpu++) { | ||
81 | cpu_top->core_info[cpu].pkg = | ||
82 | sysfs_topology_read_file(cpu, "physical_package_id"); | ||
83 | if ((int)cpu_top->core_info[cpu].pkg != -1 && | ||
84 | cpu_top->core_info[cpu].pkg > cpu_top->pkgs) | ||
85 | cpu_top->pkgs = cpu_top->core_info[cpu].pkg; | ||
86 | cpu_top->core_info[cpu].core = | ||
87 | sysfs_topology_read_file(cpu, "core_id"); | ||
88 | cpu_top->core_info[cpu].cpu = cpu; | ||
89 | } | ||
90 | cpu_top->pkgs++; | ||
91 | |||
92 | qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), | ||
93 | __compare); | ||
94 | |||
95 | /* Intel's cores count is not consecutively numbered, there may | ||
96 | * be a core_id of 3, but none of 2. Assume there always is 0 | ||
97 | * Get amount of cores by counting duplicates in a package | ||
98 | for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) { | ||
99 | if (cpu_top->core_info[cpu].core == 0) | ||
100 | cpu_top->cores++; | ||
101 | */ | ||
102 | return cpus; | ||
103 | } | ||
104 | |||
105 | void cpu_topology_release(struct cpupower_topology cpu_top) | ||
106 | { | ||
107 | free(cpu_top.core_info); | ||
108 | } | ||