From: Sasha Levin <levinsasha928@gmail.com>
To: penberg@kernel.org
Cc: mingo@elte.hu, asias.hejun@gmail.com, prasadjoshi124@gmail.com,
gorcunov@gmail.com, kvm@vger.kernel.org,
Sasha Levin <levinsasha928@gmail.com>
Subject: [PATCH] kvm tools: Add 'kvm memstat' command
Date: Mon, 15 Aug 2011 14:53:42 +0300 [thread overview]
Message-ID: <1313409222-3910-1-git-send-email-levinsasha928@gmail.com> (raw)
This patch adds 'kvm memstat' command that allows retrieving memory statistics out of
a running guest using the virtio-balloon stats vq interface.
Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
tools/kvm/Documentation/kvm-memstat.txt | 16 +++++
tools/kvm/Makefile | 1 +
tools/kvm/builtin-memstat.c | 69 ++++++++++++++++++++
tools/kvm/command-list.txt | 1 +
tools/kvm/include/kvm/builtin-memstat.h | 7 ++
tools/kvm/include/kvm/kvm.h | 1 +
tools/kvm/kvm-cmd.c | 2 +
tools/kvm/virtio/balloon.c | 108 +++++++++++++++++++++++++++++-
8 files changed, 201 insertions(+), 4 deletions(-)
create mode 100644 tools/kvm/Documentation/kvm-memstat.txt
create mode 100644 tools/kvm/builtin-memstat.c
create mode 100644 tools/kvm/include/kvm/builtin-memstat.h
diff --git a/tools/kvm/Documentation/kvm-memstat.txt b/tools/kvm/Documentation/kvm-memstat.txt
new file mode 100644
index 0000000..0562d33
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-memstat.txt
@@ -0,0 +1,16 @@
+kvm-memstat(1)
+================
+
+NAME
+----
+kvm-memstat - Print memory statistics about a running instance
+
+SYNOPSIS
+--------
+[verse]
+'kvm memstat [-n instance] [-p instance pid] [--all]'
+
+DESCRIPTION
+-----------
+The command prints memory statistics about a running instance.
+For a list of running instances see 'kvm list'.
diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index 3a06e10..ce68b8c 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-memstat.o
OBJS += builtin-pause.o
OBJS += builtin-resume.o
OBJS += builtin-run.o
diff --git a/tools/kvm/builtin-memstat.c b/tools/kvm/builtin-memstat.c
new file mode 100644
index 0000000..d32d97a
--- /dev/null
+++ b/tools/kvm/builtin-memstat.c
@@ -0,0 +1,69 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-memstat.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+static bool all;
+static u64 instance_pid;
+static const char *instance_name;
+
+static const char * const memstat_usage[] = {
+ "kvm memstat [--all] [-n name] [-p pid]",
+ NULL
+};
+
+static const struct option memstat_options[] = {
+ OPT_GROUP("General options:"),
+ OPT_BOOLEAN('a', "all", &all, "Memstat all instances"),
+ OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+ OPT_U64('p', "pid", &instance_pid, "Instance pid"),
+ OPT_END()
+};
+
+static void parse_memstat_options(int argc, const char **argv)
+{
+ while (argc != 0) {
+ argc = parse_options(argc, argv, memstat_options, memstat_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ if (argc != 0)
+ kvm_memstat_help();
+ }
+}
+
+void kvm_memstat_help(void)
+{
+ usage_with_options(memstat_usage, memstat_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_memstat(int argc, const char **argv, const char *prefix)
+{
+ parse_memstat_options(argc, argv);
+
+ if (all)
+ return kvm__enumerate_instances(do_memstat);
+
+ if (instance_name == NULL &&
+ instance_pid == 0)
+ kvm_memstat_help();
+
+ if (instance_name)
+ instance_pid = kvm__get_pid_by_instance(instance_name);
+
+ if (instance_pid <= 0)
+ die("Failed locating instance");
+
+ printf("Sending memstat command to designated instance, output should be on the targets' terminal.\n");
+
+ return kill(instance_pid, SIGKVMMEMSTAT);
+}
diff --git a/tools/kvm/command-list.txt b/tools/kvm/command-list.txt
index 6a49d0a..78f2dcf 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-memstat common
diff --git a/tools/kvm/include/kvm/builtin-memstat.h b/tools/kvm/include/kvm/builtin-memstat.h
new file mode 100644
index 0000000..eb355ee
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-memstat.h
@@ -0,0 +1,7 @@
+#ifndef KVM__MEMSTAT_H
+#define KVM__MEMSTAT_H
+
+int kvm_cmd_memstat(int argc, const char **argv, const char *prefix);
+void kvm_memstat_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..09e1825 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-memstat.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 },
+ { "memstat", kvm_cmd_memstat, kvm_memstat_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);
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
next reply other threads:[~2011-08-15 11:54 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-08-15 11:53 Sasha Levin [this message]
2011-08-15 11:56 ` [PATCH] kvm tools: Add 'kvm memstat' command Pekka Enberg
2011-08-15 12:02 ` Sasha Levin
2011-08-15 12:06 ` Pekka Enberg
2011-08-16 5:01 ` Asias He
2011-08-19 0:46 ` Neo Jia
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1313409222-3910-1-git-send-email-levinsasha928@gmail.com \
--to=levinsasha928@gmail.com \
--cc=asias.hejun@gmail.com \
--cc=gorcunov@gmail.com \
--cc=kvm@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=penberg@kernel.org \
--cc=prasadjoshi124@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox