• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
opd_open_files(void)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 */
complete_dump(void)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  */
opd_do_samples(char const * opd_buf,ssize_t count)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 
opd_do_jitdumps(void)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  */
opd_do_read(char * buf,size_t size)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 */
opd_alarm(void)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 */
opd_sighup(void)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 
clean_exit(void)278 static void clean_exit(void)
279 {
280 	perfmon_exit();
281 	unlink(op_lock_file);
282 }
283 
284 
opd_sigterm(void)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. */
opd_sigchild(void)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 
opd_26_init(void)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 
opd_26_start(void)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 
opd_26_exit(void)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