blob: 281f10f7cab937b3aab6c7fef86bf786ccacde09 [file] [log] [blame]
Upstreamcc2ee171970-01-12 13:46:40 +00001/**
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");
The Android Open Source Project48ae5fc2008-10-21 07:00:00 -0700427 //return &opd_24_ops;
428 return 0; // android. we should never need that.
Upstreamcc2ee171970-01-12 13:46:40 +0000429 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}