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