• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
opd_open_logfile(void)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  */
opd_fork(void)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 
opd_go_daemon(void)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 
opd_write_abi(void)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  */
opd_alarm(int val)178 static void opd_alarm(int val __attribute__((unused)))
179 {
180 	signal_alarm = 1;
181 }
182 
183 
184 /* re-open logfile for logrotate */
opd_sighup(int val)185 static void opd_sighup(int val __attribute__((unused)))
186 {
187 	signal_hup = 1;
188 }
189 
190 
opd_sigterm(int val)191 static void opd_sigterm(int val __attribute__((unused)))
192 {
193 	signal_term = 1;
194 }
195 
opd_sigchild(int val)196 static void opd_sigchild(int val __attribute__((unused)))
197 {
198 	signal_child = 1;
199 }
200 
201 
opd_sigusr1(int val)202 static void opd_sigusr1(int val __attribute__((unused)))
203 {
204 	signal_usr1 = 1;
205 }
206 
207 
opd_sigusr2(int val)208 static void opd_sigusr2(int val __attribute__((unused)))
209 {
210 	signal_usr2 = 1;
211 }
212 
213 
opd_setup_signals(void)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 
add_image_filter(char const * name)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 
opd_parse_image_filter(void)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 
is_image_ignored(char const * name)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 */
opd_read_fs_int(char const * path,char const * name,int fatal)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 
opd_handle_verbose_option(char const * name)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 
opd_parse_verbose(void)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 
opd_options(int argc,char const * argv[])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  */
get_ops(void)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 
main(int argc,char const * argv[])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