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