00001
00011 #ifdef __ia64__
00012
00013
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
00044 #ifndef __NR_sched_setaffinity
00045 #define __NR_sched_setaffinity 1231
00046 #endif
00047
00048
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
00238
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
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
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