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