This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] Support for performance event sampling


I have been working on PR909 and have revised the perf.c and perf.h file in the runtime to make use of the new performance event kernel api. Given the changes it seems easier to send the files as complete files rather than patches on the old versions.

The perf_test2.stp is a simple example that is compiled using guru mode (-g) to exercise the run time. Due to check that the performance event kernel api makes the script will need to be run as root.

One difficulty is the perf_event_create_kernel_counter() allocates memory for the event descriptor and returns a pointer to that structure. When the performance event overflows the callback function has the following prototype:

int perf_event_overflow(struct perf_event *event, int nmi,
			  struct perf_sample_data *data,
			  struct pt_regs *regs)

For hrtimer probes one function is used to dispatch all of hrtimer related events. Unfortunately, the approach used for the hrtimer doesn't won't work here. the hrtimer probes embed the hrtimer struct in a struct that includes the other useful information. So the systemtap translator will need to generate a unique callback for each performance event.

-Will
/* -*- linux-c -*- 
 * Perf Header File
 * Copyright (C) 2006 Red Hat Inc.
 * Copyright (C) 2010 Red Hat Inc.
 *
 * This file is part of systemtap, and is free software.  You can
 * redistribute it and/or modify it under the terms of the GNU General
 * Public License (GPL); either version 2, or (at your option) any
 * later version.
 */

#ifndef _PERF_H_
#define _PERF_H_

/** @file perf.h
 * @brief Header file for performance monitoring hardware support
 */

typedef struct {
	struct perf_event *event;
	const char *pp;
	void (*ph) (struct context *);
} perfcpu;

typedef struct {
	/* per-cpu data. allocated with _stp_alloc_percpu() */
	perfcpu *pd;
} Perf;

static Perf *_stp_perf_init (struct perf_event_attr *attr,
			     perf_overflow_handler_t callback,
			     const char *pp,
			     void (*ph) (struct context *) );

static void _stp_perf_del (Perf *pe);

#endif /* _PERF_H_ */
/* -*- linux-c -*- 
 * Perf Functions
 * Copyright (C) 2006 Red Hat Inc.
 * Copyright (C) 2010 Red Hat Inc.
 *
 * This file is part of systemtap, and is free software.  You can
 * redistribute it and/or modify it under the terms of the GNU General
 * Public License (GPL); either version 2, or (at your option) any
 * later version.
 */

#ifndef _PERF_C_
#define _PERF_C_

#include <linux/perf_event.h>

#include "perf.h"

/** @file perf.c
 * @brief Implements performance monitoring hardware support
 */

/** Initialize performance sampling
 * Call this during probe initialization to set up performance event sampling
 *
 * @param attr description of event to sample
 * @param callback function to call when perf event overflows
 * @param pp associated probe point
 * @param ph probe handler
 */
static Perf *_stp_perf_init (struct perf_event_attr *attr,
			     perf_overflow_handler_t callback,
			     const char *pp, void (*ph) (struct context *) )
{
	int cpu;
	Perf *pe;

	pe = (Perf *) _stp_kmalloc (sizeof(Perf));
	if (pe == NULL)
		return NULL;

	/* allocate space for the event descriptor for each cpu */
	pe->pd = (perfcpu *) _stp_alloc_percpu (sizeof(perfcpu));
	if (pe->pd == NULL)
		goto exit1;

	/* initialize event on each processor */
	stp_for_each_cpu(cpu) {
		perfcpu *pd = per_cpu_ptr (pe->pd, cpu);
		struct perf_event **event = &(pd->event);
		*event = perf_event_create_kernel_counter(attr, cpu, -1,
							  callback);

		if (IS_ERR(*event)) {
			*event = NULL;
			goto exit2;
		}
		pd->pp = pp;
		pd->ph = ph;
	}
	return pe;

exit2:
	stp_for_each_cpu(cpu) {
		perfcpu *pd = per_cpu_ptr (pe->pd, cpu);
		struct perf_event **event = &(pd->event);
		if (*event) perf_event_release_kernel(*event);
	}
	_stp_free_percpu(pe->pd);
exit1:
	_stp_kfree(pe);
	return NULL;
}

/** Delete performance event.
 * Call this to shutdown performance event sampling
 *
 * @param pe
 */
static void _stp_perf_del (Perf *pe)
{
	if (pe) {
		int cpu;
		/* shut down performance event sampling */
		stp_for_each_cpu(cpu) {
			perfcpu *pd = per_cpu_ptr (pe->pd, cpu);
			struct perf_event **event = &(pd->event);
			if (*event) {
				perf_event_release_kernel(*event);
			}
		}
		_stp_free_percpu (pe->pd);
		_stp_kfree (pe);
	}
}

#endif /* _PERF_C_ */

Attachment: perf_test2.stp
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]