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
46 sig_atomic_t signal_alarm;
47 sig_atomic_t signal_hup;
48 sig_atomic_t signal_term;
49 sig_atomic_t signal_child;
50 sig_atomic_t signal_usr1;
51 sig_atomic_t signal_usr2;
52
53 uint op_nr_counters;
54 op_cpu cpu_type;
55 int vsfile;
56 int vsamples;
57 int varcs;
58 int vmodule;
59 int vmisc;
60 int separate_lib;
61 int separate_kernel;
62 int separate_thread;
63 int separate_cpu;
64 int no_vmlinux;
65 char * vmlinux;
66 char * kernel_range;
67 char * session_dir;
68 int no_xen;
69 char * xenimage;
70 char * xen_range;
71 static char * verbose;
72 static char * binary_name_filter;
73 static char * events;
74 static int showvers;
75 static struct oprofiled_ops * opd_ops;
76 extern struct oprofiled_ops opd_24_ops;
77 extern struct oprofiled_ops opd_26_ops;
78
79 #define OPD_IMAGE_FILTER_HASH_SIZE 32
80 static struct list_head images_filter[OPD_IMAGE_FILTER_HASH_SIZE];
81
82 static 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
opd_open_logfile(void)102 void 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 */
opd_fork(void)122 static 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
opd_go_daemon(void)139 static 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
opd_write_abi(void)158 static 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 */
opd_alarm(int val)173 static void opd_alarm(int val __attribute__((unused)))
174 {
175 signal_alarm = 1;
176 }
177
178
179 /* re-open logfile for logrotate */
opd_sighup(int val)180 static void opd_sighup(int val __attribute__((unused)))
181 {
182 signal_hup = 1;
183 }
184
185
opd_sigterm(int val)186 static void opd_sigterm(int val __attribute__((unused)))
187 {
188 signal_term = 1;
189 }
190
opd_sigchild(int val)191 static void opd_sigchild(int val __attribute__((unused)))
192 {
193 signal_child = 1;
194 }
195
196
opd_sigusr1(int val)197 static void opd_sigusr1(int val __attribute__((unused)))
198 {
199 signal_usr1 = 1;
200 }
201
202
opd_sigusr2(int val)203 static void opd_sigusr2(int val __attribute__((unused)))
204 {
205 signal_usr2 = 1;
206 }
207
208
opd_setup_signals(void)209 static 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
274 struct opd_hashed_name {
275 char * name;
276 struct list_head next;
277 };
278
279
add_image_filter(char const * name)280 static 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
opd_parse_image_filter(void)296 static 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
is_image_ignored(char const * name)318 int 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 */
opd_read_fs_int(char const * path,char const * name,int fatal)340 int 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
opd_handle_verbose_option(char const * name)348 static 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
opd_parse_verbose(void)372 static 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
opd_options(int argc,char const * argv[])390 static 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 */
get_ops(void)465 static 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
main(int argc,char const * argv[])486 int 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