Extend the VMM stats interface to support a dynamic count of statistics.

- Add a starting index to 'struct vmstats' and change the
  VM_STATS ioctl to fetch the 64 stats starting at that index.
  A compat shim for <= 13 continues to fetch only the first 64
  stats.

- Extend vm_get_stats() in libvmmapi to use a loop and a static
  thread local buffer which grows to hold the stats needed.

Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D27463
This commit is contained in:
John Baldwin 2022-02-07 14:11:10 -08:00
parent 3f3e4f3c74
commit 6426978617
5 changed files with 80 additions and 18 deletions

View File

@ -1066,19 +1066,44 @@ uint64_t *
vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv,
int *ret_entries)
{
int error;
static struct vm_stats vmstats;
static _Thread_local uint64_t *stats_buf;
static _Thread_local u_int stats_count;
uint64_t *new_stats;
struct vm_stats vmstats;
u_int count, index;
bool have_stats;
have_stats = false;
vmstats.cpuid = vcpu;
count = 0;
for (index = 0;; index += nitems(vmstats.statbuf)) {
vmstats.index = index;
if (ioctl(ctx->fd, VM_STATS, &vmstats) != 0)
break;
if (stats_count < index + vmstats.num_entries) {
new_stats = realloc(stats_buf,
(index + vmstats.num_entries) * sizeof(uint64_t));
if (new_stats == NULL) {
errno = ENOMEM;
return (NULL);
}
stats_count = index + vmstats.num_entries;
stats_buf = new_stats;
}
memcpy(stats_buf + index, vmstats.statbuf,
vmstats.num_entries * sizeof(uint64_t));
count += vmstats.num_entries;
have_stats = true;
error = ioctl(ctx->fd, VM_STATS, &vmstats);
if (error == 0) {
if (vmstats.num_entries != nitems(vmstats.statbuf))
break;
}
if (have_stats) {
if (ret_entries)
*ret_entries = vmstats.num_entries;
*ret_entries = count;
if (ret_tv)
*ret_tv = vmstats.tv;
return (vmstats.statbuf);
return (stats_buf);
} else
return (NULL);
}

View File

@ -174,6 +174,7 @@ struct vm_nmi {
#define MAX_VM_STATS 64
struct vm_stats {
int cpuid; /* in */
int index; /* in */
int num_entries; /* out */
struct timeval tv;
uint64_t statbuf[MAX_VM_STATS];

View File

@ -69,6 +69,18 @@ __FBSDID("$FreeBSD$");
#include "io/vhpet.h"
#include "io/vrtc.h"
#ifdef COMPAT_FREEBSD13
struct vm_stats_old {
int cpuid; /* in */
int num_entries; /* out */
struct timeval tv;
uint64_t statbuf[MAX_VM_STATS];
};
#define VM_STATS_OLD \
_IOWR('v', IOCNUM_VM_STATS, struct vm_stats_old)
#endif
struct devmem_softc {
int segid;
char *name;
@ -376,6 +388,9 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
struct vm_pptdev_msi *pptmsi;
struct vm_pptdev_msix *pptmsix;
struct vm_nmi *vmnmi;
#ifdef COMPAT_FREEBSD13
struct vm_stats_old *vmstats_old;
#endif
struct vm_stats *vmstats;
struct vm_stat_desc *statdesc;
struct vm_x2apic *x2apic;
@ -501,11 +516,21 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
statdesc->desc, sizeof(statdesc->desc));
break;
}
#ifdef COMPAT_FREEBSD13
case VM_STATS_OLD:
vmstats_old = (struct vm_stats_old *)data;
getmicrotime(&vmstats_old->tv);
error = vmm_stat_copy(sc->vm, vmstats_old->cpuid, 0,
nitems(vmstats_old->statbuf),
&vmstats_old->num_entries,
vmstats_old->statbuf);
break;
#endif
case VM_STATS: {
CTASSERT(MAX_VM_STATS >= MAX_VMM_STAT_ELEMS);
vmstats = (struct vm_stats *)data;
getmicrotime(&vmstats->tv);
error = vmm_stat_copy(sc->vm, vmstats->cpuid,
error = vmm_stat_copy(sc->vm, vmstats->cpuid, vmstats->index,
nitems(vmstats->statbuf),
&vmstats->num_entries, vmstats->statbuf);
break;
}

View File

@ -82,15 +82,29 @@ vmm_stat_register(void *arg)
}
int
vmm_stat_copy(struct vm *vm, int vcpu, int *num_stats, uint64_t *buf)
vmm_stat_copy(struct vm *vm, int vcpu, int index, int count, int *num_stats,
uint64_t *buf)
{
struct vmm_stat_type *vst;
uint64_t *stats;
int i;
int i, tocopy;
if (vcpu < 0 || vcpu >= vm_get_maxcpus(vm))
return (EINVAL);
if (index < 0 || count < 0)
return (EINVAL);
if (index > vst_num_elems)
return (ENOENT);
if (index == vst_num_elems) {
*num_stats = 0;
return (0);
}
tocopy = min(vst_num_elems - index, count);
/* Let stats functions update their counters */
for (i = 0; i < vst_num_types; i++) {
vst = vsttab[i];
@ -100,9 +114,8 @@ vmm_stat_copy(struct vm *vm, int vcpu, int *num_stats, uint64_t *buf)
/* Copy over the stats */
stats = vcpu_stats(vm, vcpu);
for (i = 0; i < vst_num_elems; i++)
buf[i] = stats[i];
*num_stats = vst_num_elems;
memcpy(buf, stats + index, tocopy * sizeof(stats[0]));
*num_stats = tocopy;
return (0);
}

View File

@ -87,10 +87,8 @@ void *vmm_stat_alloc(void);
void vmm_stat_init(void *vp);
void vmm_stat_free(void *vp);
/*
* 'buf' should be at least fit 'MAX_VMM_STAT_TYPES' entries
*/
int vmm_stat_copy(struct vm *vm, int vcpu, int *num_stats, uint64_t *buf);
int vmm_stat_copy(struct vm *vm, int vcpu, int index, int count,
int *num_stats, uint64_t *buf);
int vmm_stat_desc_copy(int index, char *buf, int buflen);
static void __inline