mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-06-16 02:15:47 +00:00
kvm tools: Add 'kvm stat' command
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@gmail.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -10,3 +10,4 @@ kvm-list common
|
||||
kvm-debug common
|
||||
kvm-balloon common
|
||||
kvm-stop common
|
||||
kvm-stat common
|
||||
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 },
|
||||
|
||||
+104
-4
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user