xref: /openbmc/qemu/target/i386/kvm/vmsr_energy.c (revision b92b39af4219df4250f121f64d215506909c7404)
1 /*
2  * QEMU KVM support -- x86 virtual RAPL msr
3  *
4  * Copyright 2024 Red Hat, Inc. 2024
5  *
6  *  Author:
7  *      Anthony Harivel <aharivel@redhat.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10  * See the COPYING file in the top-level directory.
11  *
12  */
13 
14 #include "qemu/osdep.h"
15 #include "qemu/error-report.h"
16 #include "vmsr_energy.h"
17 #include "io/channel.h"
18 #include "io/channel-socket.h"
19 #include "hw/boards.h"
20 #include "cpu.h"
21 #include "host-cpu.h"
22 
vmsr_compute_default_paths(void)23 char *vmsr_compute_default_paths(void)
24 {
25     g_autofree char *state = qemu_get_local_state_dir();
26 
27     return g_build_filename(state, "run", "qemu-vmsr-helper.sock", NULL);
28 }
29 
is_rapl_enabled(void)30 int is_rapl_enabled(void)
31 {
32     const char *path = "/sys/class/powercap/intel-rapl/enabled";
33     FILE *file = fopen(path, "r");
34     int value = 0;
35 
36     if (file != NULL) {
37         if (fscanf(file, "%d", &value) != 1) {
38             error_report("INTEL RAPL not enabled");
39         }
40         fclose(file);
41     } else {
42         error_report("Error opening %s", path);
43     }
44 
45     return value;
46 }
47 
vmsr_open_socket(const char * path)48 QIOChannelSocket *vmsr_open_socket(const char *path)
49 {
50     g_autofree char *socket_path = NULL;
51 
52     socket_path = g_strdup(path);
53 
54     SocketAddress saddr = {
55         .type = SOCKET_ADDRESS_TYPE_UNIX,
56         .u.q_unix.path = socket_path
57     };
58 
59     QIOChannelSocket *sioc = qio_channel_socket_new();
60     Error *local_err = NULL;
61 
62     qio_channel_set_name(QIO_CHANNEL(sioc), "vmsr-helper");
63     qio_channel_socket_connect_sync(sioc,
64                                     &saddr,
65                                     &local_err);
66     if (local_err) {
67         /* Close socket. */
68         qio_channel_close(QIO_CHANNEL(sioc), NULL);
69         object_unref(OBJECT(sioc));
70         sioc = NULL;
71         goto out;
72     }
73 
74     qio_channel_set_delay(QIO_CHANNEL(sioc), false);
75 out:
76     return sioc;
77 }
78 
vmsr_read_msr(uint32_t reg,uint32_t cpu_id,uint32_t tid,QIOChannelSocket * sioc)79 uint64_t vmsr_read_msr(uint32_t reg, uint32_t cpu_id, uint32_t tid,
80                        QIOChannelSocket *sioc)
81 {
82     uint64_t data = 0;
83     int r = 0;
84     Error *local_err = NULL;
85     uint32_t buffer[3];
86     /*
87      * Send the required arguments:
88      * 1. RAPL MSR register to read
89      * 2. On which CPU ID
90      * 3. From which vCPU (Thread ID)
91      */
92     buffer[0] = reg;
93     buffer[1] = cpu_id;
94     buffer[2] = tid;
95 
96     r = qio_channel_write_all(QIO_CHANNEL(sioc),
97                               (char *)buffer, sizeof(buffer),
98                               &local_err);
99     if (r < 0) {
100         goto out_close;
101     }
102 
103     r = qio_channel_read(QIO_CHANNEL(sioc),
104                              (char *)&data, sizeof(data),
105                              &local_err);
106     if (r < 0) {
107         data = 0;
108         goto out_close;
109     }
110 
111 out_close:
112    return data;
113 }
114 
115 /* Retrieve the max number of physical package */
vmsr_get_max_physical_package(unsigned int max_cpus)116 unsigned int vmsr_get_max_physical_package(unsigned int max_cpus)
117 {
118     const char *dir = "/sys/devices/system/cpu/";
119     const char *topo_path = "topology/physical_package_id";
120     g_autofree int *uniquePackages = g_new0(int, max_cpus);
121     unsigned int packageCount = 0;
122     FILE *file = NULL;
123 
124     for (int i = 0; i < max_cpus; i++) {
125         g_autofree char *filePath = NULL;
126         g_autofree char *cpuid = g_strdup_printf("cpu%d", i);
127 
128         filePath = g_build_filename(dir, cpuid, topo_path, NULL);
129 
130         file = fopen(filePath, "r");
131 
132         if (file == NULL) {
133             error_report("Error opening physical_package_id file");
134             return 0;
135         }
136 
137         char packageId[10];
138         if (fgets(packageId, sizeof(packageId), file) == NULL) {
139             packageCount = 0;
140         }
141 
142         fclose(file);
143 
144         int currentPackageId = atoi(packageId);
145 
146         bool isUnique = true;
147         for (int j = 0; j < packageCount; j++) {
148             if (uniquePackages[j] == currentPackageId) {
149                 isUnique = false;
150                 break;
151             }
152         }
153 
154         if (isUnique) {
155             uniquePackages[packageCount] = currentPackageId;
156             packageCount++;
157 
158             if (packageCount >= max_cpus) {
159                 break;
160             }
161         }
162     }
163 
164     return (packageCount == 0) ? 1 : packageCount;
165 }
166 
167 /* Retrieve the max number of physical cpu on the host */
vmsr_get_maxcpus(void)168 unsigned int vmsr_get_maxcpus(void)
169 {
170     GDir *dir;
171     const gchar *entry_name;
172     unsigned int cpu_count = 0;
173     const char *path = "/sys/devices/system/cpu/";
174 
175     dir = g_dir_open(path, 0, NULL);
176     if (dir == NULL) {
177         error_report("Unable to open cpu directory");
178         return -1;
179     }
180 
181     while ((entry_name = g_dir_read_name(dir)) != NULL) {
182         if (g_ascii_strncasecmp(entry_name, "cpu", 3) == 0 &&
183             isdigit(entry_name[3])) {
184             cpu_count++;
185         }
186     }
187 
188     g_dir_close(dir);
189 
190     return cpu_count;
191 }
192 
193 /* Count the number of physical cpu on each packages */
vmsr_count_cpus_per_package(unsigned int * package_count,unsigned int max_pkgs)194 unsigned int vmsr_count_cpus_per_package(unsigned int *package_count,
195                                          unsigned int max_pkgs)
196 {
197     g_autofree char *file_contents = NULL;
198     g_autofree char *path = NULL;
199     g_autofree char *path_name = NULL;
200     gsize length;
201 
202     /* Iterate over cpus and count cpus in each package */
203     for (int cpu_id = 0; ; cpu_id++) {
204         path_name = g_strdup_printf("/sys/devices/system/cpu/cpu%d/"
205             "topology/physical_package_id", cpu_id);
206 
207         path = g_build_filename(path_name, NULL);
208 
209         if (!g_file_get_contents(path, &file_contents, &length, NULL)) {
210             break; /* No more cpus */
211         }
212 
213         /* Get the physical package ID for this CPU */
214         int package_id = atoi(file_contents);
215 
216         /* Check if the package ID is within the known number of packages */
217         if (package_id >= 0 && package_id < max_pkgs) {
218             /* If yes, count the cpu for this package*/
219             package_count[package_id]++;
220         }
221     }
222 
223     return 0;
224 }
225 
226 /* Get the physical package id from a given cpu id */
vmsr_get_physical_package_id(int cpu_id)227 int vmsr_get_physical_package_id(int cpu_id)
228 {
229     g_autofree char *file_contents = NULL;
230     g_autofree char *file_path = NULL;
231     int package_id = -1;
232     gsize length;
233 
234     file_path = g_strdup_printf("/sys/devices/system/cpu/cpu%d"
235         "/topology/physical_package_id", cpu_id);
236 
237     if (!g_file_get_contents(file_path, &file_contents, &length, NULL)) {
238         goto out;
239     }
240 
241     package_id = atoi(file_contents);
242 
243 out:
244     return package_id;
245 }
246 
247 /* Read the scheduled time for a given thread of a give pid */
vmsr_read_thread_stat(pid_t pid,unsigned int thread_id,unsigned long long * utime,unsigned long long * stime,unsigned int * cpu_id)248 void vmsr_read_thread_stat(pid_t pid,
249                       unsigned int thread_id,
250                       unsigned long long *utime,
251                       unsigned long long *stime,
252                       unsigned int *cpu_id)
253 {
254     g_autofree char *path = NULL;
255     g_autofree char *path_name = NULL;
256 
257     path_name = g_strdup_printf("/proc/%u/task/%d/stat", pid, thread_id);
258 
259     path = g_build_filename(path_name, NULL);
260 
261     FILE *file = fopen(path, "r");
262     if (file == NULL) {
263         error_report("Error opening %s", path_name);
264         return;
265     }
266 
267     if (fscanf(file, "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u"
268         " %llu %llu %*d %*d %*d %*d %*d %*d %*u %*u %*d %*u %*u"
269         " %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*u %*u %u",
270            utime, stime, cpu_id) != 3)
271     {
272         fclose(file);
273         error_report("Error fscanf did not report the right amount of items");
274         return;
275     }
276 
277     fclose(file);
278 }
279 
280 /* Read QEMU stat task folder to retrieve all QEMU threads ID */
vmsr_get_thread_ids(pid_t pid,unsigned int * num_threads)281 pid_t *vmsr_get_thread_ids(pid_t pid, unsigned int *num_threads)
282 {
283     g_autofree char *task_path = g_strdup_printf("%d/task", pid);
284     g_autofree char *path = g_build_filename("/proc", task_path, NULL);
285 
286     DIR *dir = opendir(path);
287     if (dir == NULL) {
288         error_report("Error opening /proc/qemu/task");
289         return NULL;
290     }
291 
292     pid_t *thread_ids = NULL;
293     unsigned int thread_count = 0;
294 
295     g_autofree struct dirent *ent = NULL;
296     while ((ent = readdir(dir)) != NULL) {
297         if (ent->d_name[0] == '.') {
298             continue;
299         }
300         pid_t tid = atoi(ent->d_name);
301         if (pid != tid) {
302             thread_ids = g_renew(pid_t, thread_ids, (thread_count + 1));
303             thread_ids[thread_count] = tid;
304             thread_count++;
305         }
306     }
307 
308     closedir(dir);
309 
310     *num_threads = thread_count;
311     return thread_ids;
312 }
313 
vmsr_delta_ticks(vmsr_thread_stat * thd_stat,int i)314 void vmsr_delta_ticks(vmsr_thread_stat *thd_stat, int i)
315 {
316     thd_stat[i].delta_ticks = (thd_stat[i].utime[1] + thd_stat[i].stime[1])
317                             - (thd_stat[i].utime[0] + thd_stat[i].stime[0]);
318 }
319 
vmsr_get_ratio(uint64_t e_delta,unsigned long long delta_ticks,unsigned int maxticks)320 double vmsr_get_ratio(uint64_t e_delta,
321                       unsigned long long delta_ticks,
322                       unsigned int maxticks)
323 {
324     return (e_delta / 100.0) * ((100.0 / maxticks) * delta_ticks);
325 }
326 
vmsr_init_topo_info(X86CPUTopoInfo * topo_info,const MachineState * ms)327 void vmsr_init_topo_info(X86CPUTopoInfo *topo_info,
328                            const MachineState *ms)
329 {
330     topo_info->dies_per_pkg = ms->smp.dies;
331     topo_info->modules_per_die = ms->smp.modules;
332     topo_info->cores_per_module = ms->smp.cores;
333     topo_info->threads_per_core = ms->smp.threads;
334 }
335 
336