Skip to content

Commit 5f14154

Browse files
Boris OstrovskyDavid Vrabel
authored andcommitted
xen/PMU: Sysfs interface for setting Xen PMU mode
Set Xen's PMU mode via /sys/hypervisor/pmu/pmu_mode. Add XENPMU hypercall. Signed-off-by: Boris Ostrovsky <[email protected]> Reviewed-by: Konrad Rzeszutek Wilk <[email protected]> Signed-off-by: David Vrabel <[email protected]>
1 parent a11f4f0 commit 5f14154

File tree

7 files changed

+228
-1
lines changed

7 files changed

+228
-1
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
What: /sys/hypervisor/pmu/pmu_mode
2+
Date: August 2015
3+
KernelVersion: 4.3
4+
Contact: Boris Ostrovsky <[email protected]>
5+
Description:
6+
Describes mode that Xen's performance-monitoring unit (PMU)
7+
uses. Accepted values are
8+
"off" -- PMU is disabled
9+
"self" -- The guest can profile itself
10+
"hv" -- The guest can profile itself and, if it is
11+
privileged (e.g. dom0), the hypervisor
12+
"all" -- The guest can profile itself, the hypervisor
13+
and all other guests. Only available to
14+
privileged guests.
15+
16+
What: /sys/hypervisor/pmu/pmu_features
17+
Date: August 2015
18+
KernelVersion: 4.3
19+
Contact: Boris Ostrovsky <[email protected]>
20+
Description:
21+
Describes Xen PMU features (as an integer). A set bit indicates
22+
that the corresponding feature is enabled. See
23+
include/xen/interface/xenpmu.h for available features

arch/x86/include/asm/xen/hypercall.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,12 @@ HYPERVISOR_tmem_op(
465465
return _hypercall1(int, tmem_op, op);
466466
}
467467

468+
static inline int
469+
HYPERVISOR_xenpmu_op(unsigned int op, void *arg)
470+
{
471+
return _hypercall2(int, xenpmu_op, op, arg);
472+
}
473+
468474
static inline void
469475
MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set)
470476
{

arch/x86/xen/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ config XEN
77
depends on PARAVIRT
88
select PARAVIRT_CLOCK
99
select XEN_HAVE_PVMMU
10+
select XEN_HAVE_VPMU
1011
depends on X86_64 || (X86_32 && X86_PAE)
1112
depends on X86_TSC
1213
help

drivers/xen/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,4 +288,7 @@ config XEN_SYMS
288288
Exports hypervisor symbols (along with their types and addresses) via
289289
/proc/xen/xensyms file, similar to /proc/kallsyms
290290

291+
config XEN_HAVE_VPMU
292+
bool
293+
291294
endmenu

drivers/xen/sys-hypervisor.c

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include <xen/xenbus.h>
2121
#include <xen/interface/xen.h>
2222
#include <xen/interface/version.h>
23+
#ifdef CONFIG_XEN_HAVE_VPMU
24+
#include <xen/interface/xenpmu.h>
25+
#endif
2326

2427
#define HYPERVISOR_ATTR_RO(_name) \
2528
static struct hyp_sysfs_attr _name##_attr = __ATTR_RO(_name)
@@ -368,6 +371,126 @@ static void xen_properties_destroy(void)
368371
sysfs_remove_group(hypervisor_kobj, &xen_properties_group);
369372
}
370373

374+
#ifdef CONFIG_XEN_HAVE_VPMU
375+
struct pmu_mode {
376+
const char *name;
377+
uint32_t mode;
378+
};
379+
380+
static struct pmu_mode pmu_modes[] = {
381+
{"off", XENPMU_MODE_OFF},
382+
{"self", XENPMU_MODE_SELF},
383+
{"hv", XENPMU_MODE_HV},
384+
{"all", XENPMU_MODE_ALL}
385+
};
386+
387+
static ssize_t pmu_mode_store(struct hyp_sysfs_attr *attr,
388+
const char *buffer, size_t len)
389+
{
390+
int ret;
391+
struct xen_pmu_params xp;
392+
int i;
393+
394+
for (i = 0; i < ARRAY_SIZE(pmu_modes); i++) {
395+
if (strncmp(buffer, pmu_modes[i].name, len - 1) == 0) {
396+
xp.val = pmu_modes[i].mode;
397+
break;
398+
}
399+
}
400+
401+
if (i == ARRAY_SIZE(pmu_modes))
402+
return -EINVAL;
403+
404+
xp.version.maj = XENPMU_VER_MAJ;
405+
xp.version.min = XENPMU_VER_MIN;
406+
ret = HYPERVISOR_xenpmu_op(XENPMU_mode_set, &xp);
407+
if (ret)
408+
return ret;
409+
410+
return len;
411+
}
412+
413+
static ssize_t pmu_mode_show(struct hyp_sysfs_attr *attr, char *buffer)
414+
{
415+
int ret;
416+
struct xen_pmu_params xp;
417+
int i;
418+
uint32_t mode;
419+
420+
xp.version.maj = XENPMU_VER_MAJ;
421+
xp.version.min = XENPMU_VER_MIN;
422+
ret = HYPERVISOR_xenpmu_op(XENPMU_mode_get, &xp);
423+
if (ret)
424+
return ret;
425+
426+
mode = (uint32_t)xp.val;
427+
for (i = 0; i < ARRAY_SIZE(pmu_modes); i++) {
428+
if (mode == pmu_modes[i].mode)
429+
return sprintf(buffer, "%s\n", pmu_modes[i].name);
430+
}
431+
432+
return -EINVAL;
433+
}
434+
HYPERVISOR_ATTR_RW(pmu_mode);
435+
436+
static ssize_t pmu_features_store(struct hyp_sysfs_attr *attr,
437+
const char *buffer, size_t len)
438+
{
439+
int ret;
440+
uint32_t features;
441+
struct xen_pmu_params xp;
442+
443+
ret = kstrtou32(buffer, 0, &features);
444+
if (ret)
445+
return ret;
446+
447+
xp.val = features;
448+
xp.version.maj = XENPMU_VER_MAJ;
449+
xp.version.min = XENPMU_VER_MIN;
450+
ret = HYPERVISOR_xenpmu_op(XENPMU_feature_set, &xp);
451+
if (ret)
452+
return ret;
453+
454+
return len;
455+
}
456+
457+
static ssize_t pmu_features_show(struct hyp_sysfs_attr *attr, char *buffer)
458+
{
459+
int ret;
460+
struct xen_pmu_params xp;
461+
462+
xp.version.maj = XENPMU_VER_MAJ;
463+
xp.version.min = XENPMU_VER_MIN;
464+
ret = HYPERVISOR_xenpmu_op(XENPMU_feature_get, &xp);
465+
if (ret)
466+
return ret;
467+
468+
return sprintf(buffer, "0x%x\n", (uint32_t)xp.val);
469+
}
470+
HYPERVISOR_ATTR_RW(pmu_features);
471+
472+
static struct attribute *xen_pmu_attrs[] = {
473+
&pmu_mode_attr.attr,
474+
&pmu_features_attr.attr,
475+
NULL
476+
};
477+
478+
static const struct attribute_group xen_pmu_group = {
479+
.name = "pmu",
480+
.attrs = xen_pmu_attrs,
481+
};
482+
483+
static int __init xen_pmu_init(void)
484+
{
485+
return sysfs_create_group(hypervisor_kobj, &xen_pmu_group);
486+
}
487+
488+
static void xen_pmu_destroy(void)
489+
{
490+
sysfs_remove_group(hypervisor_kobj, &xen_pmu_group);
491+
}
492+
#endif
493+
371494
static int __init hyper_sysfs_init(void)
372495
{
373496
int ret;
@@ -390,7 +513,15 @@ static int __init hyper_sysfs_init(void)
390513
ret = xen_properties_init();
391514
if (ret)
392515
goto prop_out;
393-
516+
#ifdef CONFIG_XEN_HAVE_VPMU
517+
if (xen_initial_domain()) {
518+
ret = xen_pmu_init();
519+
if (ret) {
520+
xen_properties_destroy();
521+
goto prop_out;
522+
}
523+
}
524+
#endif
394525
goto out;
395526

396527
prop_out:
@@ -407,6 +538,9 @@ static int __init hyper_sysfs_init(void)
407538

408539
static void __exit hyper_sysfs_exit(void)
409540
{
541+
#ifdef CONFIG_XEN_HAVE_VPMU
542+
xen_pmu_destroy();
543+
#endif
410544
xen_properties_destroy();
411545
xen_compilation_destroy();
412546
xen_sysfs_uuid_destroy();

include/xen/interface/xen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
#define __HYPERVISOR_kexec_op 37
8181
#define __HYPERVISOR_tmem_op 38
8282
#define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */
83+
#define __HYPERVISOR_xenpmu_op 40
8384

8485
/* Architecture-specific hypercall definitions. */
8586
#define __HYPERVISOR_arch_0 48

include/xen/interface/xenpmu.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#ifndef __XEN_PUBLIC_XENPMU_H__
2+
#define __XEN_PUBLIC_XENPMU_H__
3+
4+
#include "xen.h"
5+
6+
#define XENPMU_VER_MAJ 0
7+
#define XENPMU_VER_MIN 1
8+
9+
/*
10+
* ` enum neg_errnoval
11+
* ` HYPERVISOR_xenpmu_op(enum xenpmu_op cmd, struct xenpmu_params *args);
12+
*
13+
* @cmd == XENPMU_* (PMU operation)
14+
* @args == struct xenpmu_params
15+
*/
16+
/* ` enum xenpmu_op { */
17+
#define XENPMU_mode_get 0 /* Also used for getting PMU version */
18+
#define XENPMU_mode_set 1
19+
#define XENPMU_feature_get 2
20+
#define XENPMU_feature_set 3
21+
#define XENPMU_init 4
22+
#define XENPMU_finish 5
23+
24+
/* ` } */
25+
26+
/* Parameters structure for HYPERVISOR_xenpmu_op call */
27+
struct xen_pmu_params {
28+
/* IN/OUT parameters */
29+
struct {
30+
uint32_t maj;
31+
uint32_t min;
32+
} version;
33+
uint64_t val;
34+
35+
/* IN parameters */
36+
uint32_t vcpu;
37+
uint32_t pad;
38+
};
39+
40+
/* PMU modes:
41+
* - XENPMU_MODE_OFF: No PMU virtualization
42+
* - XENPMU_MODE_SELF: Guests can profile themselves
43+
* - XENPMU_MODE_HV: Guests can profile themselves, dom0 profiles
44+
* itself and Xen
45+
* - XENPMU_MODE_ALL: Only dom0 has access to VPMU and it profiles
46+
* everyone: itself, the hypervisor and the guests.
47+
*/
48+
#define XENPMU_MODE_OFF 0
49+
#define XENPMU_MODE_SELF (1<<0)
50+
#define XENPMU_MODE_HV (1<<1)
51+
#define XENPMU_MODE_ALL (1<<2)
52+
53+
/*
54+
* PMU features:
55+
* - XENPMU_FEATURE_INTEL_BTS: Intel BTS support (ignored on AMD)
56+
*/
57+
#define XENPMU_FEATURE_INTEL_BTS 1
58+
59+
#endif /* __XEN_PUBLIC_XENPMU_H__ */

0 commit comments

Comments
 (0)