Home | History | Annotate | Download | only in daemon
      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