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