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