Fix pfmsetup to work with system-wide contexts.
- The load_context command can now take a CPU number instead of a program
number.
- Whever we are operating on a system-wide context we need to set pfmsetup's
affinity to the CPU where the context is loaded.
Signed-off-by: Kevin Corry <[EMAIL PROTECTED]>
--- a/examples/pfmsetup.c 13 Nov 2006 17:27:40 -0000
+++ b/examples/pfmsetup.c 23 Apr 2007 19:47:18 -0000
@@ -44,14 +44,15 @@
* - <context_id>: specify an integer that you want to associate with
* the new context for use in other commands.
*
- * load_context <context_id> <event_set_id> <program_id>
+ * load_context <context_id> <event_set_id> <program_id|cpu_id>
* Attach the specified context and event-set to the specified program.
* - <context_id>: ID that you specified when creating the context.
* - <event_set_id>: ID that you specified when creating an event-set
* within the given context. All contexts
automatically
* have an event-set with ID of 0.
- * - <program_id>: ID that you specified when starting a program with
the
- * run_program command.
+ * - <program_id|cpu_id>: ID that you specified when starting a program
+ * with the run_program command, or the number of
+ * the CPU to attach to for system-wide mode.
*
* unload_context <context_id>
* Detach the specified context from the program that it's currently
@@ -213,6 +214,7 @@
#include <errno.h>
#include <getopt.h>
#include <inttypes.h>
+#include <sched.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <perfmon/perfmon.h>
@@ -242,6 +244,7 @@
struct context {
int id;
int fd;
+ int cpu;
pfarg_ctx_t ctx_arg;
pfm_dfl_smpl_arg_t smpl_arg;
struct event_set *event_sets;
@@ -399,6 +402,53 @@
}
/**
+ * set_affinity
+ *
+ * When loading or unloading a system-wide context, we must pin the pfmsetup
+ * process to that CPU before making the system call. Also, get the current
+ * affinity and return it to the caller so we can change it back later.
+ **/
+static int set_affinity(int cpu, cpu_set_t *old_cpu_set)
+{
+ cpu_set_t new_cpu_set;
+ int rc;
+
+ rc = sched_getaffinity(0, sizeof(*old_cpu_set), old_cpu_set);
+ if (rc) {
+ rc = errno;
+ LOG_ERROR("Can't get current process affinity mask: %d\n", rc);
+ return rc;
+ }
+
+ CPU_ZERO(&new_cpu_set);
+ CPU_SET(cpu, &new_cpu_set);
+ rc = sched_setaffinity(0, sizeof(new_cpu_set), &new_cpu_set);
+ if (rc) {
+ rc = errno;
+ LOG_ERROR("Can't set process affinity to CPU %d: %d\n", cpu,
rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * revert_affinity
+ *
+ * Reset the process affinity to the specified mask.
+ **/
+static void revert_affinity(cpu_set_t *old_cpu_set)
+{
+ int rc;
+
+ rc = sched_setaffinity(0, sizeof(*old_cpu_set), old_cpu_set);
+ if (rc) {
+ /* Not a fatal error if we can't reset the affinity. */
+ LOG_INFO("Can't revert process affinity to original value.\n");
+ }
+}
+
+/**
* create_context
*
* Arguments: [options] <context_id>
@@ -528,6 +578,7 @@
new_ctx->id = ctx_id;
new_ctx->fd = rc;
+ new_ctx->cpu = -1;
new_ctx->ctx_arg = ctx_arg;
new_ctx->smpl_arg = smpl_arg;
@@ -550,7 +601,7 @@
/**
* load_context
*
- * Arguments: <context_id> <event_set_id> <program_id>
+ * Arguments: <context_id> <event_set_id> <program_id|cpu_id>
*
* Call the pfm_load_context system-call to load a perfmon context into the
* system's performance monitoring unit.
@@ -561,15 +612,16 @@
struct event_set *evt;
struct program *prog;
pfarg_load_t load_arg;
+ cpu_set_t old_cpu_set;
int ctx_id, event_set_id, program_id;
- int rc;
+ int system_wide, rc;
ctx_id = strtoul(argv[1], NULL, 0);
event_set_id = strtoul(argv[2], NULL, 0);
program_id = strtoul(argv[3], NULL, 0);
- if (ctx_id <= 0 || event_set_id < 0 || program_id <= 0) {
- LOG_ERROR("context ID, event-set ID, and program ID must "
+ if (ctx_id <= 0 || event_set_id < 0 || program_id < 0) {
+ LOG_ERROR("context ID, event-set ID, and program/CPU ID must "
"be positive integers.");
return EINVAL;
}
@@ -587,16 +639,31 @@
event_set_id, ctx_id);
return EINVAL;
}
+ load_arg.load_set = evt->id;
- prog = find_program(program_id);
- if (!prog) {
- LOG_ERROR("Can't find program with ID %d.", program_id);
- return EINVAL;
- }
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide) {
+ if (ctx->cpu >= 0) {
+ LOG_ERROR("Trying to load context %d which is already "
+ "loaded on CPU %d.\n", ctx_id, ctx->cpu);
+ return EBUSY;
+ }
- /* Set up the parameters for the system call. */
- load_arg.load_set = evt->id;
- load_arg.load_pid = prog->pid;
+ rc = set_affinity(program_id, &old_cpu_set);
+ if (rc) {
+ return rc;
+ }
+
+ /* Specify the CPU as the PID. */
+ load_arg.load_pid = program_id;
+ } else {
+ prog = find_program(program_id);
+ if (!prog) {
+ LOG_ERROR("Can't find program with ID %d.", program_id);
+ return EINVAL;
+ }
+ load_arg.load_pid = prog->pid;
+ }
rc = pfm_load_context(ctx->fd, &load_arg);
if (rc) {
@@ -606,8 +673,16 @@
return rc;
}
- LOG_INFO("Loaded context %d, event-set %d onto program %d.",
- ctx_id, event_set_id, program_id);
+ if (system_wide) {
+ /* Keep track of which CPU this context is loaded on. */
+ ctx->cpu = program_id;
+
+ revert_affinity(&old_cpu_set);
+ }
+
+ LOG_INFO("Loaded context %d, event-set %d onto %s %d.",
+ ctx_id, event_set_id, system_wide ? "program" : "cpu",
+ program_id);
return 0;
}
@@ -623,6 +698,8 @@
static int unload_context(int argc, char **argv)
{
struct context *ctx;
+ cpu_set_t old_cpu_set;
+ int system_wide;
int ctx_id;
int rc;
@@ -638,6 +715,21 @@
return EINVAL;
}
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide) {
+ if (ctx->cpu < 0) {
+ /* This context isn't loaded on any CPU. */
+ LOG_ERROR("Trying to unload context %d that isn't "
+ "loaded.\n", ctx_id);
+ return EINVAL;
+ }
+
+ rc = set_affinity(ctx->cpu, &old_cpu_set);
+ if (rc) {
+ return rc;
+ }
+ }
+
rc = pfm_unload_context(ctx->fd);
if (rc) {
rc = errno;
@@ -646,6 +738,11 @@
return rc;
}
+ if (system_wide) {
+ ctx->cpu = -1;
+ revert_affinity(&old_cpu_set);
+ }
+
LOG_INFO("Unloaded context %d.", ctx_id);
return 0;
@@ -706,10 +803,11 @@
struct context *ctx;
struct event_set *evt;
pfarg_pmc_t *pmc_args = NULL;
+ cpu_set_t old_cpu_set;
int ctx_id, event_set_id;
int pmc_id, num_pmcs;
unsigned long long pmc_value;
- int i, rc;
+ int system_wide, i, rc;
ctx_id = strtoul(argv[1], NULL, 0);
event_set_id = strtoul(argv[2], NULL, 0);
@@ -756,6 +854,14 @@
pmc_args[i].reg_value = pmc_value;
}
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide && ctx->cpu >= 0) {
+ rc = set_affinity(ctx->cpu, &old_cpu_set);
+ if (rc) {
+ goto out;
+ }
+ }
+
rc = pfm_write_pmcs(ctx->fd, pmc_args, num_pmcs);
if (rc) {
rc = errno;
@@ -764,6 +870,10 @@
goto out;
}
+ if (system_wide && ctx->cpu >= 0) {
+ revert_affinity(&old_cpu_set);
+ }
+
/* Check each PMC for success or failure. */
for (i = 0; i < num_pmcs; i++) {
if (pmc_args[i].reg_flags & PFM_REG_RETFL_NOTAVAIL) {
@@ -802,10 +912,11 @@
struct context *ctx;
struct event_set *evt;
pfarg_pmd_t *pmd_args = NULL;
+ cpu_set_t old_cpu_set;
int ctx_id, event_set_id;
int pmd_id, num_pmds;
unsigned long long pmd_value;
- int i, rc;
+ int system_wide, i, rc;
ctx_id = strtoul(argv[1], NULL, 0);
event_set_id = strtoul(argv[2], NULL, 0);
@@ -852,6 +963,14 @@
pmd_args[i].reg_value = pmd_value;
}
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide && ctx->cpu >= 0) {
+ rc = set_affinity(ctx->cpu, &old_cpu_set);
+ if (rc) {
+ goto out;
+ }
+ }
+
rc = pfm_write_pmds(ctx->fd, pmd_args, num_pmds);
if (rc) {
rc = errno;
@@ -860,6 +979,10 @@
goto out;
}
+ if (system_wide && ctx->cpu >= 0) {
+ revert_affinity(&old_cpu_set);
+ }
+
/* Check each PMD for success or failure. */
for (i = 0; i < num_pmds; i++) {
if (pmd_args[i].reg_flags & PFM_REG_RETFL_NOTAVAIL) {
@@ -898,9 +1021,10 @@
struct context *ctx;
struct event_set *evt;
pfarg_pmd_t *pmd_args = NULL;
+ cpu_set_t old_cpu_set;
int ctx_id, event_set_id;
int pmd_id, num_pmds;
- int i, rc;
+ int system_wide, i, rc;
ctx_id = strtoul(argv[1], NULL, 0);
event_set_id = strtoul(argv[2], NULL, 0);
@@ -944,6 +1068,14 @@
pmd_args[i].reg_set = evt->id;
}
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide && ctx->cpu >= 0) {
+ rc = set_affinity(ctx->cpu, &old_cpu_set);
+ if (rc) {
+ goto out;
+ }
+ }
+
rc = pfm_read_pmds(ctx->fd, pmd_args, num_pmds);
if (rc) {
rc = errno;
@@ -952,6 +1084,10 @@
goto out;
}
+ if (system_wide && ctx->cpu >= 0) {
+ revert_affinity(&old_cpu_set);
+ }
+
/* Check each PMD for success or failure. */
for (i = 0; i < num_pmds; i++) {
if (pmd_args[i].reg_flags & PFM_REG_RETFL_NOTAVAIL) {
@@ -991,8 +1127,9 @@
pfarg_start_t start_arg;
struct context *ctx;
struct event_set *evt;
+ cpu_set_t old_cpu_set;
int ctx_id, event_set_id;
- int rc;
+ int system_wide, rc;
memset(&start_arg, 0, sizeof(start_arg));
@@ -1020,6 +1157,14 @@
start_arg.start_set = evt->id;
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide && ctx->cpu >= 0) {
+ rc = set_affinity(ctx->cpu, &old_cpu_set);
+ if (rc) {
+ return rc;
+ }
+ }
+
rc = pfm_start(ctx->fd, &start_arg);
if (rc) {
rc = errno;
@@ -1027,6 +1172,10 @@
return rc;
}
+ if (system_wide && ctx->cpu >= 0) {
+ revert_affinity(&old_cpu_set);
+ }
+
LOG_INFO("Started counting for context %d, event-set %d.",
ctx_id, event_set_id);
@@ -1044,6 +1193,8 @@
static int stop_counting(int argc, char **argv)
{
struct context *ctx;
+ cpu_set_t old_cpu_set;
+ int system_wide;
int ctx_id;
int rc;
@@ -1060,6 +1211,14 @@
return EINVAL;
}
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide && ctx->cpu >= 0) {
+ rc = set_affinity(ctx->cpu, &old_cpu_set);
+ if (rc) {
+ return rc;
+ }
+ }
+
rc = pfm_stop(ctx->fd);
if (rc) {
rc = errno;
@@ -1067,6 +1226,10 @@
return rc;
}
+ if (system_wide && ctx->cpu >= 0) {
+ revert_affinity(&old_cpu_set);
+ }
+
LOG_INFO("Stopped counting for context %d.", ctx_id);
return 0;
@@ -1083,6 +1246,8 @@
static int restart_counting(int argc, char **argv)
{
struct context *ctx;
+ cpu_set_t old_cpu_set;
+ int system_wide;
int ctx_id;
int rc;
@@ -1099,6 +1264,14 @@
return EINVAL;
}
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide && ctx->cpu >= 0) {
+ rc = set_affinity(ctx->cpu, &old_cpu_set);
+ if (rc) {
+ return rc;
+ }
+ }
+
rc = pfm_restart(ctx->fd);
if (rc) {
rc = errno;
@@ -1106,6 +1279,10 @@
return rc;
}
+ if (system_wide && ctx->cpu >= 0) {
+ revert_affinity(&old_cpu_set);
+ }
+
LOG_INFO("Restarted counting for context %d.", ctx_id);
return 0;
@@ -1127,13 +1304,14 @@
pfarg_setdesc_t set_arg;
struct context *ctx;
struct event_set *evt;
+ cpu_set_t old_cpu_set;
int ctx_id, event_set_id, next_set_id = 0;
unsigned long timeout = 0;
int switch_on_overflow = FALSE;
int switch_on_timeout = FALSE;
int explicit_next_set = FALSE;
int exclude_idle = FALSE;
- int c, rc;
+ int system_wide,c, rc;
struct option long_opts[] = {
{"next-set", required_argument, NULL, 1},
{"timeout", required_argument, NULL, 2},
@@ -1224,6 +1402,15 @@
(switch_on_timeout ? PFM_SETFL_TIME_SWITCH : 0) |
(explicit_next_set ? PFM_SETFL_EXPL_NEXT : 0);
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide && ctx->cpu >= 0) {
+ rc = set_affinity(ctx->cpu, &old_cpu_set);
+ if (rc) {
+ free(evt);
+ return rc;
+ }
+ }
+
rc = pfm_create_evtsets(ctx->fd, &set_arg, 1);
if (rc) {
rc = errno;
@@ -1233,6 +1420,10 @@
return rc;
}
+ if (system_wide && ctx->cpu >= 0) {
+ revert_affinity(&old_cpu_set);
+ }
+
evt->id = event_set_id;
insert_event_set(ctx, evt);
@@ -1251,8 +1442,9 @@
pfarg_setdesc_t set_arg;
struct context *ctx;
struct event_set *evt;
+ cpu_set_t old_cpu_set;
int ctx_id, event_set_id;
- int rc;
+ int system_wide, rc;
memset(&set_arg, 0, sizeof(set_arg));
@@ -1280,6 +1472,14 @@
set_arg.set_id = evt->id;
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide && ctx->cpu >= 0) {
+ rc = set_affinity(ctx->cpu, &old_cpu_set);
+ if (rc) {
+ return rc;
+ }
+ }
+
rc = pfm_delete_evtsets(ctx->fd, &set_arg, 1);
if (rc) {
rc = errno;
@@ -1288,6 +1488,10 @@
return rc;
}
+ if (system_wide && ctx->cpu >= 0) {
+ revert_affinity(&old_cpu_set);
+ }
+
remove_event_set(ctx, evt);
free(evt);
@@ -1306,8 +1510,9 @@
pfarg_setinfo_t set_arg;
struct context *ctx;
struct event_set *evt;
+ cpu_set_t old_cpu_set;
int ctx_id, event_set_id;
- int rc;
+ int system_wide, rc;
memset(&set_arg, 0, sizeof(set_arg));
@@ -1335,6 +1540,14 @@
set_arg.set_id = evt->id;
+ system_wide = ctx->ctx_arg.ctx_flags & PFM_FL_SYSTEM_WIDE;
+ if (system_wide && ctx->cpu >= 0) {
+ rc = set_affinity(ctx->cpu, &old_cpu_set);
+ if (rc) {
+ return rc;
+ }
+ }
+
rc = pfm_getinfo_evtsets(ctx->fd, &set_arg, 1);
if (rc) {
rc = errno;
@@ -1343,6 +1556,10 @@
return rc;
}
+ if (system_wide && ctx->cpu >= 0) {
+ revert_affinity(&old_cpu_set);
+ }
+
LOG_INFO("Got info for event-set %d in context %d.", event_set_id,
ctx_id);
LOG_INFO(" Next set: %u", set_arg.set_id_next);
LOG_INFO(" Flags: 0x%x", set_arg.set_flags);
@@ -1540,9 +1757,12 @@
return EINVAL;
}
- sleep(seconds);
+ LOG_INFO("Sleeping for %d seconds.", seconds);
+
+ while (seconds > 0)
+ seconds = sleep(seconds);
- LOG_INFO("Slept for %d seconds.", seconds);
+ LOG_INFO("Done sleeping.");
return 0;
}
@@ -1565,7 +1785,7 @@
create_context, 1 },
{ "load_context", "load",
- "<context_id> <event_set_id> <program_id>",
+ "<context_id> <event_set_id> <program_id|cpu_id>",
load_context, 3 },
{ "unload_context", "unload",
_______________________________________________
perfmon mailing list
[email protected]
http://www.hpl.hp.com/hosted/linux/mail-archives/perfmon/