vmm_stat.c revision 267216
1194246Smarius/*-
2194246Smarius * Copyright (c) 2011 NetApp, Inc.
3194246Smarius * All rights reserved.
4194246Smarius *
5194246Smarius * Redistribution and use in source and binary forms, with or without
6194246Smarius * modification, are permitted provided that the following conditions
7194246Smarius * are met:
8194246Smarius * 1. Redistributions of source code must retain the above copyright
9194246Smarius *    notice, this list of conditions and the following disclaimer.
10194246Smarius * 2. Redistributions in binary form must reproduce the above copyright
11194246Smarius *    notice, this list of conditions and the following disclaimer in the
12194246Smarius *    documentation and/or other materials provided with the distribution.
13194246Smarius *
14194246Smarius * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15194246Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16194246Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17194246Smarius * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18194246Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19194246Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20194246Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21194246Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22194246Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23194246Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24194246Smarius * SUCH DAMAGE.
25194246Smarius *
26194246Smarius * $FreeBSD: head/sys/amd64/vmm/vmm_stat.c 267216 2014-06-07 21:36:52Z neel $
27194246Smarius */
28194246Smarius
29194246Smarius#include <sys/cdefs.h>
30194246Smarius__FBSDID("$FreeBSD: head/sys/amd64/vmm/vmm_stat.c 267216 2014-06-07 21:36:52Z neel $");
31194246Smarius
32194246Smarius#include <sys/param.h>
33194246Smarius#include <sys/kernel.h>
34194246Smarius#include <sys/systm.h>
35194246Smarius#include <sys/malloc.h>
36194246Smarius#include <sys/smp.h>
37194246Smarius
38194246Smarius#include <machine/vmm.h>
39194246Smarius#include "vmm_util.h"
40194246Smarius#include "vmm_stat.h"
41194246Smarius
42194246Smarius/*
43194246Smarius * 'vst_num_elems' is the total number of addressable statistic elements
44194246Smarius * 'vst_num_types' is the number of unique statistic types
45194246Smarius *
46194246Smarius * It is always true that 'vst_num_elems' is greater than or equal to
47194246Smarius * 'vst_num_types'. This is because a stat type may represent more than
48194246Smarius * one element (for e.g. VMM_STAT_ARRAY).
49194246Smarius */
50194246Smariusstatic int vst_num_elems, vst_num_types;
51194246Smariusstatic struct vmm_stat_type *vsttab[MAX_VMM_STAT_ELEMS];
52194246Smarius
53194246Smariusstatic MALLOC_DEFINE(M_VMM_STAT, "vmm stat", "vmm stat");
54194246Smarius
55194246Smarius#define	vst_size	((size_t)vst_num_elems * sizeof(uint64_t))
56194246Smarius
57194246Smariusvoid
58194246Smariusvmm_stat_register(void *arg)
59249583Sgabor{
60194246Smarius	struct vmm_stat_type *vst = arg;
61194246Smarius
62194246Smarius	/* We require all stats to identify themselves with a description */
63194246Smarius	if (vst->desc == NULL)
64194246Smarius		return;
65194246Smarius
66194246Smarius	if (vst->scope == VMM_STAT_SCOPE_INTEL && !vmm_is_intel())
67194246Smarius		return;
68194246Smarius
69194246Smarius	if (vst->scope == VMM_STAT_SCOPE_AMD && !vmm_is_amd())
70194246Smarius		return;
71194246Smarius
72194246Smarius	if (vst_num_elems + vst->nelems >= MAX_VMM_STAT_ELEMS) {
73194246Smarius		printf("Cannot accomodate vmm stat type \"%s\"!\n", vst->desc);
74194246Smarius		return;
75194246Smarius	}
76194246Smarius
77194246Smarius	vst->index = vst_num_elems;
78194246Smarius	vst_num_elems += vst->nelems;
79194246Smarius
80194246Smarius	vsttab[vst_num_types++] = vst;
81194246Smarius}
82194246Smarius
83194246Smariusint
84194246Smariusvmm_stat_copy(struct vm *vm, int vcpu, int *num_stats, uint64_t *buf)
85194246Smarius{
86194246Smarius	int i;
87194246Smarius	uint64_t *stats;
88194246Smarius
89194246Smarius	if (vcpu < 0 || vcpu >= VM_MAXCPU)
90194246Smarius		return (EINVAL);
91194246Smarius
92194246Smarius	stats = vcpu_stats(vm, vcpu);
93194246Smarius	for (i = 0; i < vst_num_elems; i++)
94194246Smarius		buf[i] = stats[i];
95194246Smarius	*num_stats = vst_num_elems;
96194246Smarius	return (0);
97194246Smarius}
98194246Smarius
99194246Smariusvoid *
100194246Smariusvmm_stat_alloc(void)
101194246Smarius{
102194246Smarius
103194246Smarius	return (malloc(vst_size, M_VMM_STAT, M_WAITOK));
104194246Smarius}
105194246Smarius
106194246Smariusvoid
107194246Smariusvmm_stat_init(void *vp)
108194246Smarius{
109194246Smarius
110194246Smarius	bzero(vp, vst_size);
111194246Smarius}
112194246Smarius
113194246Smariusvoid
114194246Smariusvmm_stat_free(void *vp)
115194246Smarius{
116194246Smarius	free(vp, M_VMM_STAT);
117194246Smarius}
118194246Smarius
119194246Smariusint
120194246Smariusvmm_stat_desc_copy(int index, char *buf, int bufsize)
121194246Smarius{
122194246Smarius	int i;
123194246Smarius	struct vmm_stat_type *vst;
124194246Smarius
125194246Smarius	for (i = 0; i < vst_num_types; i++) {
126194246Smarius		vst = vsttab[i];
127194246Smarius		if (index >= vst->index && index < vst->index + vst->nelems) {
128194246Smarius			if (vst->nelems > 1) {
129194246Smarius				snprintf(buf, bufsize, "%s[%d]",
130194246Smarius					 vst->desc, index - vst->index);
131194246Smarius			} else {
132194246Smarius				strlcpy(buf, vst->desc, bufsize);
133194246Smarius			}
134194246Smarius			return (0);	/* found it */
135194246Smarius		}
136194246Smarius	}
137194246Smarius
138194246Smarius	return (EINVAL);
139194246Smarius}
140194246Smarius
141194904Smarius/* global statistics */
142194904SmariusVMM_STAT(VCPU_MIGRATIONS, "vcpu migration across host cpus");
143194904SmariusVMM_STAT(VMEXIT_COUNT, "total number of vm exits");
144194246SmariusVMM_STAT(VMEXIT_EXTINT, "vm exits due to external interrupt");
145194246SmariusVMM_STAT(VMEXIT_HLT, "number of times hlt was intercepted");
146194246SmariusVMM_STAT(VMEXIT_CR_ACCESS, "number of times %cr access was intercepted");
147194246SmariusVMM_STAT(VMEXIT_RDMSR, "number of times rdmsr was intercepted");
148194246SmariusVMM_STAT(VMEXIT_WRMSR, "number of times wrmsr was intercepted");
149194246SmariusVMM_STAT(VMEXIT_MTRAP, "number of monitor trap exits");
150194246SmariusVMM_STAT(VMEXIT_PAUSE, "number of times pause was intercepted");
151194246SmariusVMM_STAT(VMEXIT_INTR_WINDOW, "vm exits due to interrupt window opening");
152194246SmariusVMM_STAT(VMEXIT_NMI_WINDOW, "vm exits due to nmi window opening");
153194246SmariusVMM_STAT(VMEXIT_INOUT, "number of times in/out was intercepted");
154194246SmariusVMM_STAT(VMEXIT_CPUID, "number of times cpuid was intercepted");
155194246SmariusVMM_STAT(VMEXIT_NESTED_FAULT, "vm exits due to nested page fault");
156194246SmariusVMM_STAT(VMEXIT_INST_EMUL, "vm exits for instruction emulation");
157194246SmariusVMM_STAT(VMEXIT_UNKNOWN, "number of vm exits for unknown reason");
158194246SmariusVMM_STAT(VMEXIT_ASTPENDING, "number of times astpending at exit");
159194246SmariusVMM_STAT(VMEXIT_USERSPACE, "number of vm exits handled in userspace");
160194246SmariusVMM_STAT(VMEXIT_RENDEZVOUS, "number of times rendezvous pending at exit");
161194246SmariusVMM_STAT(VMEXIT_EXCEPTION, "number of vm exits due to exceptions");
162194246Smarius