oprofiled.c

Go to the documentation of this file.
00001 
00015 #include "config.h"
00016  
00017 #include "oprofiled.h"
00018 #include "opd_printf.h"
00019 #include "opd_events.h"
00020 #include "opd_extended.h"
00021 
00022 #include "op_config.h"
00023 #include "op_version.h"
00024 #include "op_hw_config.h"
00025 #include "op_libiberty.h"
00026 #include "op_file.h"
00027 #include "op_abi.h"
00028 #include "op_string.h"
00029 #include "op_cpu_type.h"
00030 #include "op_popt.h"
00031 #include "op_lockfile.h"
00032 #include "op_list.h"
00033 #include "op_fileio.h"
00034 
00035 #include <sys/types.h>
00036 #include <sys/resource.h>
00037 #include <stdlib.h>
00038 #include <fcntl.h>
00039 #include <stdio.h>
00040 #include <string.h>
00041 #include <unistd.h>
00042 #include <errno.h>
00043 #include <assert.h>
00044 #include <dirent.h>
00045 #include <limits.h>
00046 
00047 sig_atomic_t signal_alarm;
00048 sig_atomic_t signal_hup;
00049 sig_atomic_t signal_term;
00050 sig_atomic_t signal_child;
00051 sig_atomic_t signal_usr1;
00052 sig_atomic_t signal_usr2;
00053 
00054 uint op_nr_counters;
00055 op_cpu cpu_type;
00056 int no_event_ok;
00057 int vsfile;
00058 int vsamples;
00059 int varcs;
00060 int vmodule;
00061 int vmisc;
00062 int vext;
00063 int separate_lib;
00064 int separate_kernel;
00065 int separate_thread;
00066 int separate_cpu;
00067 int no_vmlinux;
00068 char * vmlinux;
00069 char * kernel_range;
00070 char * session_dir;
00071 int no_xen;
00072 char * xenimage;
00073 char * xen_range;
00074 static char * verbose;
00075 static char * binary_name_filter;
00076 static char * events;
00077 static char * ext_feature;
00078 static int showvers;
00079 static struct oprofiled_ops * opd_ops;
00080 extern struct oprofiled_ops opd_24_ops;
00081 extern struct oprofiled_ops opd_26_ops;
00082 
00083 #define OPD_IMAGE_FILTER_HASH_SIZE 32
00084 static struct list_head images_filter[OPD_IMAGE_FILTER_HASH_SIZE];
00085 
00086 static struct poptOption options[] = {
00087     { "session-dir", 0, POPT_ARG_STRING, &session_dir, 0, "place sample database in dir instead of default location", "/var/lib/oprofile", },
00088     { "kernel-range", 'r', POPT_ARG_STRING, &kernel_range, 0, "Kernel VMA range", "start-end", },
00089     { "vmlinux", 'k', POPT_ARG_STRING, &vmlinux, 0, "vmlinux kernel image", "file", },
00090     { "no-vmlinux", 0, POPT_ARG_NONE, &no_vmlinux, 0, "vmlinux kernel image file not available", NULL, },
00091     { "xen-range", 0, POPT_ARG_STRING, &xen_range, 0, "Xen VMA range", "start-end", },
00092     { "xen-image", 0, POPT_ARG_STRING, &xenimage, 0, "Xen image", "file", },
00093     { "image", 0, POPT_ARG_STRING, &binary_name_filter, 0, "image name filter", "profile these comma separated image" },
00094     { "separate-lib", 0, POPT_ARG_INT, &separate_lib, 0, "separate library samples for each distinct application", "[0|1]", },
00095     { "separate-kernel", 0, POPT_ARG_INT, &separate_kernel, 0, "separate kernel samples for each distinct application", "[0|1]", },
00096     { "separate-thread", 0, POPT_ARG_INT, &separate_thread, 0, "thread-profiling mode", "[0|1]" },
00097     { "separate-cpu", 0, POPT_ARG_INT, &separate_cpu, 0, "separate samples for each CPU", "[0|1]" },
00098     { "events", 'e', POPT_ARG_STRING, &events, 0, "events list", "[events]" },
00099     { "version", 'v', POPT_ARG_NONE, &showvers, 0, "show version", NULL, },
00100     { "verbose", 'V', POPT_ARG_STRING, &verbose, 0, "be verbose in log file", "all,sfile,arcs,samples,module,misc", },
00101     { "ext-feature", 'x', POPT_ARG_STRING, &ext_feature, 1, "enable extended feature", "<extended-feature-name>:[args]", },
00102     POPT_AUTOHELP
00103     { NULL, 0, 0, NULL, 0, NULL, NULL, },
00104 };
00105  
00106 
00107 void opd_open_logfile(void)
00108 {
00109     if (open(op_log_file, O_WRONLY|O_CREAT|O_NOCTTY|O_APPEND, 0644) == -1) {
00110         perror("oprofiled: couldn't re-open stdout: ");
00111         exit(EXIT_FAILURE);
00112     }
00113 
00114     if (dup2(1, 2) == -1) {
00115         perror("oprofiled: couldn't dup stdout to stderr: ");
00116         exit(EXIT_FAILURE);
00117     }
00118 }
00119  
00120 
00127 static void opd_fork(void)
00128 {
00129     switch (fork()) {
00130         case -1:
00131             perror("oprofiled: fork() failed: ");
00132             exit(EXIT_FAILURE);
00133             break;
00134         case 0:
00135             break;
00136         default:
00137             /* parent */
00138             _exit(EXIT_SUCCESS);
00139             break;
00140     }
00141 }
00142 
00143  
00144 static void opd_go_daemon(void)
00145 {
00146     opd_fork();
00147 
00148     if (chdir(op_session_dir)) {
00149         fprintf(stderr, "oprofiled: opd_go_daemon: couldn't chdir to %s: %s",
00150             op_session_dir, strerror(errno));
00151         exit(EXIT_FAILURE);
00152     }
00153 
00154     if (setsid() < 0) {
00155         perror("oprofiled: opd_go_daemon: couldn't setsid: ");
00156         exit(EXIT_FAILURE);
00157     }
00158 
00159     opd_fork();
00160 }
00161 
00162 
00163 static void opd_write_abi(void)
00164 {
00165     char * cbuf;
00166  
00167     cbuf = xmalloc(strlen(op_session_dir) + 5);
00168     strcpy(cbuf, op_session_dir);
00169     strcat(cbuf, "/abi");
00170     op_write_abi_to_file(cbuf);
00171     free(cbuf);
00172 }
00173 
00174 
00178 static void opd_alarm(int val __attribute__((unused)))
00179 {
00180     signal_alarm = 1;
00181 }
00182  
00183 
00184 /* re-open logfile for logrotate */
00185 static void opd_sighup(int val __attribute__((unused)))
00186 {
00187     signal_hup = 1;
00188 }
00189 
00190 
00191 static void opd_sigterm(int val __attribute__((unused)))
00192 {
00193     signal_term = 1;
00194 }
00195 
00196 static void opd_sigchild(int val __attribute__((unused)))
00197 {
00198     signal_child = 1;
00199 }
00200  
00201 
00202 static void opd_sigusr1(int val __attribute__((unused)))
00203 {
00204     signal_usr1 = 1;
00205 }
00206 
00207  
00208 static void opd_sigusr2(int val __attribute__((unused)))
00209 {
00210     signal_usr2 = 1;
00211 }
00212 
00213 
00214 static void opd_setup_signals(void)
00215 {
00216     struct sigaction act;
00217  
00218     act.sa_handler = opd_alarm;
00219     act.sa_flags = 0;
00220     sigemptyset(&act.sa_mask);
00221 
00222     if (sigaction(SIGALRM, &act, NULL)) {
00223         perror("oprofiled: install of SIGALRM handler failed: ");
00224         exit(EXIT_FAILURE);
00225     }
00226 
00227     act.sa_handler = opd_sighup;
00228     act.sa_flags = 0;
00229     sigemptyset(&act.sa_mask);
00230     sigaddset(&act.sa_mask, SIGALRM);
00231 
00232     if (sigaction(SIGHUP, &act, NULL)) {
00233         perror("oprofiled: install of SIGHUP handler failed: ");
00234         exit(EXIT_FAILURE);
00235     }
00236 
00237     act.sa_handler = opd_sigterm;
00238     act.sa_flags = 0;
00239     sigemptyset(&act.sa_mask);
00240     sigaddset(&act.sa_mask, SIGTERM);
00241 
00242     if (sigaction(SIGTERM, &act, NULL)) {
00243         perror("oprofiled: install of SIGTERM handler failed: ");
00244         exit(EXIT_FAILURE);
00245     }
00246 
00247     act.sa_handler = opd_sigchild;
00248     act.sa_flags = 0;
00249     sigemptyset(&act.sa_mask);
00250     sigaddset(&act.sa_mask, SIGCHLD);
00251 
00252     if (sigaction(SIGCHLD, &act, NULL)) {
00253         perror("oprofiled: install of SIGCHLD handler failed: ");
00254         exit(EXIT_FAILURE);
00255     }
00256 
00257     act.sa_handler = opd_sigusr1;
00258     act.sa_flags = 0;
00259     sigemptyset(&act.sa_mask);
00260     sigaddset(&act.sa_mask, SIGTERM);
00261 
00262     if (sigaction(SIGUSR1, &act, NULL)) {
00263         perror("oprofiled: install of SIGUSR1 handler failed: ");
00264         exit(EXIT_FAILURE);
00265     }
00266 
00267     act.sa_handler = opd_sigusr2;
00268     act.sa_flags = 0;
00269     sigemptyset(&act.sa_mask);
00270     sigaddset(&act.sa_mask, SIGTERM);
00271 
00272     if (sigaction(SIGUSR2, &act, NULL)) {
00273         perror("oprofiled: install of SIGUSR2 handler failed: ");
00274         exit(EXIT_FAILURE);
00275     }
00276 }
00277 
00278 
00279 struct opd_hashed_name {
00280     char * name;
00281     struct list_head next;
00282 };
00283 
00284 
00285 static void add_image_filter(char const * name)
00286 {
00287     size_t hash;
00288     struct opd_hashed_name * elt = xmalloc(sizeof(struct opd_hashed_name));
00289     elt->name = xmalloc(PATH_MAX);
00290     if (!realpath(name, elt->name)) {
00291         free(elt->name);
00292         free(elt);
00293         return;
00294     }
00295     hash = op_hash_string(elt->name);
00296     verbprintf(vmisc, "Adding to image filter: \"%s\"\n", elt->name);
00297     list_add(&elt->next, &images_filter[hash % OPD_IMAGE_FILTER_HASH_SIZE]);
00298 }
00299 
00300 
00301 static void opd_parse_image_filter(void)
00302 {
00303     size_t i;
00304     char const * last = binary_name_filter;
00305     char const * cur = binary_name_filter;
00306 
00307     if (!binary_name_filter)
00308         return;
00309 
00310     for (i = 0; i < OPD_IMAGE_FILTER_HASH_SIZE; ++i)
00311         list_init(&images_filter[i]);
00312 
00313     while ((cur = strchr(last, ',')) != NULL) {
00314         char * tmp = op_xstrndup(last, cur - last);
00315         add_image_filter(tmp);
00316         free(tmp);
00317         last = cur + 1;
00318     }
00319     add_image_filter(last);
00320 }
00321 
00322 
00323 int is_image_ignored(char const * name)
00324 {
00325     size_t hash;
00326     struct list_head * pos;
00327 
00328     if (!binary_name_filter)
00329         return 0;
00330     
00331     hash = op_hash_string(name);
00332 
00333     list_for_each(pos, &images_filter[hash % OPD_IMAGE_FILTER_HASH_SIZE]) {
00334         struct opd_hashed_name * hashed_name =
00335             list_entry(pos, struct opd_hashed_name, next);
00336         if (!strcmp(hashed_name->name, name))
00337             return 0;
00338     }
00339 
00340     return 1;
00341 }
00342 
00343 
00345 int opd_read_fs_int(char const * path, char const * name, int fatal)
00346 {
00347     char filename[PATH_MAX + 1];
00348     snprintf(filename, PATH_MAX, "%s/%s", path, name);
00349     return op_read_int_from_file(filename, fatal);
00350 }
00351 
00352 
00353 static void opd_handle_verbose_option(char const * name)
00354 {
00355     if (!strcmp(name, "all")) {
00356         vsfile = 1;
00357         vsamples = 1;
00358         varcs = 1;
00359         vmodule = 1;
00360         vmisc = 1;
00361         vext= 1;
00362     } else if (!strcmp(name, "sfile")) {
00363         vsfile = 1;
00364     } else if (!strcmp(name, "arcs")) {
00365         varcs = 1;
00366     } else if (!strcmp(name, "samples")) {
00367         vsamples = 1;
00368     } else if (!strcmp(name, "module")) {
00369         vmodule = 1;
00370     } else if (!strcmp(name, "misc")) {
00371         vmisc = 1;
00372     } else if (!strcmp(name, "ext")) {
00373         vext= 1;
00374     } else {
00375         fprintf(stderr, "unknown verbose options\n");
00376         exit(EXIT_FAILURE);
00377     }
00378 }
00379 
00380 static void opd_parse_verbose(void)
00381 {
00382     char const * last = verbose;
00383     char const * cur = verbose;
00384 
00385     if (!verbose)
00386         return;
00387 
00388     while ((cur = strchr(last, ',')) != NULL) {
00389         char * tmp = op_xstrndup(last, cur - last);
00390         opd_handle_verbose_option(tmp);
00391         free(tmp);
00392         last = cur + 1;
00393     }
00394     opd_handle_verbose_option(last);
00395 }
00396 
00397 
00398 static void opd_options(int argc, char const * argv[])
00399 {
00400     poptContext optcon;
00401     char * tmp;
00402 
00403     optcon = op_poptGetContext(NULL, argc, argv, options, 0);
00404 
00405     if (showvers)
00406         show_version(argv[0]);
00407 
00408     opd_parse_verbose();
00409 
00410     if (separate_kernel)
00411         separate_lib = 1;
00412 
00413     cpu_type = op_get_cpu_type();
00414     op_nr_counters = op_get_nr_counters(cpu_type);
00415 
00416     if (!no_vmlinux) {
00417         if (!vmlinux || !strcmp("", vmlinux)) {
00418             fprintf(stderr, "oprofiled: no vmlinux specified.\n");
00419             poptPrintHelp(optcon, stderr, 0);
00420             exit(EXIT_FAILURE);
00421         }
00422 
00423         /* canonicalise vmlinux filename. fix #637805 */
00424         tmp = xmalloc(PATH_MAX);
00425         if (realpath(vmlinux, tmp))
00426             vmlinux = tmp;
00427         else
00428             free(tmp);
00429 
00430         if (!kernel_range || !strcmp("", kernel_range)) {
00431             fprintf(stderr, "oprofiled: no kernel VMA range specified.\n");
00432             poptPrintHelp(optcon, stderr, 0);
00433             exit(EXIT_FAILURE);
00434         }
00435     }
00436 
00437     if(opd_ext_initialize(ext_feature) != EXIT_SUCCESS)
00438         exit(EXIT_FAILURE);
00439 
00440     if (events == NULL && no_event_ok == 0) {
00441         fprintf(stderr, "oprofiled: no events specified.\n");
00442         poptPrintHelp(optcon, stderr, 0);
00443         exit(EXIT_FAILURE);
00444     }
00445 
00446     if (!xenimage || !strcmp("", xenimage)) {
00447         no_xen = 1;
00448     } else {
00449         no_xen = 0;
00450 
00451         /* canonicalise xen image filename. */
00452         tmp = xmalloc(PATH_MAX);
00453         if (realpath(xenimage, tmp))
00454             xenimage = tmp;
00455         else
00456             free(tmp);
00457 
00458         if (!xen_range || !strcmp("", xen_range)) {
00459             fprintf(stderr, "oprofiled: no Xen VMA range specified.\n");
00460             poptPrintHelp(optcon, stderr, 0);
00461             exit(EXIT_FAILURE);
00462         }
00463     }
00464 
00465     if (events != NULL)
00466         opd_parse_events(events);
00467 
00468     opd_parse_image_filter();
00469 
00470     poptFreeContext(optcon);
00471 }
00472 
00473 
00474 /* determine what kernel we're running and which daemon
00475  * to use
00476  */
00477 static struct oprofiled_ops * get_ops(void)
00478 {
00479     switch (op_get_interface()) {
00480         case OP_INTERFACE_24:
00481             printf("Using 2.4 OProfile kernel interface.\n");
00482             return &opd_24_ops;
00483         case OP_INTERFACE_26:
00484             printf("Using 2.6+ OProfile kernel interface.\n");
00485             return &opd_26_ops;
00486         default:
00487             break;
00488     }
00489 
00490     fprintf(stderr, "Couldn't determine kernel version.\n");
00491     exit(EXIT_FAILURE);
00492     return NULL;
00493 }
00494 
00495 
00496 int main(int argc, char const * argv[])
00497 {
00498     int err;
00499     struct rlimit rlim = { 2048, 2048 };
00500 
00501     opd_options(argc, argv);
00502     init_op_config_dirs(session_dir);
00503 
00504     opd_setup_signals();
00505 
00506     err = setrlimit(RLIMIT_NOFILE, &rlim);
00507     if (err)
00508         perror("warning: could not set RLIMIT_NOFILE to 2048: ");
00509 
00510     opd_write_abi();
00511 
00512     opd_ops = get_ops();
00513 
00514     opd_ops->init();
00515 
00516     opd_go_daemon();
00517 
00518     /* clean up every 10 minutes */
00519     alarm(60 * 10);
00520 
00521     if (op_write_lock_file(op_lock_file)) {
00522         fprintf(stderr, "oprofiled: could not create lock file %s\n",
00523             op_lock_file);
00524         exit(EXIT_FAILURE);
00525     }
00526 
00527     opd_ops->start();
00528 
00529     opd_ops->exit();
00530 
00531     return 0;
00532 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1