1 /** 2 * @file daemon/oprofiled.c 3 * Initialisation and setup 4 * 5 * @remark Copyright 2002, 2003 OProfile authors 6 * @remark Read the file COPYING 7 * 8 * @author John Levon 9 * @author Philippe Elie 10 * Modified by Aravind Menon for Xen 11 * These modifications are: 12 * Copyright (C) 2005 Hewlett-Packard Co. 13 */ 14 15 #include "config.h" 16 17 #include "oprofiled.h" 18 #include "opd_printf.h" 19 #include "opd_events.h" 20 #include "opd_extended.h" 21 22 #include "op_config.h" 23 #include "op_version.h" 24 #include "op_hw_config.h" 25 #include "op_libiberty.h" 26 #include "op_file.h" 27 #include "op_abi.h" 28 #include "op_string.h" 29 #include "op_cpu_type.h" 30 #include "op_popt.h" 31 #include "op_lockfile.h" 32 #include "op_list.h" 33 #include "op_fileio.h" 34 35 #include <sys/types.h> 36 #include <sys/resource.h> 37 #include <stdlib.h> 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <errno.h> 43 #include <assert.h> 44 #include <dirent.h> 45 #include <limits.h> 46 47 sig_atomic_t signal_alarm; 48 sig_atomic_t signal_hup; 49 sig_atomic_t signal_term; 50 sig_atomic_t signal_child; 51 sig_atomic_t signal_usr1; 52 sig_atomic_t signal_usr2; 53 54 uint op_nr_counters; 55 op_cpu cpu_type; 56 int no_event_ok; 57 int vsfile; 58 int vsamples; 59 int varcs; 60 int vmodule; 61 int vmisc; 62 int vext; 63 int separate_lib; 64 int separate_kernel; 65 int separate_thread; 66 int separate_cpu; 67 int no_vmlinux; 68 char * vmlinux; 69 char * kernel_range; 70 char * session_dir; 71 int no_xen; 72 char * xenimage; 73 char * xen_range; 74 static char * verbose; 75 static char * binary_name_filter; 76 static char * events; 77 static char * ext_feature; 78 static int showvers; 79 static struct oprofiled_ops * opd_ops; 80 extern struct oprofiled_ops opd_24_ops; 81 extern struct oprofiled_ops opd_26_ops; 82 83 #define OPD_IMAGE_FILTER_HASH_SIZE 32 84 static struct list_head images_filter[OPD_IMAGE_FILTER_HASH_SIZE]; 85 86 static struct poptOption options[] = { 87 { "session-dir", 0, POPT_ARG_STRING, &session_dir, 0, "place sample database in dir instead of default location", "/var/lib/oprofile", }, 88 { "kernel-range", 'r', POPT_ARG_STRING, &kernel_range, 0, "Kernel VMA range", "start-end", }, 89 { "vmlinux", 'k', POPT_ARG_STRING, &vmlinux, 0, "vmlinux kernel image", "file", }, 90 { "no-vmlinux", 0, POPT_ARG_NONE, &no_vmlinux, 0, "vmlinux kernel image file not available", NULL, }, 91 { "xen-range", 0, POPT_ARG_STRING, &xen_range, 0, "Xen VMA range", "start-end", }, 92 { "xen-image", 0, POPT_ARG_STRING, &xenimage, 0, "Xen image", "file", }, 93 { "image", 0, POPT_ARG_STRING, &binary_name_filter, 0, "image name filter", "profile these comma separated image" }, 94 { "separate-lib", 0, POPT_ARG_INT, &separate_lib, 0, "separate library samples for each distinct application", "[0|1]", }, 95 { "separate-kernel", 0, POPT_ARG_INT, &separate_kernel, 0, "separate kernel samples for each distinct application", "[0|1]", }, 96 { "separate-thread", 0, POPT_ARG_INT, &separate_thread, 0, "thread-profiling mode", "[0|1]" }, 97 { "separate-cpu", 0, POPT_ARG_INT, &separate_cpu, 0, "separate samples for each CPU", "[0|1]" }, 98 { "events", 'e', POPT_ARG_STRING, &events, 0, "events list", "[events]" }, 99 { "version", 'v', POPT_ARG_NONE, &showvers, 0, "show version", NULL, }, 100 { "verbose", 'V', POPT_ARG_STRING, &verbose, 0, "be verbose in log file", "all,sfile,arcs,samples,module,misc", }, 101 { "ext-feature", 'x', POPT_ARG_STRING, &ext_feature, 1, "enable extended feature", "<extended-feature-name>:[args]", }, 102 POPT_AUTOHELP 103 { NULL, 0, 0, NULL, 0, NULL, NULL, }, 104 }; 105 106 107 void opd_open_logfile(void) 108 { 109 if (open(op_log_file, O_WRONLY|O_CREAT|O_NOCTTY|O_APPEND, 0644) == -1) { 110 perror("oprofiled: couldn't re-open stdout: "); 111 exit(EXIT_FAILURE); 112 } 113 114 if (dup2(1, 2) == -1) { 115 perror("oprofiled: couldn't dup stdout to stderr: "); 116 exit(EXIT_FAILURE); 117 } 118 } 119 120 121 /** 122 * opd_fork - fork and return as child 123 * 124 * fork() and exit the parent with _exit(). 125 * Failure is fatal. 126 */ 127 static void opd_fork(void) 128 { 129 switch (fork()) { 130 case -1: 131 perror("oprofiled: fork() failed: "); 132 exit(EXIT_FAILURE); 133 break; 134 case 0: 135 break; 136 default: 137 /* parent */ 138 _exit(EXIT_SUCCESS); 139 break; 140 } 141 } 142 143 144 static void opd_go_daemon(void) 145 { 146 opd_fork(); 147 148 if (chdir(op_session_dir)) { 149 fprintf(stderr, "oprofiled: opd_go_daemon: couldn't chdir to %s: %s", 150 op_session_dir, strerror(errno)); 151 exit(EXIT_FAILURE); 152 } 153 154 if (setsid() < 0) { 155 perror("oprofiled: opd_go_daemon: couldn't setsid: "); 156 exit(EXIT_FAILURE); 157 } 158 159 opd_fork(); 160 } 161 162 163 static void opd_write_abi(void) 164 { 165 char * cbuf; 166 167 cbuf = xmalloc(strlen(op_session_dir) + 5); 168 strcpy(cbuf, op_session_dir); 169 strcat(cbuf, "/abi"); 170 op_write_abi_to_file(cbuf); 171 free(cbuf); 172 } 173 174 175 /** 176 * opd_alarm - sync files and report stats 177 */ 178 static void opd_alarm(int val __attribute__((unused))) 179 { 180 signal_alarm = 1; 181 } 182 183 184 /* re-open logfile for logrotate */ 185 static void opd_sighup(int val __attribute__((unused))) 186 { 187 signal_hup = 1; 188 } 189 190 191 static void opd_sigterm(int val __attribute__((unused))) 192 { 193 signal_term = 1; 194 } 195 196 static void opd_sigchild(int val __attribute__((unused))) 197 { 198 signal_child = 1; 199 } 200 201 202 static void opd_sigusr1(int val __attribute__((unused))) 203 { 204 signal_usr1 = 1; 205 } 206 207 208 static void opd_sigusr2(int val __attribute__((unused))) 209 { 210 signal_usr2 = 1; 211 } 212 213 214 static void opd_setup_signals(void) 215 { 216 struct sigaction act; 217 218 act.sa_handler = opd_alarm; 219 act.sa_flags = 0; 220 sigemptyset(&act.sa_mask); 221 222 if (sigaction(SIGALRM, &act, NULL)) { 223 perror("oprofiled: install of SIGALRM handler failed: "); 224 exit(EXIT_FAILURE); 225 } 226 227 act.sa_handler = opd_sighup; 228 act.sa_flags = 0; 229 sigemptyset(&act.sa_mask); 230 sigaddset(&act.sa_mask, SIGALRM); 231 232 if (sigaction(SIGHUP, &act, NULL)) { 233 perror("oprofiled: install of SIGHUP handler failed: "); 234 exit(EXIT_FAILURE); 235 } 236 237 act.sa_handler = opd_sigterm; 238 act.sa_flags = 0; 239 sigemptyset(&act.sa_mask); 240 sigaddset(&act.sa_mask, SIGTERM); 241 242 if (sigaction(SIGTERM, &act, NULL)) { 243 perror("oprofiled: install of SIGTERM handler failed: "); 244 exit(EXIT_FAILURE); 245 } 246 247 act.sa_handler = opd_sigchild; 248 act.sa_flags = 0; 249 sigemptyset(&act.sa_mask); 250 sigaddset(&act.sa_mask, SIGCHLD); 251 252 if (sigaction(SIGCHLD, &act, NULL)) { 253 perror("oprofiled: install of SIGCHLD handler failed: "); 254 exit(EXIT_FAILURE); 255 } 256 257 act.sa_handler = opd_sigusr1; 258 act.sa_flags = 0; 259 sigemptyset(&act.sa_mask); 260 sigaddset(&act.sa_mask, SIGTERM); 261 262 if (sigaction(SIGUSR1, &act, NULL)) { 263 perror("oprofiled: install of SIGUSR1 handler failed: "); 264 exit(EXIT_FAILURE); 265 } 266 267 act.sa_handler = opd_sigusr2; 268 act.sa_flags = 0; 269 sigemptyset(&act.sa_mask); 270 sigaddset(&act.sa_mask, SIGTERM); 271 272 if (sigaction(SIGUSR2, &act, NULL)) { 273 perror("oprofiled: install of SIGUSR2 handler failed: "); 274 exit(EXIT_FAILURE); 275 } 276 } 277 278 279 struct opd_hashed_name { 280 char * name; 281 struct list_head next; 282 }; 283 284 285 static void add_image_filter(char const * name) 286 { 287 size_t hash; 288 struct opd_hashed_name * elt = xmalloc(sizeof(struct opd_hashed_name)); 289 elt->name = xmalloc(PATH_MAX); 290 if (!realpath(name, elt->name)) { 291 free(elt->name); 292 free(elt); 293 return; 294 } 295 hash = op_hash_string(elt->name); 296 verbprintf(vmisc, "Adding to image filter: \"%s\"\n", elt->name); 297 list_add(&elt->next, &images_filter[hash % OPD_IMAGE_FILTER_HASH_SIZE]); 298 } 299 300 301 static void opd_parse_image_filter(void) 302 { 303 size_t i; 304 char const * last = binary_name_filter; 305 char const * cur = binary_name_filter; 306 307 if (!binary_name_filter) 308 return; 309 310 for (i = 0; i < OPD_IMAGE_FILTER_HASH_SIZE; ++i) 311 list_init(&images_filter[i]); 312 313 while ((cur = strchr(last, ',')) != NULL) { 314 char * tmp = op_xstrndup(last, cur - last); 315 add_image_filter(tmp); 316 free(tmp); 317 last = cur + 1; 318 } 319 add_image_filter(last); 320 } 321 322 323 int is_image_ignored(char const * name) 324 { 325 size_t hash; 326 struct list_head * pos; 327 328 if (!binary_name_filter) 329 return 0; 330 331 hash = op_hash_string(name); 332 333 list_for_each(pos, &images_filter[hash % OPD_IMAGE_FILTER_HASH_SIZE]) { 334 struct opd_hashed_name * hashed_name = 335 list_entry(pos, struct opd_hashed_name, next); 336 if (!strcmp(hashed_name->name, name)) 337 return 0; 338 } 339 340 return 1; 341 } 342 343 344 /** return the int in the given oprofilefs file */ 345 int opd_read_fs_int(char const * path, char const * name, int fatal) 346 { 347 char filename[PATH_MAX + 1]; 348 snprintf(filename, PATH_MAX, "%s/%s", path, name); 349 return op_read_int_from_file(filename, fatal); 350 } 351 352 353 static void opd_handle_verbose_option(char const * name) 354 { 355 if (!strcmp(name, "all")) { 356 vsfile = 1; 357 vsamples = 1; 358 varcs = 1; 359 vmodule = 1; 360 vmisc = 1; 361 vext= 1; 362 } else if (!strcmp(name, "sfile")) { 363 vsfile = 1; 364 } else if (!strcmp(name, "arcs")) { 365 varcs = 1; 366 } else if (!strcmp(name, "samples")) { 367 vsamples = 1; 368 } else if (!strcmp(name, "module")) { 369 vmodule = 1; 370 } else if (!strcmp(name, "misc")) { 371 vmisc = 1; 372 } else if (!strcmp(name, "ext")) { 373 vext= 1; 374 } else { 375 fprintf(stderr, "unknown verbose options\n"); 376 exit(EXIT_FAILURE); 377 } 378 } 379 380 static void opd_parse_verbose(void) 381 { 382 char const * last = verbose; 383 char const * cur = verbose; 384 385 if (!verbose) 386 return; 387 388 while ((cur = strchr(last, ',')) != NULL) { 389 char * tmp = op_xstrndup(last, cur - last); 390 opd_handle_verbose_option(tmp); 391 free(tmp); 392 last = cur + 1; 393 } 394 opd_handle_verbose_option(last); 395 } 396 397 398 static void opd_options(int argc, char const * argv[]) 399 { 400 poptContext optcon; 401 char * tmp; 402 403 optcon = op_poptGetContext(NULL, argc, argv, options, 0); 404 405 if (showvers) 406 show_version(argv[0]); 407 408 opd_parse_verbose(); 409 410 if (separate_kernel) 411 separate_lib = 1; 412 413 cpu_type = op_get_cpu_type(); 414 op_nr_counters = op_get_nr_counters(cpu_type); 415 416 if (!no_vmlinux) { 417 if (!vmlinux || !strcmp("", vmlinux)) { 418 fprintf(stderr, "oprofiled: no vmlinux specified.\n"); 419 poptPrintHelp(optcon, stderr, 0); 420 exit(EXIT_FAILURE); 421 } 422 423 /* canonicalise vmlinux filename. fix #637805 */ 424 tmp = xmalloc(PATH_MAX); 425 if (realpath(vmlinux, tmp)) 426 vmlinux = tmp; 427 else 428 free(tmp); 429 430 if (!kernel_range || !strcmp("", kernel_range)) { 431 fprintf(stderr, "oprofiled: no kernel VMA range specified.\n"); 432 poptPrintHelp(optcon, stderr, 0); 433 exit(EXIT_FAILURE); 434 } 435 } 436 437 if(opd_ext_initialize(ext_feature) != EXIT_SUCCESS) 438 exit(EXIT_FAILURE); 439 440 if (events == NULL && no_event_ok == 0) { 441 fprintf(stderr, "oprofiled: no events specified.\n"); 442 poptPrintHelp(optcon, stderr, 0); 443 exit(EXIT_FAILURE); 444 } 445 446 if (!xenimage || !strcmp("", xenimage)) { 447 no_xen = 1; 448 } else { 449 no_xen = 0; 450 451 /* canonicalise xen image filename. */ 452 tmp = xmalloc(PATH_MAX); 453 if (realpath(xenimage, tmp)) 454 xenimage = tmp; 455 else 456 free(tmp); 457 458 if (!xen_range || !strcmp("", xen_range)) { 459 fprintf(stderr, "oprofiled: no Xen VMA range specified.\n"); 460 poptPrintHelp(optcon, stderr, 0); 461 exit(EXIT_FAILURE); 462 } 463 } 464 465 if (events != NULL) 466 opd_parse_events(events); 467 468 opd_parse_image_filter(); 469 470 poptFreeContext(optcon); 471 } 472 473 474 /* determine what kernel we're running and which daemon 475 * to use 476 */ 477 static struct oprofiled_ops * get_ops(void) 478 { 479 switch (op_get_interface()) { 480 #ifndef ANDROID 481 case OP_INTERFACE_24: 482 printf("Using 2.4 OProfile kernel interface.\n"); 483 return &opd_24_ops; 484 #endif 485 case OP_INTERFACE_26: 486 printf("Using 2.6+ OProfile kernel interface.\n"); 487 return &opd_26_ops; 488 default: 489 break; 490 } 491 492 fprintf(stderr, "Couldn't determine kernel version.\n"); 493 exit(EXIT_FAILURE); 494 return NULL; 495 } 496 497 498 int main(int argc, char const * argv[]) 499 { 500 int err; 501 struct rlimit rlim = { 2048, 2048 }; 502 503 opd_options(argc, argv); 504 init_op_config_dirs(session_dir); 505 506 opd_setup_signals(); 507 508 err = setrlimit(RLIMIT_NOFILE, &rlim); 509 if (err) 510 perror("warning: could not set RLIMIT_NOFILE to 2048: "); 511 512 opd_write_abi(); 513 514 opd_ops = get_ops(); 515 516 opd_ops->init(); 517 518 opd_go_daemon(); 519 520 /* clean up every 10 minutes */ 521 alarm(60 * 10); 522 523 if (op_write_lock_file(op_lock_file)) { 524 fprintf(stderr, "oprofiled: could not create lock file %s\n", 525 op_lock_file); 526 exit(EXIT_FAILURE); 527 } 528 529 opd_ops->start(); 530 531 opd_ops->exit(); 532 533 return 0; 534 } 535