[libvirt] [PATCH v2 3/8] perf: implement a set of util functions for perf event
Daniel P. Berrange
berrange at redhat.com
Tue Dec 8 10:54:26 UTC 2015
On Mon, Dec 07, 2015 at 03:53:54PM +0800, Qiaowei Ren wrote:
> 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 at intel.com>
> ---
> include/libvirt/virterror.h | 1 +
> src/Makefile.am | 1 +
> src/libvirt_private.syms | 12 ++
> src/util/virerror.c | 1 +
> src/util/virperf.c | 298 ++++++++++++++++++++++++++++++++++++++++++++
> src/util/virperf.h | 61 +++++++++
> 6 files changed, 374 insertions(+)
> create mode 100644 src/util/virperf.c
> create mode 100644 src/util/virperf.h
>
> +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;
> + int event_type;
> + FILE *fp = NULL;
> + FILE *fp_scale = NULL;
> + int scale = 0;
> +
> + fp = fopen("/sys/devices/intel_cqm/type", "r");
> + if (!fp) {
> + virReportSystemError(errno, "%s",
> + _("CMT is not available on this host"));
> + return -1;
> + }
> + if (fscanf(fp, "%d", &event_type) != 1) {
> + virReportSystemError(errno, "%s",
> + _("Unable to read event type file."));
> + goto cleanup;
> + }
Scanf has pretty poor error reporting, so we'd usually do
char *buf;
if (virFileReadAll("/path", 100, &buf) < 0)
return -1;
if (virStrToLong_ui(buf, NULL, 10, &scale) < 0) {
VIR_FREE(buf);
....report error...
return -1;
}
VIR_FREE(buf);
> +
> + fp_scale = fopen("/sys/devices/intel_cqm/events/llc_occupancy.scale", "r");
> + if (!fp_scale) {
> + virReportSystemError(errno, "%s",
> + _("Unable to open CMT scale file"));
> + goto cleanup;
> + }
> + if (fscanf(fp_scale, "%d", &scale) != 1) {
> + virReportSystemError(errno, "%s",
> + _("Unable to read CMT scale file"));
> + goto cleanup;
> + }
Same comment here.
> + 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:
> + if (fp)
> + VIR_FORCE_FCLOSE(fp);
> + if (fp_scale)
> + VIR_FORCE_FCLOSE(fp_scale);
> + if (event->fd >= 0)
> + VIR_FORCE_CLOSE(event->fd);
> + return -1;
> +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;
> + }
Since we're closing the file handle next, is there any benefit
in doing this ioctl() ?
> +
> + event->enabled = false;
> + VIR_FORCE_CLOSE(event->fd);
> + return 0;
> +}
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the libvir-list
mailing list