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 48 size_t kernel_pointer_size; 49 50 static fd_t devfd; 51 static char * sbuf; 52 static size_t s_buf_bytesize; 53 extern char * session_dir; 54 static char start_time_str[32]; 55 static int jit_conversion_running; 56 57 static void opd_sighup(void); 58 static void opd_alarm(void); 59 static void opd_sigterm(void); 60 static void opd_sigchild(void); 61 static 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 */ 69 static 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 */ 104 static void complete_dump(void) 105 { 106 FILE * status_file; 107 108 retry: 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 */ 139 static 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 152 static 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 */ 203 static 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 */ 257 static 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 */ 266 static 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 277 static void clean_exit(void) 278 { 279 perfmon_exit(); 280 unlink(op_lock_file); 281 } 282 283 284 static 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. */ 293 static 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 307 static 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 352 static void opd_26_start(void) 353 { 354 /* simple sleep-then-process loop */ 355 opd_do_read(sbuf, s_buf_bytesize); 356 } 357 358 359 static 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 369 struct oprofiled_ops opd_26_ops = { 370 .init = opd_26_init, 371 .start = opd_26_start, 372 .exit = opd_26_exit, 373 }; 374