summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Cohen <wcohen@redhat.com>2010-02-17 10:30:15 -0500
committerJosh Stone <jistone@redhat.com>2010-03-17 11:50:34 -0700
commit5d8efa6b59a399815e065d4f29ed64d01bdb6182 (patch)
tree7f70b243a56c9a88b0f339d3b0beae0630c26178
parent6ccb243c59eff3ac89072b112414c50d6ef6cf3b (diff)
downloadsystemtap-steved-5d8efa6b59a399815e065d4f29ed64d01bdb6182.tar.gz
systemtap-steved-5d8efa6b59a399815e065d4f29ed64d01bdb6182.tar.xz
systemtap-steved-5d8efa6b59a399815e065d4f29ed64d01bdb6182.zip
PR909: Runtime for Performance Event Sampling
Implements a very simple sampling runtime to using the performance events kernel API. An perf event attribute describing the setup and a function to handle the counter overflows are passed into _stp_perf_init(). This function sets up the event on each processor. If successfully initialized, a pointer data structure is returned. When the sampling is no longer needed _stp_perf_del() is called to shutdown the sampling. * runtime/perf.h: Add declarations for data structures and functions * runtime/perf.c: Remove old perfmon runtime runtime. Add _stp_perf_init() and _stp_perf_del() functions.
-rw-r--r--runtime/perf.c160
-rw-r--r--runtime/perf.h17
2 files changed, 69 insertions, 108 deletions
diff --git a/runtime/perf.c b/runtime/perf.c
index 9ac8b481..06ed551a 100644
--- a/runtime/perf.c
+++ b/runtime/perf.c
@@ -1,6 +1,7 @@
/* -*- 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
@@ -11,7 +12,7 @@
#ifndef _PERF_C_
#define _PERF_C_
-#include <linux/perfmon.h>
+#include <linux/perf_event.h>
#include "perf.h"
@@ -19,117 +20,72 @@
* @brief Implements performance monitoring hardware support
*/
-/* TODO fix so this works on SMP machines
- * Need to do context load, register setup, and start on each processor
+/** Initialize performance sampling
+ * Call this during probe initialization to set up performance event sampling
*
- * Similarly need to stop and unload on each processor
+ * @param attr description of event to sample
+ * @param callback function to call when perf event overflows
*/
-
-/* TODO make this work with sampling. There needs to be a help thread
- * handling the sampling. */
-
-
-static int _stp_pfm_register_setup(void *desc,
- struct pfarg_pmc pmc[], int pmc_count,
- struct pfarg_pmd pmd[], int pmd_count)
-{
- int err = 0;
-
- if (desc == 0) return -EINVAL;
- err = pfmk_write_pmcs(desc, pmc, pmc_count);
- if (err) return err;
-
- err = pfmk_write_pmds(desc, pmd, pmd_count);
- return err;
-}
-
-static struct completion c;
-static struct pfarg_load load_args;
-static struct pfarg_start start_args;
-
-/** Sets up the performance monitoring hardware.
- * The locations desc and context point to are modified as
- * side-effects of the setup. desc is a unique pointer used
- * by the various routines.
- * @param desc pointer to void *, handle to describe perfmon config
- * @param context pointer to context information
- * @param pmc, pointer to array describing control register setup
- * @param pmc_count, number of entries in pmc
- * @param pmd, pointer to array describing data register setup
- * @param pmd_count, number of entries in pmd
- * @returns an int, 0 if no errors encountered during setup
- */
-static int _stp_perfmon_setup(void **desc,
- struct pfarg_ctx *context,
- struct pfarg_pmc pmc[], int pmc_count,
- struct pfarg_pmd pmd[], int pmd_count)
+static Perf _stp_perf_init (struct perf_event_attr *attr,
+ perf_overflow_handler_t callback)
{
- int err = 0;
-
- /* create a context */
- err = pfmk_create_context(context, NULL, 0, &c, desc, NULL);
- if (err) goto cleanup;
-
- /* set up the counters */
- err = _stp_pfm_register_setup(*desc, pmc, pmc_count, pmd, pmd_count);
- if (err) goto cleanup2;
-
- /* start measuring */
- err = pfmk_load_context(*desc, &load_args);
- if (err) {
- printk("pfmk_load_context error\n");
- goto cleanup2;
+ int cpu;
+ Perf pe;
+
+ pe = (Perf) _stp_kmalloc (sizeof(struct _Perf));
+ if (pe == NULL)
+ return NULL;
+ pe->callback = callback;
+
+ /* allocate space for the event descriptor for each cpu */
+ pe->pd = (struct perf_event **)
+ _stp_alloc_percpu (sizeof(struct perf_event *));
+ if (pe->pd == NULL)
+ goto exit1;
+
+ /* initialize event on each processor */
+ stp_for_each_cpu(cpu) {
+ struct perf_event **event = per_cpu_ptr (pe->pd, cpu);
+ *event = perf_event_create_kernel_counter(attr, cpu, -1,
+ callback);
+
+ if (IS_ERR(*event)) {
+ *event = NULL;
+ goto exit2;
+ }
}
- err = pfmk_start(*desc, &start_args);
- if (err) {
- printk("pfmk_start error\n");
- goto cleanup3;
- }
-
- return err;
-
-cleanup3: pfmk_unload_context(*desc);
-cleanup2: pfmk_close(*desc);
-cleanup: *desc=NULL;
- return err;
-}
-
-/** Shuts down the performance monitoring hardware.
- * @param desc unique pointer to describe configuration
- * @returns an int, 0 if no errors encountered during shutdown
- */
-static int _stp_perfmon_shutdown(void *desc)
-{
- int err=0;
+ return pe;
- if (desc == 0) return -EINVAL;
- /* stop the counters */
- err=pfmk_stop(desc);
- if (err) return err;
- err=pfmk_unload_context(desc);
- if (err) return err;
- err=pfmk_close(desc);
- return err;
+exit2:
+ stp_for_each_cpu(cpu) {
+ struct perf_event **event = per_cpu_ptr (pe->pd, cpu);
+ if (*event) perf_event_release_kernel(*event);
+ }
+ _stp_free_percpu(pe->pd);
+exit1:
+ _stp_kfree(pe);
+ return NULL;
}
-/** Reads the performance counter
- * @param desc unique pointer to describe configuration
- * @returns an int64, raw value of counter
+/** Delete performance event.
+ * Call this to shutdown performance event sampling
+ *
+ * @param pe
*/
-static int64_t _stp_perfmon_read(void *desc, int counter)
+static void _stp_perf_del (Perf pe)
{
- struct pfarg_pmd storage;
-
- storage.reg_set = 0;
- storage.reg_num = counter;
-
- if ( desc != NULL) {
- if (pfmk_read_pmds(desc, &storage, 1))
- printk( "pfm_read_pmds error\n");
+ if (pe) {
+ int cpu;
+ /* shut down performance event sampling */
+ stp_for_each_cpu(cpu) {
+ struct perf_event **event = per_cpu_ptr (pe->pd, cpu);
+ if (*event) {
+ perf_event_release_kernel(*event);
+ }
+ }
+ _stp_free_percpu (pe->pd);
+ _stp_kfree (pe);
}
-
- return storage.reg_value;
}
#endif /* _PERF_C_ */
-
diff --git a/runtime/perf.h b/runtime/perf.h
index 6a87bff0..32383665 100644
--- a/runtime/perf.h
+++ b/runtime/perf.h
@@ -1,6 +1,7 @@
/* -*- 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
@@ -15,13 +16,17 @@
* @brief Header file for performance monitoring hardware support
*/
-static int _stp_perfmon_setup(void **desc,
- struct pfarg_ctx *context,
- struct pfarg_pmc pmc[], int pmc_count,
- struct pfarg_pmd pmd[], int pmd_count);
+struct _Perf {
+ /* per-cpu data. allocated with _stp_alloc_percpu() */
+ struct perf_event **pd;
+ perf_overflow_handler_t callback;
+};
-static int _stp_perfmon_shutdown(void *desc);
+typedef struct _Perf *Perf;
-static int64_t _stp_perfmon_read(void *desc, int counter);
+static Perf _stp_perf_init (struct perf_event_attr *attr,
+ perf_overflow_handler_t callback);
+
+static void _stp_perf_del (Perf pe);
#endif /* _PERF_H_ */