|
@@ -2893,6 +2893,90 @@ GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
|
|
|
return guest_get_diskstats(errp);
|
|
|
}
|
|
|
|
|
|
+GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
|
|
|
+{
|
|
|
+ GuestCpuStatsList *head = NULL, **tail = &head;
|
|
|
+ const char *cpustats = "/proc/stat";
|
|
|
+ int clk_tck = sysconf(_SC_CLK_TCK);
|
|
|
+ FILE *fp;
|
|
|
+ size_t n;
|
|
|
+ char *line = NULL;
|
|
|
+
|
|
|
+ fp = fopen(cpustats, "r");
|
|
|
+ if (fp == NULL) {
|
|
|
+ error_setg_errno(errp, errno, "open(\"%s\")", cpustats);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (getline(&line, &n, fp) != -1) {
|
|
|
+ GuestCpuStats *cpustat = NULL;
|
|
|
+ GuestLinuxCpuStats *linuxcpustat;
|
|
|
+ int i;
|
|
|
+ unsigned long user, system, idle, iowait, irq, softirq, steal, guest;
|
|
|
+ unsigned long nice, guest_nice;
|
|
|
+ char name[64];
|
|
|
+
|
|
|
+ i = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
|
|
|
+ name, &user, &nice, &system, &idle, &iowait, &irq, &softirq,
|
|
|
+ &steal, &guest, &guest_nice);
|
|
|
+
|
|
|
+ /* drop "cpu 1 2 3 ...", get "cpuX 1 2 3 ..." only */
|
|
|
+ if ((i == EOF) || strncmp(name, "cpu", 3) || (name[3] == '\0')) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i < 5) {
|
|
|
+ slog("Parsing cpu stat from %s failed, see \"man proc\"", cpustats);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ cpustat = g_new0(GuestCpuStats, 1);
|
|
|
+ cpustat->type = GUEST_CPU_STATS_TYPE_LINUX;
|
|
|
+
|
|
|
+ linuxcpustat = &cpustat->u.q_linux;
|
|
|
+ linuxcpustat->cpu = atoi(&name[3]);
|
|
|
+ linuxcpustat->user = user * 1000 / clk_tck;
|
|
|
+ linuxcpustat->nice = nice * 1000 / clk_tck;
|
|
|
+ linuxcpustat->system = system * 1000 / clk_tck;
|
|
|
+ linuxcpustat->idle = idle * 1000 / clk_tck;
|
|
|
+
|
|
|
+ if (i > 5) {
|
|
|
+ linuxcpustat->has_iowait = true;
|
|
|
+ linuxcpustat->iowait = iowait * 1000 / clk_tck;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i > 6) {
|
|
|
+ linuxcpustat->has_irq = true;
|
|
|
+ linuxcpustat->irq = irq * 1000 / clk_tck;
|
|
|
+ linuxcpustat->has_softirq = true;
|
|
|
+ linuxcpustat->softirq = softirq * 1000 / clk_tck;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i > 8) {
|
|
|
+ linuxcpustat->has_steal = true;
|
|
|
+ linuxcpustat->steal = steal * 1000 / clk_tck;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i > 9) {
|
|
|
+ linuxcpustat->has_guest = true;
|
|
|
+ linuxcpustat->guest = guest * 1000 / clk_tck;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i > 10) {
|
|
|
+ linuxcpustat->has_guest = true;
|
|
|
+ linuxcpustat->guest = guest * 1000 / clk_tck;
|
|
|
+ linuxcpustat->has_guestnice = true;
|
|
|
+ linuxcpustat->guestnice = guest_nice * 1000 / clk_tck;
|
|
|
+ }
|
|
|
+
|
|
|
+ QAPI_LIST_APPEND(tail, cpustat);
|
|
|
+ }
|
|
|
+
|
|
|
+ free(line);
|
|
|
+ fclose(fp);
|
|
|
+ return head;
|
|
|
+}
|
|
|
+
|
|
|
#else /* defined(__linux__) */
|
|
|
|
|
|
void qmp_guest_suspend_disk(Error **errp)
|
|
@@ -3247,6 +3331,11 @@ GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
|
|
|
+{
|
|
|
+ error_setg(errp, QERR_UNSUPPORTED);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
|
|
|
#endif /* CONFIG_FSFREEZE */
|
|
|
|