Home | History | Annotate | Download | only in daemon
      1 /**
      2  * @file daemon/init.c
      3  * Daemon set up and main loop for 2.6
      4  *
      5  * @remark Copyright 2002 OProfile authors
      6  * @remark Read the file COPYING
      7  *
      8  * @author John Levon
      9  * @author Philippe Elie
     10  * @Modifications Daniel Hansel
     11  * Modified by Aravind Menon for Xen
     12  * These modifications are:
     13  * Copyright (C) 2005 Hewlett-Packard Co.
     14  */
     15 
     16 #include "config.h"
     17 
     18 #include "oprofiled.h"
     19 #include "opd_stats.h"
     20 #include "opd_sfile.h"
     21 #include "opd_pipe.h"
     22 #include "opd_kernel.h"
     23 #include "opd_trans.h"
     24 #include "opd_anon.h"
     25 #include "opd_perfmon.h"
     26 #include "opd_printf.h"
     27 #include "opd_extended.h"
     28 
     29 #include "op_version.h"
     30 #include "op_config.h"
     31 #include "op_deviceio.h"
     32 #include "op_get_time.h"
     33 #include "op_libiberty.h"
     34 #include "op_fileio.h"
     35 
     36 #include <fcntl.h>
     37 #include <stdio.h>
     38 #include <errno.h>
     39 #include <limits.h>
     40 #include <stdlib.h>
     41 #include <sys/time.h>
     42 #if ANDROID
     43 #include <sys/wait.h>
     44 #else
     45 #include <wait.h>
     46 #endif
     47 #include <string.h>
     48 
     49 size_t kernel_pointer_size;
     50 
     51 static fd_t devfd;
     52 static char * sbuf;
     53 static size_t s_buf_bytesize;
     54 extern char * session_dir;
     55 static char start_time_str[32];
     56 static int jit_conversion_running;
     57 
     58 static void opd_sighup(void);
     59 static void opd_alarm(void);
     60 static void opd_sigterm(void);
     61 static void opd_sigchild(void);
     62 static void opd_do_jitdumps(void);
     63 
     64 /**
     65  * opd_open_files - open necessary files
     66  *
     67  * Open the device files and the log file,
     68  * and mmap() the hash map.
     69  */
     70 static void opd_open_files(void)
     71 {
     72 	devfd = op_open_device("/dev/oprofile/buffer");
     73 	if (devfd == -1) {
     74 		if (errno == EINVAL)
     75 			fprintf(stderr, "Failed to open device. Possibly you have passed incorrect\n"
     76 				"parameters. Check /var/log/messages.");
     77 		else
     78 			perror("Failed to open profile device");
     79 		exit(EXIT_FAILURE);
     80 	}
     81 
     82 	/* give output before re-opening stdout as the logfile */
     83 	printf("Using log file %s\n", op_log_file);
     84 
     85 	/* set up logfile */
     86 	close(0);
     87 	close(1);
     88 
     89 	if (open("/dev/null", O_RDONLY) == -1) {
     90 		perror("oprofiled: couldn't re-open stdin as /dev/null: ");
     91 		exit(EXIT_FAILURE);
     92 	}
     93 
     94 	opd_open_logfile();
     95 	opd_create_pipe();
     96 
     97 	printf("oprofiled started %s", op_get_time());
     98 	printf("kernel pointer size: %lu\n",
     99 		(unsigned long)kernel_pointer_size);
    100 	fflush(stdout);
    101 }
    102 
    103 
    104 /** Done writing out the samples, indicate with complete_dump file */
    105 static void complete_dump(void)
    106 {
    107 	FILE * status_file;
    108 
    109 retry:
    110 	status_file = fopen(op_dump_status, "w");
    111 
    112 	if (!status_file && errno == EMFILE) {
    113 		if (sfile_lru_clear()) {
    114 			printf("LRU cleared but file open fails for %s.\n",
    115 			       op_dump_status);
    116 			abort();
    117 		}
    118 		goto retry;
    119 	}
    120 
    121 	if (!status_file) {
    122 		perror("warning: couldn't set complete_dump: ");
    123 		return;
    124 	}
    125 
    126 	fprintf(status_file, "1\n");
    127 	fclose(status_file);
    128 }
    129 
    130 
    131 /**
    132  * opd_do_samples - process a sample buffer
    133  * @param opd_buf  buffer to process
    134  *
    135  * Process a buffer of samples.
    136  *
    137  * If the sample could be processed correctly, it is written
    138  * to the relevant sample file.
    139  */
    140 static void opd_do_samples(char const * opd_buf, ssize_t count)
    141 {
    142 	size_t num = count / kernel_pointer_size;
    143 
    144 	opd_stats[OPD_DUMP_COUNT]++;
    145 
    146 	verbprintf(vmisc, "Read buffer of %d entries.\n", (unsigned int)num);
    147 
    148 	opd_process_samples(opd_buf, num);
    149 
    150 	complete_dump();
    151 }
    152 
    153 static void opd_do_jitdumps(void)
    154 {
    155 	pid_t childpid;
    156 	int arg_num;
    157 	unsigned long long end_time = 0ULL;
    158 	struct timeval tv;
    159 	char end_time_str[32];
    160 	char opjitconv_path[PATH_MAX + 1];
    161 	char * exec_args[6];
    162 
    163 	if (jit_conversion_running)
    164 		return;
    165 	jit_conversion_running = 1;
    166 
    167 	childpid = fork();
    168 	switch (childpid) {
    169 		case -1:
    170 			perror("Error forking JIT dump process!");
    171 			break;
    172 		case 0:
    173 			gettimeofday(&tv, NULL);
    174 			end_time = tv.tv_sec;
    175 			sprintf(end_time_str, "%llu", end_time);
    176 			sprintf(opjitconv_path, "%s/%s", OP_BINDIR, "opjitconv");
    177 			arg_num = 0;
    178 			exec_args[arg_num++] = "opjitconv";
    179 			if (vmisc)
    180 				exec_args[arg_num++] = "-d";
    181 			exec_args[arg_num++] = session_dir;
    182 			exec_args[arg_num++] = start_time_str;
    183 			exec_args[arg_num++] = end_time_str;
    184 			exec_args[arg_num] = (char *) NULL;
    185 			execvp(opjitconv_path, exec_args);
    186 			fprintf(stderr, "Failed to exec %s: %s\n",
    187 			        exec_args[0], strerror(errno));
    188 			/* We don't want any cleanup in the child */
    189 			_exit(EXIT_FAILURE);
    190 		default:
    191 			break;
    192 	}
    193 
    194 }
    195 
    196 /**
    197  * opd_do_read - enter processing loop
    198  * @param buf  buffer to read into
    199  * @param size  size of buffer
    200  *
    201  * Read some of a buffer from the device and process
    202  * the contents.
    203  */
    204 static void opd_do_read(char * buf, size_t size)
    205 {
    206 	opd_open_pipe();
    207 
    208 	while (1) {
    209 		ssize_t count = -1;
    210 
    211 		/* loop to handle EINTR */
    212 		while (count < 0) {
    213 			count = op_read_device(devfd, buf, size);
    214 
    215 			/* we can lose an alarm or a hup but
    216 			 * we don't care.
    217 			 */
    218 			if (signal_alarm) {
    219 				signal_alarm = 0;
    220 				opd_alarm();
    221 			}
    222 
    223 			if (signal_hup) {
    224 				signal_hup = 0;
    225 				opd_sighup();
    226 			}
    227 
    228 			if (signal_term)
    229 				opd_sigterm();
    230 
    231 			if (signal_child)
    232 				opd_sigchild();
    233 
    234 			if (signal_usr1) {
    235 				signal_usr1 = 0;
    236 				perfmon_start();
    237 			}
    238 
    239 			if (signal_usr2) {
    240 				signal_usr2 = 0;
    241 				perfmon_stop();
    242 			}
    243 
    244 			if (is_jitconv_requested()) {
    245 				verbprintf(vmisc, "Start opjitconv was triggered\n");
    246 				opd_do_jitdumps();
    247 			}
    248 		}
    249 
    250 		opd_do_samples(buf, count);
    251 	}
    252 
    253 	opd_close_pipe();
    254 }
    255 
    256 
    257 /** opd_alarm - sync files and report stats */
    258 static void opd_alarm(void)
    259 {
    260 	sfile_sync_files();
    261 	opd_print_stats();
    262 	alarm(60 * 10);
    263 }
    264 
    265 
    266 /** re-open files for logrotate/opcontrol --reset */
    267 static void opd_sighup(void)
    268 {
    269 	printf("Received SIGHUP.\n");
    270 	/* We just close them, and re-open them lazily as usual. */
    271 	sfile_close_files();
    272 	close(1);
    273 	close(2);
    274 	opd_open_logfile();
    275 }
    276 
    277 
    278 static void clean_exit(void)
    279 {
    280 	perfmon_exit();
    281 	unlink(op_lock_file);
    282 }
    283 
    284 
    285 static void opd_sigterm(void)
    286 {
    287 	opd_do_jitdumps();
    288 	opd_print_stats();
    289 	printf("oprofiled stopped %s", op_get_time());
    290 	opd_ext_deinitialize();
    291 
    292 	exit(EXIT_FAILURE);
    293 }
    294 
    295 /* SIGCHLD received from JIT dump child process. */
    296 static void opd_sigchild(void)
    297 {
    298 	int child_status;
    299 	wait(&child_status);
    300 	jit_conversion_running = 0;
    301 	if (WIFEXITED(child_status) && (!WEXITSTATUS(child_status))) {
    302 		verbprintf(vmisc, "JIT dump processing complete.\n");
    303 	} else {
    304 		printf("JIT dump processing exited abnormally: %d\n",
    305 		       WEXITSTATUS(child_status));
    306 	}
    307 
    308 }
    309 
    310 static void opd_26_init(void)
    311 {
    312 	size_t i;
    313 	size_t opd_buf_size;
    314 	unsigned long long start_time = 0ULL;
    315 	struct timeval tv;
    316 
    317 	opd_create_vmlinux(vmlinux, kernel_range);
    318 	opd_create_xen(xenimage, xen_range);
    319 
    320 	opd_buf_size = opd_read_fs_int("/dev/oprofile/", "buffer_size", 1);
    321 	kernel_pointer_size = opd_read_fs_int("/dev/oprofile/", "pointer_size", 1);
    322 
    323 	s_buf_bytesize = opd_buf_size * kernel_pointer_size;
    324 
    325 	sbuf = xmalloc(s_buf_bytesize);
    326 
    327 	opd_reread_module_info();
    328 
    329 	for (i = 0; i < OPD_MAX_STATS; i++)
    330 		opd_stats[i] = 0;
    331 
    332 	perfmon_init();
    333 
    334 	cookie_init();
    335 	sfile_init();
    336 	anon_init();
    337 
    338 	/* must be /after/ perfmon_init() at least */
    339 	if (atexit(clean_exit)) {
    340 		perfmon_exit();
    341 		perror("oprofiled: couldn't set exit cleanup: ");
    342 		exit(EXIT_FAILURE);
    343 	}
    344 
    345 	/* trigger kernel module setup before returning control to opcontrol */
    346 	opd_open_files();
    347 	gettimeofday(&tv, NULL);
    348 	start_time = 0ULL;
    349 	start_time = tv.tv_sec;
    350 	sprintf(start_time_str, "%llu", start_time);
    351 
    352 }
    353 
    354 
    355 static void opd_26_start(void)
    356 {
    357 	/* simple sleep-then-process loop */
    358 	opd_do_read(sbuf, s_buf_bytesize);
    359 }
    360 
    361 
    362 static void opd_26_exit(void)
    363 {
    364 	opd_print_stats();
    365 	printf("oprofiled stopped %s", op_get_time());
    366 
    367 	free(sbuf);
    368 	free(vmlinux);
    369 	/* FIXME: free kernel images, sfiles etc. */
    370 }
    371 
    372 struct oprofiled_ops opd_26_ops = {
    373 	.init = opd_26_init,
    374 	.start = opd_26_start,
    375 	.exit = opd_26_exit,
    376 };
    377