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