[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen staging] tools/xentop: Add physical CPU statistics support



commit 45bb8868ef21459b266919fbbda98f2256295a0f
Author:     Jahan Murudi <jahan.murudi.zg@xxxxxxxxxxx>
AuthorDate: Mon Aug 4 18:36:43 2025 +0530
Commit:     Anthony PERARD <anthony.perard@xxxxxxxxxx>
CommitDate: Thu Sep 4 14:30:53 2025 +0200

    tools/xentop: Add physical CPU statistics support
    
    Introduce a new '-p/--pcpus' flag to display physical CPU utilization 
metrics
    using xc_interface. This provides hypervisor-level CPU usage insights 
alongside
    existing domain statistics. This helps correlate VM resource usage with 
host CPU
    load patterns.
    
    Changes:
    - Add pcpu.c/pcpu.h for PCPU stat collection logic
    - Link against libxenctrl for xc_handle access
    - Extend CLI with '-p' flag and output formatting
    - Forward declare xenstat_handle to access xc_handle
    - Include cleanup for PCPU resources in exit handler
    
    Example usage:
      xentop -p  # Shows physical CPU stats
      xentop -bp # Batch mode
      xentop -d 1 -p # With different delays
    
    Example output with '-p':
      NAME      STATE   CPU(%)  MEM(%)  VCPUS ...
      Domain-0  -----r    17.0     6.3      8
      DomD      -----r   767.0    38.1      8
    
      Physical CPU Usage:
      â??â??â??â??â??â??â??â??â?¬â??â??â??â??â??â??â??â??â??
      â?? Core  â?? Usage  â??
      â??â??â??â??â??â??â??â??â?¼â??â??â??â??â??â??â??â??â?¤
      â?? 0     â??  98.1% â??
      â?? ...   â??  ...   â??
      â?? 7     â??  97.3% â??
      â??â??â??â??â??â??â??â??â?´â??â??â??â??â??â??â??â??â??
    
    Signed-off-by: Jahan Murudi <jahan.murudi.zg@xxxxxxxxxxx>
    Reviewed-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
 tools/xentop/Makefile |   5 +-
 tools/xentop/pcpu.c   | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/xentop/pcpu.h   |  17 ++++++
 tools/xentop/xentop.c |  79 +++++++++++++++++++++-------
 4 files changed, 222 insertions(+), 20 deletions(-)

diff --git a/tools/xentop/Makefile b/tools/xentop/Makefile
index 70cc2211c5..f514a6f7a8 100644
--- a/tools/xentop/Makefile
+++ b/tools/xentop/Makefile
@@ -15,6 +15,7 @@ include $(XEN_ROOT)/tools/Rules.mk
 
 CFLAGS += -DGCC_PRINTF $(CFLAGS_libxenstat)
 LDLIBS += $(LDLIBS_libxenstat) $(CURSES_LIBS) $(TINFO_LIBS) $(SOCKET_LIBS) -lm
+LDLIBS += $(LDLIBS_libxenctrl)
 CFLAGS += -DHOST_$(XEN_OS)
 
 # Include configure output (config.h)
@@ -25,8 +26,8 @@ TARGETS := xentop
 .PHONY: all
 all: $(TARGETS)
 
-xentop: xentop.o
-       $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS) $(APPEND_LDFLAGS)
+xentop: xentop.o pcpu.o
+       $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(APPEND_LDFLAGS)
 
 .PHONY: install
 install: all
diff --git a/tools/xentop/pcpu.c b/tools/xentop/pcpu.c
new file mode 100644
index 0000000000..cdb4cb2131
--- /dev/null
+++ b/tools/xentop/pcpu.c
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2025 Renesas Electronics Corporation
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <xenctrl.h>
+#include "pcpu.h"
+
+#define MAX_PCPUS 128
+
+typedef struct {
+    float usage_pct;
+} pcpu_stat_t;
+
+static pcpu_stat_t *pcpu_stats = NULL;
+static uint64_t *prev_idle = NULL;
+static int allocated_pcpus = 0;
+static xc_interface *xc_handle = NULL;
+static uint64_t prev_global_time = 0;
+
+static void report_pcpu_error(const char *context)
+{
+    fprintf(stderr, "PCPU error: %s (%s)\n", context, strerror(errno));
+}
+
+int update_pcpu_stats(const struct timeval *now, unsigned int delay_sec)
+{
+    struct xen_sysctl_cpuinfo info[MAX_PCPUS];
+    int detected_cpus = 0;
+    int ret, i;
+    uint64_t current_time = (uint64_t)now->tv_sec * 1000000ULL + now->tv_usec;
+    uint64_t time_diff;
+
+    if (!xc_handle) {
+        xc_handle = xc_interface_open(NULL, NULL, 0);
+        if (!xc_handle) {
+            report_pcpu_error("xc_interface_open failed");
+            return -1;
+        }
+    }
+
+    ret = xc_getcpuinfo(xc_handle, MAX_PCPUS, info, &detected_cpus);
+    if (ret < 0) {
+        report_pcpu_error("xc_getcpuinfo failed");
+        return -1;
+    }
+
+    /* Allocate/reallocate memory if needed */
+    if (!pcpu_stats || detected_cpus > allocated_pcpus) {
+        pcpu_stat_t *new_stats = realloc(pcpu_stats,
+                        detected_cpus * sizeof(*pcpu_stats));
+        if (!new_stats) goto alloc_error;
+
+        pcpu_stats = new_stats;
+
+        uint64_t *new_prev_idle = realloc(prev_idle,
+                        detected_cpus * sizeof(*prev_idle));
+        if (!new_prev_idle) goto alloc_error;
+
+        prev_idle = new_prev_idle;
+        allocated_pcpus = detected_cpus;
+
+        /* Initialize new entries */
+        for (i = 0; i < detected_cpus; i++) {
+            prev_idle[i] = info[i].idletime / 1000; /* ns->us */
+            pcpu_stats[i].usage_pct = 0.0;
+        }
+
+        /* Set initial global time reference */
+        prev_global_time = current_time;
+        return 0;
+    }
+
+    /* Calculate time difference since last update */
+    time_diff = current_time - prev_global_time;
+
+    /* Calculate CPU usage for each core */
+    for (i = 0; i < detected_cpus; i++) {
+        uint64_t current_idle = info[i].idletime / 1000;
+        uint64_t idle_diff = current_idle - prev_idle[i];
+
+        if (time_diff > 0) {
+            double usage = 100.0 * (1.0 - ((double)idle_diff / time_diff));
+            /* Clamp between 0-100% */
+            pcpu_stats[i].usage_pct = (usage < 0) ? 0.0 :
+                                     (usage > 100) ? 100.0 : usage;
+        } else {
+            pcpu_stats[i].usage_pct = 0.0;
+        }
+
+        prev_idle[i] = current_idle;
+    }
+
+    /* Update global time reference for next calculation */
+    prev_global_time = current_time;
+
+    return 0;
+
+alloc_error:
+    free_pcpu_stats();
+    errno = ENOMEM;
+    report_pcpu_error("memory allocation failed");
+    return -1;
+}
+
+/* Accessor functions for xentop.c */
+int get_pcpu_count(void)
+{
+    return allocated_pcpus;
+}
+
+float get_pcpu_usage(int cpu_index)
+{
+    if (!pcpu_stats || cpu_index < 0 || cpu_index >= allocated_pcpus) {
+        return 0.0;
+    }
+    return pcpu_stats[cpu_index].usage_pct;
+}
+
+int has_pcpu_data(void)
+{
+    return (pcpu_stats != NULL && allocated_pcpus > 0);
+}
+
+void free_pcpu_stats(void)
+{
+    if (xc_handle) {
+        xc_interface_close(xc_handle);
+        xc_handle = NULL;
+    }
+    free(pcpu_stats);
+    pcpu_stats = NULL;
+    free(prev_idle);
+    prev_idle = NULL;
+    allocated_pcpus = 0;
+}
diff --git a/tools/xentop/pcpu.h b/tools/xentop/pcpu.h
new file mode 100644
index 0000000000..a528177476
--- /dev/null
+++ b/tools/xentop/pcpu.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2025 Renesas Electronics Corporation
+ */
+
+#ifndef __XENTOP_PCPU_H__
+#define __XENTOP_PCPU_H__
+
+#include <sys/time.h>
+
+int update_pcpu_stats(const struct timeval *now, unsigned int delay);
+int get_pcpu_count(void);
+float get_pcpu_usage(int cpu_index);
+int has_pcpu_data(void);
+void free_pcpu_stats(void);
+
+#endif /* __XENTOP_PCPU_H__ */
diff --git a/tools/xentop/xentop.c b/tools/xentop/xentop.c
index f5d6c19cf9..addb1c70c9 100644
--- a/tools/xentop/xentop.c
+++ b/tools/xentop/xentop.c
@@ -37,6 +37,7 @@
 #endif
 
 #include <xenstat.h>
+#include "pcpu.h"
 
 #define XENTOP_VERSION "1.0"
 
@@ -205,6 +206,7 @@ field_id sort_field = FIELD_DOMID;
 unsigned int first_domain_index = 0;
 unsigned int delay = 3;
 unsigned int batch = 0;
+static unsigned int show_pcpus = 0;
 unsigned int loop = 1;
 unsigned int iterations = 0;
 int show_vcpus = 0;
@@ -230,22 +232,23 @@ static WINDOW *cwin;
 /* Print usage message, using given program name */
 static void usage(const char *program)
 {
-       printf("Usage: %s [OPTION]\n"
-              "Displays ongoing information about xen vm resources \n\n"
-              "-h, --help           display this help and exit\n"
-              "-V, --version        output version information and exit\n"
-              "-d, --delay=SECONDS  seconds between updates (default 3)\n"
-              "-n, --networks       output vif network data\n"
-              "-x, --vbds           output vbd block device data\n"
-              "-r, --repeat-header  repeat table header before each domain\n"
-              "-v, --vcpus          output vcpu data\n"
-              "-b, --batch          output in batch mode, no user input 
accepted\n"
-              "-i, --iterations     number of iterations before exiting\n"
-              "-f, --full-name      output the full domain name (not 
truncated)\n"
-              "-z, --dom0-first     display dom0 first (ignore sorting)\n"
-              "\n" XENTOP_BUGSTO,
-              program);
-       return;
+    printf("Usage: %s [OPTION]\n"
+           "Displays ongoing information about xen vm resources \n\n"
+           "-h, --help           display this help and exit\n"
+           "-V, --version        output version information and exit\n"
+           "-d, --delay=SECONDS  seconds between updates (default 3)\n"
+           "-n, --networks       output vif network data\n"
+           "-x, --vbds           output vbd block device data\n"
+           "-r, --repeat-header  repeat table header before each domain\n"
+           "-v, --vcpus          output vcpu data\n"
+           "-b, --batch          output in batch mode, no user input 
accepted\n"
+           "-p, --pcpus          show physical CPU stats\n"
+           "-i, --iterations     number of iterations before exiting\n"
+           "-f, --full-name      output the full domain name (not truncated)\n"
+           "-z, --dom0-first     display dom0 first (ignore sorting)\n"
+           "\n" XENTOP_BUGSTO,
+           program);
+    return;
 }
 
 /* Print program version information */
@@ -267,6 +270,8 @@ static void cleanup(void)
                xenstat_free_node(cur_node);
        if(xhandle != NULL)
                xenstat_uninit(xhandle);
+
+       free_pcpu_stats();
 }
 
 /* Display the given message and gracefully exit */
@@ -313,6 +318,32 @@ static void print(const char *fmt, ...)
        }
 }
 
+/* PCPU statistics display function */
+static void print_pcpu_stats_display(void)
+{
+    int i;
+    int num_cpus;
+
+    if (!has_pcpu_data()) {
+        print("\nNo PCPU data available\n");
+        return;
+    }
+
+    num_cpus = get_pcpu_count();
+
+    /* Use the existing print() function which handles cursor bounds */
+    print("\nPhysical CPU Usage:\n");
+    print("+-------+--------+\n");
+    print("| Core  | Usage  |\n");
+    print("+-------+--------+\n");
+
+    for (i = 0; i < num_cpus; i++) {
+        print("| %-5d | %5.1f%% |\n", i, get_pcpu_usage(i));
+    }
+
+    print("+-------+--------+\n");
+}
+
 static void xentop_attron(int attr)
 {
        if (!batch)
@@ -1245,6 +1276,14 @@ static void top(void)
                        do_vbd(domains[i]);
        }
 
+    if (show_pcpus) {
+        if (update_pcpu_stats(&curtime, delay) == 0) {
+            print_pcpu_stats_display();
+        } else {
+            fail("Error getting PCPU stats\n");
+        }
+    }
+
        if (!batch)
                do_bottom_line();
 
@@ -1271,13 +1310,14 @@ int main(int argc, char **argv)
                { "repeat-header", no_argument,       NULL, 'r' },
                { "vcpus",         no_argument,       NULL, 'v' },
                { "delay",         required_argument, NULL, 'd' },
-               { "batch",         no_argument,       NULL, 'b' },
+               { "batch",         no_argument,       NULL, 'b' },
+               { "pcpus",         no_argument,       NULL, 'p' },
                { "iterations",    required_argument, NULL, 'i' },
                { "full-name",     no_argument,       NULL, 'f' },
                { "dom0-first",    no_argument,       NULL, 'z' },
                { 0, 0, 0, 0 },
        };
-       const char *sopts = "hVnxrvd:bi:fz";
+       const char *sopts = "hVnxrvd:bpi:fz";
 
        if (atexit(cleanup) != 0)
                fail("Failed to install cleanup handler.\n");
@@ -1312,6 +1352,9 @@ int main(int argc, char **argv)
                case 'b':
                        batch = 1;
                        break;
+               case 'p':
+                       show_pcpus = 1;
+                       break;
                case 'i':
                        iterations = atoi(optarg);
                        loop = 0;
--
generated by git-patchbot for /home/xen/git/xen.git#staging



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.