opd_perfmon.c

Go to the documentation of this file.
00001 
00011 #ifdef __ia64__
00012 
00013 /* need this for sched_setaffinity() in <sched.h> */
00014 #define _GNU_SOURCE
00015 
00016 #include "oprofiled.h"
00017 #include "opd_perfmon.h"
00018 #include "opd_events.h"
00019 
00020 #include "op_cpu_type.h"
00021 #include "op_libiberty.h"
00022 #include "op_hw_config.h"
00023 
00024 #include <sys/syscall.h>
00025 #include <sys/wait.h>
00026 #include <unistd.h>
00027 #include <limits.h>
00028 #include <signal.h>
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <errno.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #ifdef HAVE_SCHED_SETAFFINITY
00036 #include <sched.h>
00037 #endif
00038 
00039 extern op_cpu cpu_type;
00040 
00041 #ifndef HAVE_SCHED_SETAFFINITY
00042 
00043 /* many glibc's are not yet up to date */
00044 #ifndef __NR_sched_setaffinity
00045 #define __NR_sched_setaffinity 1231
00046 #endif
00047 
00048 /* Copied from glibc's <sched.h> and <bits/sched.h> and munged */
00049 #define CPU_SETSIZE 1024
00050 #define __NCPUBITS  (8 * sizeof (unsigned long))
00051 typedef struct
00052 {
00053     unsigned long __bits[CPU_SETSIZE / __NCPUBITS];
00054 } cpu_set_t;
00055 
00056 #define CPU_SET(cpu, cpusetp) \
00057     ((cpusetp)->__bits[(cpu)/__NCPUBITS] |= (1UL << ((cpu) % __NCPUBITS)))
00058 #define CPU_ZERO(cpusetp) \
00059     memset((cpusetp), 0, sizeof(cpu_set_t))
00060 
00061 static int
00062 sched_setaffinity(pid_t pid, size_t len, cpu_set_t const * cpusetp)
00063 {
00064     return syscall(__NR_sched_setaffinity, pid, len, cpusetp);
00065 }
00066 #endif
00067 
00068 
00069 #ifndef HAVE_PERFMONCTL
00070 #ifndef __NR_perfmonctl
00071 #define __NR_perfmonctl 1175
00072 #endif
00073 
00074 static int perfmonctl(int fd, int cmd, void * arg, int narg)
00075 {
00076     return syscall(__NR_perfmonctl, fd, cmd, arg, narg);
00077 }
00078 #endif
00079 
00080 
00081 static unsigned char uuid[16] = {
00082     0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69,
00083     0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c
00084 };
00085 
00086 
00087 static size_t nr_cpus;
00088 
00089 struct child {
00090     pid_t pid;
00091     int up_pipe[2];
00092     int ctx_fd;
00093     sig_atomic_t sigusr1;
00094     sig_atomic_t sigusr2;
00095     sig_atomic_t sigterm;
00096 };
00097 
00098 static struct child * children;
00099 
00100 static void perfmon_start_child(int ctx_fd)
00101 {
00102     if (perfmonctl(ctx_fd, PFM_START, 0, 0) == -1) {
00103         exit(EXIT_FAILURE);
00104     }
00105 }
00106 
00107 
00108 static void perfmon_stop_child(int ctx_fd)
00109 {
00110     if (perfmonctl(ctx_fd, PFM_STOP, 0, 0) == -1) {
00111         exit(EXIT_FAILURE);
00112     }
00113 }
00114 
00115 
00116 static void child_sigusr1(int val __attribute__((unused)))
00117 {
00118     size_t i;
00119 
00120     for (i = 0; i < nr_cpus; ++i) {
00121         if (children[i].pid == getpid()) {
00122             children[i].sigusr1 = 1;
00123             return;
00124         }
00125     }
00126 }
00127 
00128 
00129 static void child_sigusr2(int val __attribute__((unused)))
00130 {
00131     size_t i;
00132 
00133     for (i = 0; i < nr_cpus; ++i) {
00134         if (children[i].pid == getpid()) {
00135             children[i].sigusr2 = 1;
00136             return;
00137         }
00138     }
00139 }
00140 
00141 
00142 static void child_sigterm(int val __attribute__((unused)))
00143 {
00144     kill(getppid(), SIGTERM);
00145 }
00146 
00147 
00148 static void set_affinity(size_t cpu)
00149 {
00150     cpu_set_t set;
00151     int err;
00152 
00153     CPU_ZERO(&set);
00154     CPU_SET(cpu, &set);
00155 
00156     err = sched_setaffinity(getpid(), sizeof(set), &set);
00157 
00158     if (err == -1) {
00159         perror("Failed to set affinity");
00160         exit(EXIT_FAILURE);
00161     }
00162 }
00163 
00164 
00165 static void setup_signals(void)
00166 {
00167     struct sigaction act;
00168     sigset_t mask;
00169 
00170     sigemptyset(&mask);
00171     sigaddset(&mask, SIGUSR1);
00172     sigaddset(&mask, SIGUSR2);
00173     sigprocmask(SIG_BLOCK, &mask, NULL);
00174 
00175     act.sa_handler = child_sigusr1;
00176     act.sa_flags = 0;
00177     sigemptyset(&act.sa_mask);
00178 
00179     if (sigaction(SIGUSR1, &act, NULL)) {
00180         perror("oprofiled: install of SIGUSR1 handler failed");
00181         exit(EXIT_FAILURE);
00182     }
00183 
00184     act.sa_handler = child_sigusr2;
00185     act.sa_flags = 0;
00186     sigemptyset(&act.sa_mask);
00187 
00188     if (sigaction(SIGUSR2, &act, NULL)) {
00189         perror("oprofiled: install of SIGUSR2 handler failed");
00190         exit(EXIT_FAILURE);
00191     }
00192 
00193     act.sa_handler = child_sigterm;
00194     act.sa_flags = 0;
00195     sigemptyset(&act.sa_mask);
00196 
00197     if (sigaction(SIGTERM, &act, NULL)) {
00198         perror("oprofiled: install of SIGTERM handler failed");
00199         exit(EXIT_FAILURE);
00200     }
00201 }
00202 
00203 
00205 static void create_context(struct child * self)
00206 {
00207     pfarg_context_t ctx;
00208     int err;
00209 
00210     memset(&ctx, 0, sizeof(pfarg_context_t));
00211     memcpy(&ctx.ctx_smpl_buf_id, &uuid, 16);
00212     ctx.ctx_flags = PFM_FL_SYSTEM_WIDE;
00213 
00214     err = perfmonctl(0, PFM_CREATE_CONTEXT, &ctx, 1);
00215     if (err == -1) {
00216         perror("CREATE_CONTEXT failed");
00217         exit(EXIT_FAILURE);
00218     }
00219 
00220     self->ctx_fd = ctx.ctx_fd;
00221 }
00222 
00223 
00225 static void write_pmu(struct child * self)
00226 {
00227     pfarg_reg_t pc[OP_MAX_COUNTERS];
00228     pfarg_reg_t pd[OP_MAX_COUNTERS];
00229     int err;
00230     size_t i;
00231 
00232     memset(pc, 0, sizeof(pc));
00233     memset(pd, 0, sizeof(pd));
00234 
00235 #define PMC_GEN_INTERRUPT (1UL << 5)
00236 #define PMC_PRIV_MONITOR (1UL << 6)
00237 /* McKinley requires pmc4 to have bit 23 set (enable PMU).
00238  * It is supposedly ignored in other pmc registers.
00239  */
00240 #define PMC_MANDATORY (1UL << 23)
00241 #define PMC_USER (1UL << 3)
00242 #define PMC_KERNEL (1UL << 0)
00243     for (i = 0; i < op_nr_counters && opd_events[i].name; ++i) {
00244         struct opd_event * event = &opd_events[i];
00245         pc[i].reg_num = event->counter + 4;
00246         pc[i].reg_value = PMC_GEN_INTERRUPT;
00247         pc[i].reg_value |= PMC_PRIV_MONITOR;
00248         pc[i].reg_value |= PMC_MANDATORY;
00249         (event->user) ? (pc[i].reg_value |= PMC_USER)
00250                       : (pc[i].reg_value &= ~PMC_USER);
00251         (event->kernel) ? (pc[i].reg_value |= PMC_KERNEL)
00252                         : (pc[i].reg_value &= ~PMC_KERNEL);
00253         pc[i].reg_value &= ~(0xff << 8);
00254         pc[i].reg_value |= ((event->value & 0xff) << 8);
00255         pc[i].reg_value &= ~(0xf << 16);
00256         pc[i].reg_value |= ((event->um & 0xf) << 16);
00257         pc[i].reg_smpl_eventid = event->counter;
00258     }
00259 
00260     for (i = 0; i < op_nr_counters && opd_events[i].name; ++i) {
00261         struct opd_event * event = &opd_events[i];
00262         pd[i].reg_value = ~0UL - event->count + 1;
00263         pd[i].reg_short_reset = ~0UL - event->count + 1;
00264         pd[i].reg_num = event->counter + 4;
00265     }
00266 
00267     err = perfmonctl(self->ctx_fd, PFM_WRITE_PMCS, pc, i);
00268     if (err == -1) {
00269         perror("Couldn't write PMCs");
00270         exit(EXIT_FAILURE);
00271     }
00272 
00273     err = perfmonctl(self->ctx_fd, PFM_WRITE_PMDS, pd, i);
00274     if (err == -1) {
00275         perror("Couldn't write PMDs");
00276         exit(EXIT_FAILURE);
00277     }
00278 }
00279 
00280 
00281 static void load_context(struct child * self)
00282 {
00283     pfarg_load_t load_args;
00284     int err;
00285 
00286     memset(&load_args, 0, sizeof(load_args));
00287     load_args.load_pid = self->pid;
00288 
00289     err = perfmonctl(self->ctx_fd, PFM_LOAD_CONTEXT, &load_args, 1);
00290     if (err == -1) {
00291         perror("Couldn't load context");
00292         exit(EXIT_FAILURE);
00293     }
00294 }
00295 
00296 
00297 static void notify_parent(struct child * self, size_t cpu)
00298 {
00299     for (;;) {
00300         ssize_t ret;
00301         ret = write(self->up_pipe[1], &cpu, sizeof(size_t));
00302         if (ret == sizeof(size_t))
00303             break;
00304         if (ret < 0 && errno != EINTR) {
00305             perror("Failed to write child pipe:");
00306             exit(EXIT_FAILURE);
00307         }
00308     }
00309 }
00310 
00311 static struct child * inner_child;
00312 void close_pipe(void)
00313 {
00314     close(inner_child->up_pipe[1]);
00315 }
00316 
00317 static void run_child(size_t cpu)
00318 {
00319     struct child * self = &children[cpu];
00320 
00321     self->pid = getpid();
00322     self->sigusr1 = 0;
00323     self->sigusr2 = 0;
00324     self->sigterm = 0;
00325 
00326     inner_child = self;
00327     if (atexit(close_pipe)){
00328         close_pipe();
00329         exit(EXIT_FAILURE);
00330     }
00331 
00332     umask(0);
00333     /* Change directory to allow directory to be removed */
00334     if (chdir("/") < 0) {
00335         perror("Unable to chdir to \"/\"");
00336         exit(EXIT_FAILURE);
00337     }
00338 
00339     setup_signals();
00340 
00341     set_affinity(cpu);
00342 
00343     create_context(self);
00344 
00345     write_pmu(self);
00346 
00347     load_context(self);
00348 
00349     notify_parent(self, cpu);
00350 
00351     /* Redirect standard files to /dev/null */
00352     freopen( "/dev/null", "r", stdin);
00353     freopen( "/dev/null", "w", stdout);
00354     freopen( "/dev/null", "w", stderr);
00355 
00356     for (;;) {
00357         sigset_t sigmask;
00358         sigfillset(&sigmask);
00359         sigdelset(&sigmask, SIGUSR1);
00360         sigdelset(&sigmask, SIGUSR2);
00361         sigdelset(&sigmask, SIGTERM);
00362 
00363         if (self->sigusr1) {
00364             perfmon_start_child(self->ctx_fd);
00365             self->sigusr1 = 0;
00366         }
00367 
00368         if (self->sigusr2) {
00369             perfmon_stop_child(self->ctx_fd);
00370             self->sigusr2 = 0;
00371         }
00372 
00373         sigsuspend(&sigmask);
00374     }
00375 }
00376 
00377 
00378 static void wait_for_child(struct child * child)
00379 {
00380     size_t tmp;
00381     for (;;) {
00382         ssize_t ret;
00383         ret = read(child->up_pipe[0], &tmp, sizeof(size_t));
00384         if (ret == sizeof(size_t))
00385             break;
00386         if ((ret < 0 && errno != EINTR) || ret == 0 ) {
00387             perror("Failed to read child pipe");
00388             exit(EXIT_FAILURE);
00389         }
00390     }
00391     printf("Perfmon child up on CPU%d\n", (int)tmp);
00392     fflush(stdout);
00393 
00394     close(child->up_pipe[0]);
00395 }
00396 
00397 static struct child* xen_ctx;
00398 
00399 void perfmon_init(void)
00400 {
00401     size_t i;
00402     long nr;
00403 
00404     if (cpu_type == CPU_TIMER_INT)
00405         return;
00406 
00407     if (!no_xen) {
00408         xen_ctx = xmalloc(sizeof(struct child));
00409         xen_ctx->pid = getpid();
00410         xen_ctx->up_pipe[0] = -1;
00411         xen_ctx->up_pipe[1] = -1;
00412         xen_ctx->sigusr1 = 0;
00413         xen_ctx->sigusr2 = 0;
00414         xen_ctx->sigterm = 0;
00415 
00416         create_context(xen_ctx);
00417 
00418         write_pmu(xen_ctx);
00419         
00420         load_context(xen_ctx);
00421         return;
00422     }
00423     
00424 
00425     nr = sysconf(_SC_NPROCESSORS_ONLN);
00426     if (nr == -1) {
00427         fprintf(stderr, "Couldn't determine number of CPUs.\n");
00428         exit(EXIT_FAILURE);
00429     }
00430 
00431     nr_cpus = nr;
00432 
00433     children = xmalloc(sizeof(struct child) * nr_cpus);
00434     bzero(children, sizeof(struct child) * nr_cpus);
00435 
00436     for (i = 0; i < nr_cpus; ++i) {
00437         int ret;
00438 
00439         if (pipe(children[i].up_pipe)) {
00440             perror("Couldn't create child pipe");
00441             exit(EXIT_FAILURE);
00442         }
00443 
00444         ret = fork();
00445         if (ret == -1) {
00446             perror("Couldn't fork perfmon child");
00447             exit(EXIT_FAILURE);
00448         } else if (ret == 0) {
00449             close(children[i].up_pipe[0]);
00450             run_child(i);
00451         } else {
00452             children[i].pid = ret;
00453             close(children[i].up_pipe[1]);
00454             printf("Waiting on CPU%d\n", (int)i);
00455             wait_for_child(&children[i]);
00456         }
00457     }
00458 }
00459 
00460 
00461 void perfmon_exit(void)
00462 {
00463     size_t i;
00464 
00465     if (cpu_type == CPU_TIMER_INT)
00466         return;
00467 
00468     if (!no_xen)
00469         return;
00470 
00471     for (i = 0; i < nr_cpus; ++i) {
00472         if (children[i].pid) {
00473             int c_pid = children[i].pid;
00474             children[i].pid = 0;
00475             if (kill(c_pid, SIGKILL)==0)
00476                 waitpid(c_pid, NULL, 0);
00477         }
00478     }
00479 }
00480 
00481 
00482 void perfmon_start(void)
00483 {
00484     size_t i;
00485 
00486     if (cpu_type == CPU_TIMER_INT)
00487         return;
00488 
00489     if (!no_xen) {
00490         perfmon_start_child(xen_ctx->ctx_fd);
00491         return;
00492     }
00493 
00494     for (i = 0; i < nr_cpus; ++i) {
00495         if (kill(children[i].pid, SIGUSR1)) {
00496             perror("Unable to start perfmon");
00497             exit(EXIT_FAILURE);
00498         }
00499     }
00500 }
00501 
00502 
00503 void perfmon_stop(void)
00504 {
00505     size_t i;
00506 
00507     if (cpu_type == CPU_TIMER_INT)
00508         return;
00509 
00510     if (!no_xen) {
00511         perfmon_stop_child(xen_ctx->ctx_fd);
00512         return;
00513     }
00514     
00515     for (i = 0; i < nr_cpus; ++i)
00516         if (kill(children[i].pid, SIGUSR2)) {
00517             perror("Unable to stop perfmon");
00518             exit(EXIT_FAILURE);
00519         }
00520 }
00521 
00522 #endif /* __ia64__ */

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1