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