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