00001
00015 #include "config.h"
00016
00017 #include "oprofiled.h"
00018 #include "opd_printf.h"
00019 #include "opd_events.h"
00020 #include "opd_extended.h"
00021
00022 #include "op_config.h"
00023 #include "op_version.h"
00024 #include "op_hw_config.h"
00025 #include "op_libiberty.h"
00026 #include "op_file.h"
00027 #include "op_abi.h"
00028 #include "op_string.h"
00029 #include "op_cpu_type.h"
00030 #include "op_popt.h"
00031 #include "op_lockfile.h"
00032 #include "op_list.h"
00033 #include "op_fileio.h"
00034
00035 #include <sys/types.h>
00036 #include <sys/resource.h>
00037 #include <stdlib.h>
00038 #include <fcntl.h>
00039 #include <stdio.h>
00040 #include <string.h>
00041 #include <unistd.h>
00042 #include <errno.h>
00043 #include <assert.h>
00044 #include <dirent.h>
00045 #include <limits.h>
00046
00047 sig_atomic_t signal_alarm;
00048 sig_atomic_t signal_hup;
00049 sig_atomic_t signal_term;
00050 sig_atomic_t signal_child;
00051 sig_atomic_t signal_usr1;
00052 sig_atomic_t signal_usr2;
00053
00054 uint op_nr_counters;
00055 op_cpu cpu_type;
00056 int no_event_ok;
00057 int vsfile;
00058 int vsamples;
00059 int varcs;
00060 int vmodule;
00061 int vmisc;
00062 int vext;
00063 int separate_lib;
00064 int separate_kernel;
00065 int separate_thread;
00066 int separate_cpu;
00067 int no_vmlinux;
00068 char * vmlinux;
00069 char * kernel_range;
00070 char * session_dir;
00071 int no_xen;
00072 char * xenimage;
00073 char * xen_range;
00074 static char * verbose;
00075 static char * binary_name_filter;
00076 static char * events;
00077 static char * ext_feature;
00078 static int showvers;
00079 static struct oprofiled_ops * opd_ops;
00080 extern struct oprofiled_ops opd_24_ops;
00081 extern struct oprofiled_ops opd_26_ops;
00082
00083 #define OPD_IMAGE_FILTER_HASH_SIZE 32
00084 static struct list_head images_filter[OPD_IMAGE_FILTER_HASH_SIZE];
00085
00086 static struct poptOption options[] = {
00087 { "session-dir", 0, POPT_ARG_STRING, &session_dir, 0, "place sample database in dir instead of default location", "/var/lib/oprofile", },
00088 { "kernel-range", 'r', POPT_ARG_STRING, &kernel_range, 0, "Kernel VMA range", "start-end", },
00089 { "vmlinux", 'k', POPT_ARG_STRING, &vmlinux, 0, "vmlinux kernel image", "file", },
00090 { "no-vmlinux", 0, POPT_ARG_NONE, &no_vmlinux, 0, "vmlinux kernel image file not available", NULL, },
00091 { "xen-range", 0, POPT_ARG_STRING, &xen_range, 0, "Xen VMA range", "start-end", },
00092 { "xen-image", 0, POPT_ARG_STRING, &xenimage, 0, "Xen image", "file", },
00093 { "image", 0, POPT_ARG_STRING, &binary_name_filter, 0, "image name filter", "profile these comma separated image" },
00094 { "separate-lib", 0, POPT_ARG_INT, &separate_lib, 0, "separate library samples for each distinct application", "[0|1]", },
00095 { "separate-kernel", 0, POPT_ARG_INT, &separate_kernel, 0, "separate kernel samples for each distinct application", "[0|1]", },
00096 { "separate-thread", 0, POPT_ARG_INT, &separate_thread, 0, "thread-profiling mode", "[0|1]" },
00097 { "separate-cpu", 0, POPT_ARG_INT, &separate_cpu, 0, "separate samples for each CPU", "[0|1]" },
00098 { "events", 'e', POPT_ARG_STRING, &events, 0, "events list", "[events]" },
00099 { "version", 'v', POPT_ARG_NONE, &showvers, 0, "show version", NULL, },
00100 { "verbose", 'V', POPT_ARG_STRING, &verbose, 0, "be verbose in log file", "all,sfile,arcs,samples,module,misc", },
00101 { "ext-feature", 'x', POPT_ARG_STRING, &ext_feature, 1, "enable extended feature", "<extended-feature-name>:[args]", },
00102 POPT_AUTOHELP
00103 { NULL, 0, 0, NULL, 0, NULL, NULL, },
00104 };
00105
00106
00107 void opd_open_logfile(void)
00108 {
00109 if (open(op_log_file, O_WRONLY|O_CREAT|O_NOCTTY|O_APPEND, 0644) == -1) {
00110 perror("oprofiled: couldn't re-open stdout: ");
00111 exit(EXIT_FAILURE);
00112 }
00113
00114 if (dup2(1, 2) == -1) {
00115 perror("oprofiled: couldn't dup stdout to stderr: ");
00116 exit(EXIT_FAILURE);
00117 }
00118 }
00119
00120
00127 static void opd_fork(void)
00128 {
00129 switch (fork()) {
00130 case -1:
00131 perror("oprofiled: fork() failed: ");
00132 exit(EXIT_FAILURE);
00133 break;
00134 case 0:
00135 break;
00136 default:
00137
00138 _exit(EXIT_SUCCESS);
00139 break;
00140 }
00141 }
00142
00143
00144 static void opd_go_daemon(void)
00145 {
00146 opd_fork();
00147
00148 if (chdir(op_session_dir)) {
00149 fprintf(stderr, "oprofiled: opd_go_daemon: couldn't chdir to %s: %s",
00150 op_session_dir, strerror(errno));
00151 exit(EXIT_FAILURE);
00152 }
00153
00154 if (setsid() < 0) {
00155 perror("oprofiled: opd_go_daemon: couldn't setsid: ");
00156 exit(EXIT_FAILURE);
00157 }
00158
00159 opd_fork();
00160 }
00161
00162
00163 static void opd_write_abi(void)
00164 {
00165 char * cbuf;
00166
00167 cbuf = xmalloc(strlen(op_session_dir) + 5);
00168 strcpy(cbuf, op_session_dir);
00169 strcat(cbuf, "/abi");
00170 op_write_abi_to_file(cbuf);
00171 free(cbuf);
00172 }
00173
00174
00178 static void opd_alarm(int val __attribute__((unused)))
00179 {
00180 signal_alarm = 1;
00181 }
00182
00183
00184
00185 static void opd_sighup(int val __attribute__((unused)))
00186 {
00187 signal_hup = 1;
00188 }
00189
00190
00191 static void opd_sigterm(int val __attribute__((unused)))
00192 {
00193 signal_term = 1;
00194 }
00195
00196 static void opd_sigchild(int val __attribute__((unused)))
00197 {
00198 signal_child = 1;
00199 }
00200
00201
00202 static void opd_sigusr1(int val __attribute__((unused)))
00203 {
00204 signal_usr1 = 1;
00205 }
00206
00207
00208 static void opd_sigusr2(int val __attribute__((unused)))
00209 {
00210 signal_usr2 = 1;
00211 }
00212
00213
00214 static void opd_setup_signals(void)
00215 {
00216 struct sigaction act;
00217
00218 act.sa_handler = opd_alarm;
00219 act.sa_flags = 0;
00220 sigemptyset(&act.sa_mask);
00221
00222 if (sigaction(SIGALRM, &act, NULL)) {
00223 perror("oprofiled: install of SIGALRM handler failed: ");
00224 exit(EXIT_FAILURE);
00225 }
00226
00227 act.sa_handler = opd_sighup;
00228 act.sa_flags = 0;
00229 sigemptyset(&act.sa_mask);
00230 sigaddset(&act.sa_mask, SIGALRM);
00231
00232 if (sigaction(SIGHUP, &act, NULL)) {
00233 perror("oprofiled: install of SIGHUP handler failed: ");
00234 exit(EXIT_FAILURE);
00235 }
00236
00237 act.sa_handler = opd_sigterm;
00238 act.sa_flags = 0;
00239 sigemptyset(&act.sa_mask);
00240 sigaddset(&act.sa_mask, SIGTERM);
00241
00242 if (sigaction(SIGTERM, &act, NULL)) {
00243 perror("oprofiled: install of SIGTERM handler failed: ");
00244 exit(EXIT_FAILURE);
00245 }
00246
00247 act.sa_handler = opd_sigchild;
00248 act.sa_flags = 0;
00249 sigemptyset(&act.sa_mask);
00250 sigaddset(&act.sa_mask, SIGCHLD);
00251
00252 if (sigaction(SIGCHLD, &act, NULL)) {
00253 perror("oprofiled: install of SIGCHLD handler failed: ");
00254 exit(EXIT_FAILURE);
00255 }
00256
00257 act.sa_handler = opd_sigusr1;
00258 act.sa_flags = 0;
00259 sigemptyset(&act.sa_mask);
00260 sigaddset(&act.sa_mask, SIGTERM);
00261
00262 if (sigaction(SIGUSR1, &act, NULL)) {
00263 perror("oprofiled: install of SIGUSR1 handler failed: ");
00264 exit(EXIT_FAILURE);
00265 }
00266
00267 act.sa_handler = opd_sigusr2;
00268 act.sa_flags = 0;
00269 sigemptyset(&act.sa_mask);
00270 sigaddset(&act.sa_mask, SIGTERM);
00271
00272 if (sigaction(SIGUSR2, &act, NULL)) {
00273 perror("oprofiled: install of SIGUSR2 handler failed: ");
00274 exit(EXIT_FAILURE);
00275 }
00276 }
00277
00278
00279 struct opd_hashed_name {
00280 char * name;
00281 struct list_head next;
00282 };
00283
00284
00285 static void add_image_filter(char const * name)
00286 {
00287 size_t hash;
00288 struct opd_hashed_name * elt = xmalloc(sizeof(struct opd_hashed_name));
00289 elt->name = xmalloc(PATH_MAX);
00290 if (!realpath(name, elt->name)) {
00291 free(elt->name);
00292 free(elt);
00293 return;
00294 }
00295 hash = op_hash_string(elt->name);
00296 verbprintf(vmisc, "Adding to image filter: \"%s\"\n", elt->name);
00297 list_add(&elt->next, &images_filter[hash % OPD_IMAGE_FILTER_HASH_SIZE]);
00298 }
00299
00300
00301 static void opd_parse_image_filter(void)
00302 {
00303 size_t i;
00304 char const * last = binary_name_filter;
00305 char const * cur = binary_name_filter;
00306
00307 if (!binary_name_filter)
00308 return;
00309
00310 for (i = 0; i < OPD_IMAGE_FILTER_HASH_SIZE; ++i)
00311 list_init(&images_filter[i]);
00312
00313 while ((cur = strchr(last, ',')) != NULL) {
00314 char * tmp = op_xstrndup(last, cur - last);
00315 add_image_filter(tmp);
00316 free(tmp);
00317 last = cur + 1;
00318 }
00319 add_image_filter(last);
00320 }
00321
00322
00323 int is_image_ignored(char const * name)
00324 {
00325 size_t hash;
00326 struct list_head * pos;
00327
00328 if (!binary_name_filter)
00329 return 0;
00330
00331 hash = op_hash_string(name);
00332
00333 list_for_each(pos, &images_filter[hash % OPD_IMAGE_FILTER_HASH_SIZE]) {
00334 struct opd_hashed_name * hashed_name =
00335 list_entry(pos, struct opd_hashed_name, next);
00336 if (!strcmp(hashed_name->name, name))
00337 return 0;
00338 }
00339
00340 return 1;
00341 }
00342
00343
00345 int opd_read_fs_int(char const * path, char const * name, int fatal)
00346 {
00347 char filename[PATH_MAX + 1];
00348 snprintf(filename, PATH_MAX, "%s/%s", path, name);
00349 return op_read_int_from_file(filename, fatal);
00350 }
00351
00352
00353 static void opd_handle_verbose_option(char const * name)
00354 {
00355 if (!strcmp(name, "all")) {
00356 vsfile = 1;
00357 vsamples = 1;
00358 varcs = 1;
00359 vmodule = 1;
00360 vmisc = 1;
00361 vext= 1;
00362 } else if (!strcmp(name, "sfile")) {
00363 vsfile = 1;
00364 } else if (!strcmp(name, "arcs")) {
00365 varcs = 1;
00366 } else if (!strcmp(name, "samples")) {
00367 vsamples = 1;
00368 } else if (!strcmp(name, "module")) {
00369 vmodule = 1;
00370 } else if (!strcmp(name, "misc")) {
00371 vmisc = 1;
00372 } else if (!strcmp(name, "ext")) {
00373 vext= 1;
00374 } else {
00375 fprintf(stderr, "unknown verbose options\n");
00376 exit(EXIT_FAILURE);
00377 }
00378 }
00379
00380 static void opd_parse_verbose(void)
00381 {
00382 char const * last = verbose;
00383 char const * cur = verbose;
00384
00385 if (!verbose)
00386 return;
00387
00388 while ((cur = strchr(last, ',')) != NULL) {
00389 char * tmp = op_xstrndup(last, cur - last);
00390 opd_handle_verbose_option(tmp);
00391 free(tmp);
00392 last = cur + 1;
00393 }
00394 opd_handle_verbose_option(last);
00395 }
00396
00397
00398 static void opd_options(int argc, char const * argv[])
00399 {
00400 poptContext optcon;
00401 char * tmp;
00402
00403 optcon = op_poptGetContext(NULL, argc, argv, options, 0);
00404
00405 if (showvers)
00406 show_version(argv[0]);
00407
00408 opd_parse_verbose();
00409
00410 if (separate_kernel)
00411 separate_lib = 1;
00412
00413 cpu_type = op_get_cpu_type();
00414 op_nr_counters = op_get_nr_counters(cpu_type);
00415
00416 if (!no_vmlinux) {
00417 if (!vmlinux || !strcmp("", vmlinux)) {
00418 fprintf(stderr, "oprofiled: no vmlinux specified.\n");
00419 poptPrintHelp(optcon, stderr, 0);
00420 exit(EXIT_FAILURE);
00421 }
00422
00423
00424 tmp = xmalloc(PATH_MAX);
00425 if (realpath(vmlinux, tmp))
00426 vmlinux = tmp;
00427 else
00428 free(tmp);
00429
00430 if (!kernel_range || !strcmp("", kernel_range)) {
00431 fprintf(stderr, "oprofiled: no kernel VMA range specified.\n");
00432 poptPrintHelp(optcon, stderr, 0);
00433 exit(EXIT_FAILURE);
00434 }
00435 }
00436
00437 if(opd_ext_initialize(ext_feature) != EXIT_SUCCESS)
00438 exit(EXIT_FAILURE);
00439
00440 if (events == NULL && no_event_ok == 0) {
00441 fprintf(stderr, "oprofiled: no events specified.\n");
00442 poptPrintHelp(optcon, stderr, 0);
00443 exit(EXIT_FAILURE);
00444 }
00445
00446 if (!xenimage || !strcmp("", xenimage)) {
00447 no_xen = 1;
00448 } else {
00449 no_xen = 0;
00450
00451
00452 tmp = xmalloc(PATH_MAX);
00453 if (realpath(xenimage, tmp))
00454 xenimage = tmp;
00455 else
00456 free(tmp);
00457
00458 if (!xen_range || !strcmp("", xen_range)) {
00459 fprintf(stderr, "oprofiled: no Xen VMA range specified.\n");
00460 poptPrintHelp(optcon, stderr, 0);
00461 exit(EXIT_FAILURE);
00462 }
00463 }
00464
00465 if (events != NULL)
00466 opd_parse_events(events);
00467
00468 opd_parse_image_filter();
00469
00470 poptFreeContext(optcon);
00471 }
00472
00473
00474
00475
00476
00477 static struct oprofiled_ops * get_ops(void)
00478 {
00479 switch (op_get_interface()) {
00480 case OP_INTERFACE_24:
00481 printf("Using 2.4 OProfile kernel interface.\n");
00482 return &opd_24_ops;
00483 case OP_INTERFACE_26:
00484 printf("Using 2.6+ OProfile kernel interface.\n");
00485 return &opd_26_ops;
00486 default:
00487 break;
00488 }
00489
00490 fprintf(stderr, "Couldn't determine kernel version.\n");
00491 exit(EXIT_FAILURE);
00492 return NULL;
00493 }
00494
00495
00496 int main(int argc, char const * argv[])
00497 {
00498 int err;
00499 struct rlimit rlim = { 2048, 2048 };
00500
00501 opd_options(argc, argv);
00502 init_op_config_dirs(session_dir);
00503
00504 opd_setup_signals();
00505
00506 err = setrlimit(RLIMIT_NOFILE, &rlim);
00507 if (err)
00508 perror("warning: could not set RLIMIT_NOFILE to 2048: ");
00509
00510 opd_write_abi();
00511
00512 opd_ops = get_ops();
00513
00514 opd_ops->init();
00515
00516 opd_go_daemon();
00517
00518
00519 alarm(60 * 10);
00520
00521 if (op_write_lock_file(op_lock_file)) {
00522 fprintf(stderr, "oprofiled: could not create lock file %s\n",
00523 op_lock_file);
00524 exit(EXIT_FAILURE);
00525 }
00526
00527 opd_ops->start();
00528
00529 opd_ops->exit();
00530
00531 return 0;
00532 }