mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 11:31:16 +00:00
perf: implement a set of util functions for perf event
This patch implement a set of interfaces for perf event. Based on these interfaces, we can implement internal driver API for perf, and get the results of perf conuter you care about. Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com> Message-id: 1459171833-26416-4-git-send-email-qiaowei.ren@intel.com
This commit is contained in:
parent
dd00767cbd
commit
28b446292b
@ -130,6 +130,8 @@ typedef enum {
|
||||
VIR_FROM_LOGGING = 63, /* Error from log manager */
|
||||
VIR_FROM_XENXL = 64, /* Error from Xen xl config code */
|
||||
|
||||
VIR_FROM_PERF = 65, /* Error from perf */
|
||||
|
||||
# ifdef VIR_ENUM_SENTINELS
|
||||
VIR_ERR_DOMAIN_LAST
|
||||
# endif
|
||||
|
@ -222,6 +222,7 @@ src/util/virnodesuspend.c
|
||||
src/util/virnuma.c
|
||||
src/util/virobject.c
|
||||
src/util/virpci.c
|
||||
src/util/virperf.c
|
||||
src/util/virpidfile.c
|
||||
src/util/virpolkit.c
|
||||
src/util/virportallocator.c
|
||||
|
@ -98,6 +98,7 @@ UTIL_SOURCES = \
|
||||
util/virauthconfig.c util/virauthconfig.h \
|
||||
util/virbitmap.c util/virbitmap.h \
|
||||
util/virbuffer.c util/virbuffer.h \
|
||||
util/virperf.c util/virperf.h \
|
||||
util/vircgroup.c util/vircgroup.h util/vircgrouppriv.h \
|
||||
util/virclosecallbacks.c util/virclosecallbacks.h \
|
||||
util/vircommand.c util/vircommand.h util/vircommandpriv.h \
|
||||
|
@ -2023,6 +2023,18 @@ virPCIStubDriverTypeFromString;
|
||||
virPCIStubDriverTypeToString;
|
||||
|
||||
|
||||
# util/virperf.h
|
||||
virPerfEventDisable;
|
||||
virPerfEventEnable;
|
||||
virPerfEventIsEnabled;
|
||||
virPerfEventTypeFromString;
|
||||
virPerfEventTypeToString;
|
||||
virPerfFree;
|
||||
virPerfGetEventFd;
|
||||
virPerfNew;
|
||||
virPerfReadEvent;
|
||||
|
||||
|
||||
# util/virpidfile.h
|
||||
virPidFileAcquire;
|
||||
virPidFileAcquirePath;
|
||||
|
@ -136,6 +136,8 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
|
||||
"Admin Interface",
|
||||
"Log Manager",
|
||||
"Xen XL Config",
|
||||
|
||||
"Perf",
|
||||
)
|
||||
|
||||
|
||||
|
307
src/util/virperf.c
Normal file
307
src/util/virperf.c
Normal file
@ -0,0 +1,307 @@
|
||||
/*
|
||||
* virperf.c: methods for managing perf events
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Ren Qiaowei <qiaowei.ren@intel.com>
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#if defined HAVE_SYS_SYSCALL_H
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#include "virperf.h"
|
||||
#include "viralloc.h"
|
||||
#include "virerror.h"
|
||||
#include "virlog.h"
|
||||
#include "virfile.h"
|
||||
#include "virstring.h"
|
||||
#include "virtypedparam.h"
|
||||
|
||||
VIR_LOG_INIT("util.perf");
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_PERF
|
||||
|
||||
VIR_ENUM_IMPL(virPerfEvent, VIR_PERF_EVENT_LAST,
|
||||
"cmt");
|
||||
|
||||
struct virPerfEvent {
|
||||
int type;
|
||||
int fd;
|
||||
bool enabled;
|
||||
union {
|
||||
/* cmt */
|
||||
struct {
|
||||
int scale;
|
||||
} cmt;
|
||||
} efields;
|
||||
};
|
||||
typedef struct virPerfEvent *virPerfEventPtr;
|
||||
|
||||
struct virPerf {
|
||||
struct virPerfEvent events[VIR_PERF_EVENT_LAST];
|
||||
};
|
||||
|
||||
virPerfPtr
|
||||
virPerfNew(void)
|
||||
{
|
||||
size_t i;
|
||||
virPerfPtr perf;
|
||||
|
||||
if (VIR_ALLOC(perf) < 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < VIR_PERF_EVENT_LAST; i++) {
|
||||
perf->events[i].type = i;
|
||||
perf->events[i].fd = -1;
|
||||
perf->events[i].enabled = false;
|
||||
}
|
||||
|
||||
return perf;
|
||||
}
|
||||
|
||||
void
|
||||
virPerfFree(virPerfPtr perf)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (perf == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < VIR_PERF_EVENT_LAST; i++) {
|
||||
if (perf->events[i].enabled)
|
||||
virPerfEventDisable(perf, i);
|
||||
}
|
||||
|
||||
VIR_FREE(perf);
|
||||
}
|
||||
|
||||
#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
|
||||
|
||||
# include <linux/perf_event.h>
|
||||
|
||||
static virPerfEventPtr
|
||||
virPerfGetEvent(virPerfPtr perf,
|
||||
virPerfEventType type)
|
||||
{
|
||||
if (type >= VIR_PERF_EVENT_LAST) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Event '%d' is not supported"),
|
||||
type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return perf->events + type;
|
||||
}
|
||||
|
||||
static int
|
||||
virPerfCmtEnable(virPerfEventPtr event,
|
||||
pid_t pid)
|
||||
{
|
||||
struct perf_event_attr cmt_attr;
|
||||
char *buf = NULL;
|
||||
char *tmp = NULL;
|
||||
unsigned int event_type, scale;
|
||||
|
||||
if (virFileReadAll("/sys/devices/intel_cqm/type",
|
||||
10, &buf) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((tmp = strchr(buf, '\n')))
|
||||
*tmp = '\0';
|
||||
|
||||
if (virStrToLong_ui(buf, NULL, 10, &event_type) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("failed to get cmt event type"));
|
||||
goto cleanup;
|
||||
}
|
||||
VIR_FREE(buf);
|
||||
|
||||
if (virFileReadAll("/sys/devices/intel_cqm/events/llc_occupancy.scale",
|
||||
10, &buf) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virStrToLong_ui(buf, NULL, 10, &scale) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("failed to get cmt scaling factor"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
event->efields.cmt.scale = scale;
|
||||
|
||||
memset(&cmt_attr, 0, sizeof(cmt_attr));
|
||||
cmt_attr.size = sizeof(cmt_attr);
|
||||
cmt_attr.type = event_type;
|
||||
cmt_attr.config = 1;
|
||||
cmt_attr.inherit = 1;
|
||||
cmt_attr.disabled = 1;
|
||||
cmt_attr.enable_on_exec = 0;
|
||||
|
||||
event->fd = syscall(__NR_perf_event_open, &cmt_attr, pid, -1, -1, 0);
|
||||
if (event->fd < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("Unable to open perf type=%d for pid=%d"),
|
||||
event_type, pid);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ioctl(event->fd, PERF_EVENT_IOC_ENABLE) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("Unable to enable perf event for CMT"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
event->enabled = true;
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
VIR_FORCE_CLOSE(event->fd);
|
||||
VIR_FREE(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
virPerfEventEnable(virPerfPtr perf,
|
||||
virPerfEventType type,
|
||||
pid_t pid)
|
||||
{
|
||||
virPerfEventPtr event = virPerfGetEvent(perf, type);
|
||||
if (event == NULL)
|
||||
return -1;
|
||||
|
||||
switch (type) {
|
||||
case VIR_PERF_EVENT_CMT:
|
||||
if (virPerfCmtEnable(event, pid))
|
||||
return -1;
|
||||
break;
|
||||
case VIR_PERF_EVENT_LAST:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unexpected perf event type=%d"), type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
virPerfEventDisable(virPerfPtr perf,
|
||||
virPerfEventType type)
|
||||
{
|
||||
virPerfEventPtr event = virPerfGetEvent(perf, type);
|
||||
if (event == NULL)
|
||||
return -1;
|
||||
|
||||
if (ioctl(event->fd, PERF_EVENT_IOC_DISABLE) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("Unable to disable perf event type=%d"),
|
||||
event->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
event->enabled = false;
|
||||
VIR_FORCE_CLOSE(event->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool virPerfEventIsEnabled(virPerfPtr perf,
|
||||
virPerfEventType type)
|
||||
{
|
||||
virPerfEventPtr event = virPerfGetEvent(perf, type);
|
||||
if (event == NULL)
|
||||
return false;
|
||||
|
||||
return event->enabled;
|
||||
}
|
||||
|
||||
int virPerfGetEventFd(virPerfPtr perf,
|
||||
virPerfEventType type)
|
||||
{
|
||||
virPerfEventPtr event = virPerfGetEvent(perf, type);
|
||||
if (event == NULL)
|
||||
return false;
|
||||
|
||||
return event->fd;
|
||||
}
|
||||
|
||||
int
|
||||
virPerfReadEvent(virPerfPtr perf,
|
||||
virPerfEventType type,
|
||||
uint64_t *value)
|
||||
{
|
||||
virPerfEventPtr event = virPerfGetEvent(perf, type);
|
||||
if (event == NULL || !event->enabled)
|
||||
return -1;
|
||||
|
||||
if (read(event->fd, value, sizeof(uint64_t)) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("Unable to read cache data"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (type == VIR_PERF_EVENT_CMT)
|
||||
*value *= event->efields.cmt.scale;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int
|
||||
virPerfEventEnable(virPerfPtr perf ATTRIBUTE_UNUSED,
|
||||
pid_t pid ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENXIO, "%s",
|
||||
_("Perf not supported on this platform"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
virPerfEventDisable(virPerfPtr perf ATTRIBUTE_UNUSED,
|
||||
int event ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENXIO, "%s",
|
||||
_("Perf not supported on this platform"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
virPerfEventIsEnabled(virPerfPtr perf,
|
||||
virPerfEventType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
virPerfGetEventFd(virPerfPtr perf,
|
||||
virPerfEventType type)
|
||||
{
|
||||
virReportSystemError(ENXIO, "%s",
|
||||
_("Perf not supported on this platform"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
virPerfReadEvent(virPerfPtr perf,
|
||||
virPerfEventType type
|
||||
uint64_t *value)
|
||||
{
|
||||
virReportSystemError(ENXIO, "%s",
|
||||
_("Perf not supported on this platform"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
63
src/util/virperf.h
Normal file
63
src/util/virperf.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* virperf.h: methods for managing perf events
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Ren Qiaowei <qiaowei.ren@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __VIR_PERF_H__
|
||||
# define __VIR_PERF_H__
|
||||
|
||||
# include "virutil.h"
|
||||
|
||||
typedef enum {
|
||||
VIR_PERF_EVENT_CMT,
|
||||
|
||||
VIR_PERF_EVENT_LAST
|
||||
} virPerfEventType;
|
||||
|
||||
VIR_ENUM_DECL(virPerfEvent);
|
||||
|
||||
# define VIR_PERF_PARAMETERS \
|
||||
VIR_PERF_PARAM_CMT, VIR_TYPED_PARAM_BOOLEAN, \
|
||||
NULL
|
||||
|
||||
struct virPerf;
|
||||
typedef struct virPerf *virPerfPtr;
|
||||
|
||||
virPerfPtr virPerfNew(void);
|
||||
|
||||
void virPerfFree(virPerfPtr perf);
|
||||
|
||||
int virPerfEventEnable(virPerfPtr perf,
|
||||
virPerfEventType type,
|
||||
pid_t pid);
|
||||
|
||||
int virPerfEventDisable(virPerfPtr perf,
|
||||
virPerfEventType type);
|
||||
|
||||
bool virPerfEventIsEnabled(virPerfPtr perf,
|
||||
virPerfEventType type);
|
||||
|
||||
int virPerfGetEventFd(virPerfPtr perf,
|
||||
virPerfEventType type);
|
||||
|
||||
int virPerfReadEvent(virPerfPtr perf,
|
||||
virPerfEventType type,
|
||||
uint64_t *value);
|
||||
|
||||
#endif /* __VIR_PERF_H__ */
|
Loading…
Reference in New Issue
Block a user