2 * QEMU KVM support -- x86 virtual RAPL msr
4 * Copyright 2024 Red Hat, Inc. 2024
7 * Anthony Harivel <aharivel@redhat.com>
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.
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"
23 char *vmsr_compute_default_paths(void)
25 g_autofree
char *state
= qemu_get_local_state_dir();
27 return g_build_filename(state
, "run", "qemu-vmsr-helper.sock", NULL
);
30 bool is_host_cpu_intel(void)
32 int family
, model
, stepping
;
33 char vendor
[CPUID_VENDOR_SZ
+ 1];
35 host_cpu_vendor_fms(vendor
, &family
, &model
, &stepping
);
37 return strcmp(vendor
, CPUID_VENDOR_INTEL
);
40 int is_rapl_enabled(void)
42 const char *path
= "/sys/class/powercap/intel-rapl/enabled";
43 FILE *file
= fopen(path
, "r");
47 if (fscanf(file
, "%d", &value
) != 1) {
48 error_report("INTEL RAPL not enabled");
52 error_report("Error opening %s", path
);
58 QIOChannelSocket
*vmsr_open_socket(const char *path
)
60 g_autofree
char *socket_path
= NULL
;
62 socket_path
= g_strdup(path
);
64 SocketAddress saddr
= {
65 .type
= SOCKET_ADDRESS_TYPE_UNIX
,
66 .u
.q_unix
.path
= socket_path
69 QIOChannelSocket
*sioc
= qio_channel_socket_new();
70 Error
*local_err
= NULL
;
72 qio_channel_set_name(QIO_CHANNEL(sioc
), "vmsr-helper");
73 qio_channel_socket_connect_sync(sioc
,
78 qio_channel_close(QIO_CHANNEL(sioc
), NULL
);
79 object_unref(OBJECT(sioc
));
84 qio_channel_set_delay(QIO_CHANNEL(sioc
), false);
89 uint64_t vmsr_read_msr(uint32_t reg
, uint32_t cpu_id
, uint32_t tid
,
90 QIOChannelSocket
*sioc
)
94 Error
*local_err
= NULL
;
97 * Send the required arguments:
98 * 1. RAPL MSR register to read
100 * 3. From which vCPU (Thread ID)
106 r
= qio_channel_write_all(QIO_CHANNEL(sioc
),
107 (char *)buffer
, sizeof(buffer
),
113 r
= qio_channel_read(QIO_CHANNEL(sioc
),
114 (char *)&data
, sizeof(data
),
125 /* Retrieve the max number of physical package */
126 unsigned int vmsr_get_max_physical_package(unsigned int max_cpus
)
128 const char *dir
= "/sys/devices/system/cpu/";
129 const char *topo_path
= "topology/physical_package_id";
130 g_autofree
int *uniquePackages
= g_new0(int, max_cpus
);
131 unsigned int packageCount
= 0;
134 for (int i
= 0; i
< max_cpus
; i
++) {
135 g_autofree
char *filePath
= NULL
;
136 g_autofree
char *cpuid
= g_strdup_printf("cpu%d", i
);
138 filePath
= g_build_filename(dir
, cpuid
, topo_path
, NULL
);
140 file
= fopen(filePath
, "r");
143 error_report("Error opening physical_package_id file");
148 if (fgets(packageId
, sizeof(packageId
), file
) == NULL
) {
154 int currentPackageId
= atoi(packageId
);
156 bool isUnique
= true;
157 for (int j
= 0; j
< packageCount
; j
++) {
158 if (uniquePackages
[j
] == currentPackageId
) {
165 uniquePackages
[packageCount
] = currentPackageId
;
168 if (packageCount
>= max_cpus
) {
174 return (packageCount
== 0) ? 1 : packageCount
;
177 /* Retrieve the max number of physical cpu on the host */
178 unsigned int vmsr_get_maxcpus(void)
181 const gchar
*entry_name
;
182 unsigned int cpu_count
= 0;
183 const char *path
= "/sys/devices/system/cpu/";
185 dir
= g_dir_open(path
, 0, NULL
);
187 error_report("Unable to open cpu directory");
191 while ((entry_name
= g_dir_read_name(dir
)) != NULL
) {
192 if (g_ascii_strncasecmp(entry_name
, "cpu", 3) == 0 &&
193 isdigit(entry_name
[3])) {
203 /* Count the number of physical cpu on each packages */
204 unsigned int vmsr_count_cpus_per_package(unsigned int *package_count
,
205 unsigned int max_pkgs
)
207 g_autofree
char *file_contents
= NULL
;
208 g_autofree
char *path
= NULL
;
209 g_autofree
char *path_name
= NULL
;
212 /* Iterate over cpus and count cpus in each package */
213 for (int cpu_id
= 0; ; cpu_id
++) {
214 path_name
= g_strdup_printf("/sys/devices/system/cpu/cpu%d/"
215 "topology/physical_package_id", cpu_id
);
217 path
= g_build_filename(path_name
, NULL
);
219 if (!g_file_get_contents(path
, &file_contents
, &length
, NULL
)) {
220 break; /* No more cpus */
223 /* Get the physical package ID for this CPU */
224 int package_id
= atoi(file_contents
);
226 /* Check if the package ID is within the known number of packages */
227 if (package_id
>= 0 && package_id
< max_pkgs
) {
228 /* If yes, count the cpu for this package*/
229 package_count
[package_id
]++;
236 /* Get the physical package id from a given cpu id */
237 int vmsr_get_physical_package_id(int cpu_id
)
239 g_autofree
char *file_contents
= NULL
;
240 g_autofree
char *file_path
= NULL
;
244 file_path
= g_strdup_printf("/sys/devices/system/cpu/cpu%d"
245 "/topology/physical_package_id", cpu_id
);
247 if (!g_file_get_contents(file_path
, &file_contents
, &length
, NULL
)) {
251 package_id
= atoi(file_contents
);
257 /* Read the scheduled time for a given thread of a give pid */
258 void vmsr_read_thread_stat(pid_t pid
,
259 unsigned int thread_id
,
260 unsigned long long *utime
,
261 unsigned long long *stime
,
262 unsigned int *cpu_id
)
264 g_autofree
char *path
= NULL
;
265 g_autofree
char *path_name
= NULL
;
267 path_name
= g_strdup_printf("/proc/%u/task/%d/stat", pid
, thread_id
);
269 path
= g_build_filename(path_name
, NULL
);
271 FILE *file
= fopen(path
, "r");
273 error_report("Error opening %s", path_name
);
277 if (fscanf(file
, "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u"
278 " %llu %llu %*d %*d %*d %*d %*d %*d %*u %*u %*d %*u %*u"
279 " %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*u %*u %u",
280 utime
, stime
, cpu_id
) != 3)
283 error_report("Error fscanf did not report the right amount of items");
291 /* Read QEMU stat task folder to retrieve all QEMU threads ID */
292 pid_t
*vmsr_get_thread_ids(pid_t pid
, unsigned int *num_threads
)
294 g_autofree
char *task_path
= g_strdup_printf("%d/task", pid
);
295 g_autofree
char *path
= g_build_filename("/proc", task_path
, NULL
);
297 DIR *dir
= opendir(path
);
299 error_report("Error opening /proc/qemu/task");
303 pid_t
*thread_ids
= NULL
;
304 unsigned int thread_count
= 0;
306 g_autofree
struct dirent
*ent
= NULL
;
307 while ((ent
= readdir(dir
)) != NULL
) {
308 if (ent
->d_name
[0] == '.') {
311 pid_t tid
= atoi(ent
->d_name
);
313 thread_ids
= g_renew(pid_t
, thread_ids
, (thread_count
+ 1));
314 thread_ids
[thread_count
] = tid
;
321 *num_threads
= thread_count
;
325 void vmsr_delta_ticks(vmsr_thread_stat
*thd_stat
, int i
)
327 thd_stat
[i
].delta_ticks
= (thd_stat
[i
].utime
[1] + thd_stat
[i
].stime
[1])
328 - (thd_stat
[i
].utime
[0] + thd_stat
[i
].stime
[0]);
331 double vmsr_get_ratio(uint64_t e_delta
,
332 unsigned long long delta_ticks
,
333 unsigned int maxticks
)
335 return (e_delta
/ 100.0) * ((100.0 / maxticks
) * delta_ticks
);
338 void vmsr_init_topo_info(X86CPUTopoInfo
*topo_info
,
339 const MachineState
*ms
)
341 topo_info
->dies_per_pkg
= ms
->smp
.dies
;
342 topo_info
->modules_per_die
= ms
->smp
.modules
;
343 topo_info
->cores_per_module
= ms
->smp
.cores
;
344 topo_info
->threads_per_core
= ms
->smp
.threads
;