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