On Mon, Aug 15, 2011 at 05:32:59PM +0300, Sasha Levin wrote: >This patch adds 'kvm stat' command that allows retrieving statistics out of >a running guest. > >Currently the only supported statistics are memory statistics, available using the >'--memory' parameter. > >Signed-off-by: Sasha Levin <levinsasha928@xxxxxxxxx> >--- > tools/kvm/Documentation/kvm-stat.txt | 19 ++++++ > tools/kvm/Makefile | 1 + > tools/kvm/builtin-stat.c | 79 +++++++++++++++++++++++++ > tools/kvm/command-list.txt | 1 + > tools/kvm/include/kvm/builtin-stat.h | 7 ++ > tools/kvm/include/kvm/kvm.h | 1 + > tools/kvm/kvm-cmd.c | 2 + > tools/kvm/virtio/balloon.c | 108 ++++++++++++++++++++++++++++++++- > 8 files changed, 214 insertions(+), 4 deletions(-) > create mode 100644 tools/kvm/Documentation/kvm-stat.txt > create mode 100644 tools/kvm/builtin-stat.c > create mode 100644 tools/kvm/include/kvm/builtin-stat.h > >diff --git a/tools/kvm/Documentation/kvm-stat.txt b/tools/kvm/Documentation/kvm-stat.txt >new file mode 100644 >index 0000000..ce5ab54 >--- /dev/null >+++ b/tools/kvm/Documentation/kvm-stat.txt >@@ -0,0 +1,19 @@ >+kvm-stat(1) >+================ >+ >+NAME >+---- >+kvm-stat - Print statistics about a running instance >+ >+SYNOPSIS >+-------- >+[verse] >+'kvm [command] [-n instance] [-p instance pid] [--all]' >+ >+DESCRIPTION >+----------- >+The command prints statistics about a running instance. >+For a list of running instances see 'kvm list'. >+ >+Commands: >+ --memory, -m Display memory statistics >diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile >index 3a06e10..85bbce7 100644 >--- a/tools/kvm/Makefile >+++ b/tools/kvm/Makefile >@@ -24,6 +24,7 @@ OBJS += builtin-balloon.o > OBJS += builtin-debug.o > OBJS += builtin-help.o > OBJS += builtin-list.o >+OBJS += builtin-stat.o > OBJS += builtin-pause.o > OBJS += builtin-resume.o > OBJS += builtin-run.o >diff --git a/tools/kvm/builtin-stat.c b/tools/kvm/builtin-stat.c >new file mode 100644 >index 0000000..d9bc75d >--- /dev/null >+++ b/tools/kvm/builtin-stat.c >@@ -0,0 +1,79 @@ >+#include <kvm/util.h> >+#include <kvm/kvm-cmd.h> >+#include <kvm/builtin-stat.h> >+#include <kvm/kvm.h> >+#include <kvm/parse-options.h> >+ >+#include <stdio.h> >+#include <string.h> >+#include <signal.h> >+ >+static bool mem; >+static bool all; >+static u64 instance_pid; >+static const char *instance_name; >+ >+static const char * const stat_usage[] = { >+ "kvm stat [command] [--all] [-n name] [-p pid]", >+ NULL >+}; >+ >+static const struct option stat_options[] = { >+ OPT_GROUP("Commands options:"), >+ OPT_BOOLEAN('m', "memory", &mem, "Display memory statistics"), >+ OPT_GROUP("Instance options:"), >+ OPT_BOOLEAN('a', "all", &all, "All instances"), >+ OPT_STRING('n', "name", &instance_name, "name", "Instance name"), >+ OPT_U64('p', "pid", &instance_pid, "Instance pid"), >+ OPT_END() >+}; >+ >+static void parse_stat_options(int argc, const char **argv) >+{ >+ while (argc != 0) { >+ argc = parse_options(argc, argv, stat_options, stat_usage, >+ PARSE_OPT_STOP_AT_NON_OPTION); >+ if (argc != 0) >+ kvm_stat_help(); >+ } >+} >+ >+void kvm_stat_help(void) >+{ >+ usage_with_options(stat_usage, stat_options); >+} >+ >+static int do_memstat(const char *name, int pid) >+{ >+ printf("Sending memstat command to %s, output should be on the targets' terminal.\n", name); >+ return kill(pid, SIGKVMMEMSTAT); >+} >+ >+int kvm_cmd_stat(int argc, const char **argv, const char *prefix) >+{ >+ parse_stat_options(argc, argv); >+ >+ if (!mem) >+ usage_with_options(stat_usage, stat_options); >+ >+ if (mem && all) >+ return kvm__enumerate_instances(do_memstat); >+ >+ if (instance_name == NULL && >+ instance_pid == 0) >+ kvm_stat_help(); >+ >+ if (instance_name) >+ instance_pid = kvm__get_pid_by_instance(instance_name); >+ >+ if (instance_pid <= 0) >+ die("Failed locating instance"); >+ >+ if (mem) { >+ printf("Sending memstat command to designated instance, output should be on the targets' terminal.\n"); >+ >+ return kill(instance_pid, SIGKVMMEMSTAT); >+ } >+ >+ return 0; >+} >diff --git a/tools/kvm/command-list.txt b/tools/kvm/command-list.txt >index 6a49d0a..f201d75 100644 >--- a/tools/kvm/command-list.txt >+++ b/tools/kvm/command-list.txt >@@ -10,3 +10,4 @@ kvm-list common > kvm-debug common > kvm-balloon common > kvm-stop common >+kvm-stat common >diff --git a/tools/kvm/include/kvm/builtin-stat.h b/tools/kvm/include/kvm/builtin-stat.h >new file mode 100644 >index 0000000..e3ce292 >--- /dev/null >+++ b/tools/kvm/include/kvm/builtin-stat.h >@@ -0,0 +1,7 @@ >+#ifndef KVM__STAT_H >+#define KVM__STAT_H >+ >+int kvm_cmd_stat(int argc, const char **argv, const char *prefix); >+void kvm_stat_help(void); >+ >+#endif >diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h >index d4fe2a1..c2d815c 100644 >--- a/tools/kvm/include/kvm/kvm.h >+++ b/tools/kvm/include/kvm/kvm.h >@@ -22,6 +22,7 @@ > #define SIGKVMDELMEM (SIGRTMIN + 3) > #define SIGKVMSTOP (SIGRTMIN + 4) > #define SIGKVMRESUME (SIGRTMIN + 5) >+#define SIGKVMMEMSTAT (SIGRTMIN + 6) > > struct kvm { > int sys_fd; /* For system ioctls(), i.e. /dev/kvm */ >diff --git a/tools/kvm/kvm-cmd.c b/tools/kvm/kvm-cmd.c >index 4e3ea22..8fc6d22 100644 >--- a/tools/kvm/kvm-cmd.c >+++ b/tools/kvm/kvm-cmd.c >@@ -12,6 +12,7 @@ > #include "kvm/builtin-list.h" > #include "kvm/builtin-version.h" > #include "kvm/builtin-stop.h" >+#include "kvm/builtin-stat.h" > #include "kvm/builtin-help.h" > #include "kvm/kvm-cmd.h" > #include "kvm/builtin-run.h" >@@ -26,6 +27,7 @@ struct cmd_struct kvm_commands[] = { > { "version", kvm_cmd_version, NULL, 0 }, > { "--version", kvm_cmd_version, NULL, 0 }, > { "stop", kvm_cmd_stop, kvm_stop_help, 0 }, >+ { "stat", kvm_cmd_stat, kvm_stat_help, 0 }, > { "help", kvm_cmd_help, NULL, 0 }, > { "run", kvm_cmd_run, kvm_run_help, 0 }, > { NULL, NULL, NULL, 0 }, >diff --git a/tools/kvm/virtio/balloon.c b/tools/kvm/virtio/balloon.c >index 983a114..c5853a5 100644 >--- a/tools/kvm/virtio/balloon.c >+++ b/tools/kvm/virtio/balloon.c >@@ -21,10 +21,11 @@ > #include <sys/stat.h> > #include <pthread.h> > >-#define NUM_VIRT_QUEUES 2 >+#define NUM_VIRT_QUEUES 3 > #define VIRTIO_BLN_QUEUE_SIZE 128 > #define VIRTIO_BLN_INFLATE 0 > #define VIRTIO_BLN_DEFLATE 1 >+#define VIRTIO_BLN_STATS 2 > > struct bln_dev { > struct pci_device_header pci_hdr; >@@ -41,6 +42,12 @@ struct bln_dev { > struct virt_queue vqs[NUM_VIRT_QUEUES]; > struct thread_pool__job jobs[NUM_VIRT_QUEUES]; > >+ struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR]; >+ struct virtio_balloon_stat *cur_stat; >+ u32 cur_stat_head; >+ u16 stat_count; >+ int stat_waitfd; >+ > struct virtio_balloon_config config; > }; > >@@ -127,7 +134,7 @@ static bool virtio_bln_do_io_request(struct kvm *kvm, struct bln_dev *bdev, stru > if (queue == &bdev->vqs[VIRTIO_BLN_INFLATE]) { > madvise(guest_ptr, 1 << VIRTIO_BALLOON_PFN_SHIFT, MADV_DONTNEED); > bdev->config.actual++; >- } else { >+ } else if (queue == &bdev->vqs[VIRTIO_BLN_DEFLATE]) { > bdev->config.actual--; > } > } >@@ -137,10 +144,46 @@ static bool virtio_bln_do_io_request(struct kvm *kvm, struct bln_dev *bdev, stru > return true; > } > >+static bool virtio_bln_do_stat_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue) >+{ >+ struct iovec iov[VIRTIO_BLN_QUEUE_SIZE]; >+ u16 out, in, head; >+ struct virtio_balloon_stat *stat; >+ u64 wait_val = 1; >+ >+ head = virt_queue__get_iov(queue, iov, &out, &in, kvm); >+ stat = iov[0].iov_base; >+ >+ /* Initial empty stat buffer */ >+ if (bdev->cur_stat == NULL) { >+ bdev->cur_stat = stat; >+ bdev->cur_stat_head = head; >+ >+ return true; >+ } >+ >+ memcpy(bdev->stats, stat, iov[0].iov_len); >+ >+ bdev->stat_count = iov[0].iov_len / sizeof(struct virtio_balloon_stat); >+ bdev->cur_stat = stat; >+ bdev->cur_stat_head = head; >+ >+ if (write(bdev->stat_waitfd, &wait_val, sizeof(wait_val)) <= 0) >+ return -EFAULT; >+ >+ return 1; >+} >+ > static void virtio_bln_do_io(struct kvm *kvm, void *param) > { > struct virt_queue *vq = param; > >+ if (vq == &bdev.vqs[VIRTIO_BLN_STATS]) { >+ virtio_bln_do_stat_request(kvm, &bdev, vq); >+ virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm); >+ return; >+ } >+ > while (virt_queue__available(vq)) { > virtio_bln_do_io_request(kvm, &bdev, vq); > virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm); >@@ -218,15 +261,70 @@ static struct ioport_operations virtio_bln_io_ops = { > .io_out = virtio_bln_pci_io_out, > }; > >+static int virtio_bln__collect_stats(void) >+{ >+ u64 tmp; >+ >+ virt_queue__set_used_elem(&bdev.vqs[VIRTIO_BLN_STATS], bdev.cur_stat_head, >+ sizeof(struct virtio_balloon_stat)); >+ virt_queue__trigger_irq(&bdev.vqs[VIRTIO_BLN_STATS], bdev.pci_hdr.irq_line, >+ &bdev.isr, kvm); >+ >+ if (read(bdev.stat_waitfd, &tmp, sizeof(tmp)) <= 0) >+ return -EFAULT; >+ >+ return 0; >+} >+ >+static int virtio_bln__print_stats(void) >+{ >+ u16 i; >+ >+ if (virtio_bln__collect_stats() < 0) >+ return -EFAULT; >+ >+ printf("\n\n\t*** Guest memory statistics ***\n\n"); >+ for (i = 0; i < bdev.stat_count; i++) { >+ switch (bdev.stats[i].tag) { >+ case VIRTIO_BALLOON_S_SWAP_IN: >+ printf("The amount of memory that has been swapped in (in bytes):"); >+ break; >+ case VIRTIO_BALLOON_S_SWAP_OUT: >+ printf("The amount of memory that has been swapped out to disk (in bytes):"); >+ break; >+ case VIRTIO_BALLOON_S_MAJFLT: >+ printf("The number of major page faults that have occurred:"); >+ break; >+ case VIRTIO_BALLOON_S_MINFLT: >+ printf("The number of minor page faults that have occurred:"); >+ break; >+ case VIRTIO_BALLOON_S_MEMFREE: >+ printf("The amount of memory not being used for any purpose (in bytes):"); >+ break; >+ case VIRTIO_BALLOON_S_MEMTOT: >+ printf("The total amount of memory available (in bytes):"); >+ break; >+ } >+ printf("%llu\n", bdev.stats[i].val); >+ } >+ printf("\n"); >+ >+ return 0; >+} >+ > static void handle_sigmem(int sig) > { > if (sig == SIGKVMADDMEM) { > bdev.config.num_pages += 256; >- } else { >+ } else if (sig == SIGKVMDELMEM) { > if (bdev.config.num_pages < 256) > return; > > bdev.config.num_pages -= 256; >+ } else if (sig == SIGKVMMEMSTAT) { >+ virtio_bln__print_stats(); >+ >+ return; > } > > /* Notify that the configuration space has changed */ >@@ -241,6 +339,7 @@ void virtio_bln__init(struct kvm *kvm) > > signal(SIGKVMADDMEM, handle_sigmem); > signal(SIGKVMDELMEM, handle_sigmem); >+ signal(SIGKVMMEMSTAT, handle_sigmem); We also should add SIG_IGN in builtin-run for this signal. walimis > > bdev_base_addr = ioport__register(IOPORT_EMPTY, &virtio_bln_io_ops, IOPORT_SIZE, &bdev); > >@@ -262,7 +361,8 @@ void virtio_bln__init(struct kvm *kvm) > > bdev.pci_hdr.irq_pin = pin; > bdev.pci_hdr.irq_line = line; >- bdev.host_features = 0; >+ bdev.host_features = 1 << VIRTIO_BALLOON_F_STATS_VQ; >+ bdev.stat_waitfd = eventfd(0, 0); > memset(&bdev.config, 0, sizeof(struct virtio_balloon_config)); > > pci__register(&bdev.pci_hdr, dev); >-- >1.7.6 > >-- >To unsubscribe from this list: send the line "unsubscribe kvm" in >the body of a message to majordomo@xxxxxxxxxxxxxxx >More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html