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