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/

Reply via email to