@@ -51,6 +51,7 @@ TARGETS_COPY += xenpvnetboot
# Everything which needs to be built
TARGETS_BUILD := $(filter-out $(TARGETS_COPY),$(TARGETS_ALL))
+TARGETS_BUILD += xen-vcpus-stats
# ... including build-only targets
TARGETS_BUILD += $(TARGETS_BUILD-y)
@@ -139,4 +140,9 @@ xencov: xencov.o
xen-ucode: xen-ucode.o
$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS)
+xen-vcpus-stats.o: CFLAGS += $(CFLAGS_libxenforeginmemory)
+
+xen-vcpus-stats: xen-vcpus-stats.o
+ $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(LDLIBS_libxenforeignmemory) $(APPEND_LDFLAGS)
+
-include $(DEPS_INCLUDE)
new file mode 100644
@@ -0,0 +1,132 @@
+#include <err.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <signal.h>
+
+#include <xenctrl.h>
+#include <xenforeignmemory.h>
+#include <xen/vcpu.h>
+
+/*
+ * Note that virt_*() is used when ordering is required between the hypevisor
+ * and the tool domain. This tool is meant to be arch-agnostic so add the
+ * corresponding barrier for each architecture.
+ *
+ */
+#if defined(__x86_64__)
+#define barrier() asm volatile("" ::: "memory")
+#define virt_rmb() barrier()
+#elif defined(__aarch64__)
+#define dmb(opt) asm volatile("dmb " #opt : : : "memory")
+#define virt_rmb() dmb(ishld)
+#else
+#error Please fill in barrier macros
+#endif
+
+static sig_atomic_t interrupted;
+static void close_handler(int signum)
+{
+ interrupted = 1;
+}
+
+int main(int argc, char **argv)
+{
+ xenforeignmemory_handle *fh;
+ xenforeignmemory_resource_handle *res;
+ size_t size;
+ int rc, domid, period, vcpu;
+ xen_vcpu_shmemstats_t *info_shmem;
+ xen_shared_vcpustats_t *info;
+ struct sigaction act;
+ uint32_t seq;
+ uint64_t value;
+
+ if ( argc != 4 )
+ {
+ fprintf(stderr, "Usage: %s <domid> <vcpu> <period>\n", argv[0]);
+ return 1;
+ }
+
+ domid = atoi(argv[1]);
+ vcpu = atoi(argv[2]);
+ period = atoi(argv[3]);
+
+ act.sa_handler = close_handler;
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGALRM, &act, NULL);
+
+ fh = xenforeignmemory_open(NULL, 0);
+
+ if ( !fh )
+ err(1, "xenforeignmemory_open");
+
+ rc = xenforeignmemory_resource_size(
+ fh, domid, XENMEM_resource_stats_table,
+ XENMEM_resource_stats_table_id_vcpustats, &size);
+
+ if ( rc )
+ err(1, "Fail: Get size");
+
+ res = xenforeignmemory_map_resource(
+ fh, domid, XENMEM_resource_stats_table,
+ XENMEM_resource_stats_table_id_vcpustats, 0, size >> XC_PAGE_SHIFT,
+ (void **)&info_shmem, PROT_READ, 0);
+
+ if ( !res )
+ err(1, "Fail: Map");
+
+ if ( info_shmem->magic != VCPU_STATS_MAGIC )
+ {
+ fprintf(stderr, "Wrong magic number\n");
+ return 1;
+ }
+
+ if ( offsetof(struct vcpu_stats, runstate_running_time) > info_shmem->size )
+ {
+ fprintf(stderr, "The counter is not produced\n");
+ return 1;
+ }
+
+ info = (xen_shared_vcpustats_t*)((void*)info_shmem
+ + info_shmem->offset
+ + info_shmem->size * vcpu);
+
+ if ( info->runstate_running_time & ((uint64_t)1 << 63) )
+ {
+ fprintf(stderr, "The counter is inactived or has overflowed\n");
+ return 1;
+ }
+
+ while ( !interrupted )
+ {
+ sleep(period);
+ do {
+ seq = info[vcpu].seq;
+ virt_rmb();
+ value = info[vcpu].runstate_running_time;
+ virt_rmb();
+ } while ( (info[vcpu].seq & 1) ||
+ (seq != info[vcpu].seq) );
+ if ( value & ((uint64_t)1 << 63) )
+ break;
+ printf("running_vcpu_time[%d]: %ld\n", vcpu, value);
+ }
+
+ rc = xenforeignmemory_unmap_resource(fh, res);
+ if ( rc )
+ err(1, "Fail: Unmap");
+
+ rc = xenforeignmemory_close(fh);
+ if ( rc )
+ err(1, "Fail: Close");
+
+ return 0;
+}
Add a demonstration tool that uses the stats_table resource to query vcpus' RUNSTATE_running counter for a DomU. Signed-off-by: Matias Ezequiel Vara Larsen <matias.vara@vates.fr> --- Changes in v3: - use memory layout as discussed at https://lists.xenproject.org/archives/html/xen-devel/2023-03/msg00383.html - use virt_*() - issue xenforeignmemory_close() Changes in v2: - use period instead of frec - rely on version to ensure reading is coherent Changes in v1: - change the name of the tool to xen-vcpus-stats - set command line parameters in the same order that are passed - remove header libs.h - build by default - remove errno, strerrno, "\n", and identation - use errx when errno is not needed - address better the number of pages requested and error msgs - use the shared_vcpustatspage_t structure - use the correct frame id when requesting the resource --- tools/misc/Makefile | 6 ++ tools/misc/xen-vcpus-stats.c | 132 +++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 tools/misc/xen-vcpus-stats.c