~arosales/test/oprofile

« back to all changes in this revision

Viewing changes to daemon/init.c

  • Committer: Antonio Rosales
  • Date: 2013-03-28 08:40:26 UTC
  • Revision ID: antonio.rosales@canonical.com-20130328084026-gpqns1mkqd7cnr05
Move files up one directory.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <wait.h>
 
43
#include <string.h>
 
44
 
 
45
size_t kernel_pointer_size;
 
46
 
 
47
static fd_t devfd;
 
48
static char * sbuf;
 
49
static size_t s_buf_bytesize;
 
50
extern char * session_dir;
 
51
static char start_time_str[32];
 
52
static int jit_conversion_running;
 
53
 
 
54
static void opd_sighup(void);
 
55
static void opd_alarm(void);
 
56
static void opd_sigterm(void);
 
57
static void opd_sigchild(void);
 
58
static void opd_do_jitdumps(void);
 
59
 
 
60
/**
 
61
 * opd_open_files - open necessary files
 
62
 *
 
63
 * Open the device files and the log file,
 
64
 * and mmap() the hash map.
 
65
 */
 
66
static void opd_open_files(void)
 
67
{
 
68
        devfd = op_open_device("/dev/oprofile/buffer");
 
69
        if (devfd == -1) {
 
70
                if (errno == EINVAL)
 
71
                        fprintf(stderr, "Failed to open device. Possibly you have passed incorrect\n"
 
72
                                "parameters. Check /var/log/messages.");
 
73
                else
 
74
                        perror("Failed to open profile device");
 
75
                exit(EXIT_FAILURE);
 
76
        }
 
77
 
 
78
        /* give output before re-opening stdout as the logfile */
 
79
        printf("Using log file %s\n", op_log_file);
 
80
 
 
81
        /* set up logfile */
 
82
        close(0);
 
83
        close(1);
 
84
 
 
85
        if (open("/dev/null", O_RDONLY) == -1) {
 
86
                perror("oprofiled: couldn't re-open stdin as /dev/null: ");
 
87
                exit(EXIT_FAILURE);
 
88
        }
 
89
 
 
90
        opd_open_logfile();
 
91
        opd_create_pipe();
 
92
 
 
93
        printf("oprofiled started %s", op_get_time());
 
94
        printf("kernel pointer size: %lu\n",
 
95
                (unsigned long)kernel_pointer_size);
 
96
        fflush(stdout);
 
97
}
 
98
 
 
99
 
 
100
/** Done writing out the samples, indicate with complete_dump file */
 
101
static void complete_dump(void)
 
102
{
 
103
        FILE * status_file;
 
104
 
 
105
retry:
 
106
        status_file = fopen(op_dump_status, "w");
 
107
 
 
108
        if (!status_file && errno == EMFILE) {
 
109
                if (sfile_lru_clear()) {
 
110
                        printf("LRU cleared but file open fails for %s.\n",
 
111
                               op_dump_status);
 
112
                        abort();
 
113
                }
 
114
                goto retry;
 
115
        }
 
116
 
 
117
        if (!status_file) {
 
118
                perror("warning: couldn't set complete_dump: ");
 
119
                return;
 
120
        }
 
121
 
 
122
        fprintf(status_file, "1\n");
 
123
        fclose(status_file);
 
124
}
 
125
 
 
126
 
 
127
/**
 
128
 * opd_do_samples - process a sample buffer
 
129
 * @param opd_buf  buffer to process
 
130
 *
 
131
 * Process a buffer of samples.
 
132
 *
 
133
 * If the sample could be processed correctly, it is written
 
134
 * to the relevant sample file.
 
135
 */
 
136
static void opd_do_samples(char const * opd_buf, ssize_t count)
 
137
{
 
138
        size_t num = count / kernel_pointer_size;
 
139
 
 
140
        opd_stats[OPD_DUMP_COUNT]++;
 
141
 
 
142
        verbprintf(vmisc, "Read buffer of %d entries.\n", (unsigned int)num);
 
143
 
 
144
        opd_process_samples(opd_buf, num);
 
145
 
 
146
        complete_dump();
 
147
}
 
148
 
 
149
static void opd_do_jitdumps(void)
 
150
 
151
        pid_t childpid;
 
152
        int arg_num;
 
153
        unsigned long long end_time = 0ULL;
 
154
        struct timeval tv;
 
155
        char end_time_str[32];
 
156
        char opjitconv_path[PATH_MAX + 1];
 
157
        char * exec_args[6];
 
158
 
 
159
        if (jit_conversion_running)
 
160
                return;
 
161
        jit_conversion_running = 1;
 
162
 
 
163
        childpid = fork();
 
164
        switch (childpid) {
 
165
                case -1:
 
166
                        perror("Error forking JIT dump process!");
 
167
                        break;
 
168
                case 0:
 
169
                        gettimeofday(&tv, NULL);
 
170
                        end_time = tv.tv_sec;
 
171
                        sprintf(end_time_str, "%llu", end_time);
 
172
                        sprintf(opjitconv_path, "%s/%s", OP_BINDIR, "opjitconv");
 
173
                        arg_num = 0;
 
174
                        exec_args[arg_num++] = "opjitconv";
 
175
                        if (vmisc)
 
176
                                exec_args[arg_num++] = "-d";
 
177
                        exec_args[arg_num++] = session_dir;
 
178
                        exec_args[arg_num++] = start_time_str;
 
179
                        exec_args[arg_num++] = end_time_str;
 
180
                        exec_args[arg_num] = (char *) NULL;
 
181
                        execvp(opjitconv_path, exec_args);
 
182
                        fprintf(stderr, "Failed to exec %s: %s\n",
 
183
                                exec_args[0], strerror(errno));
 
184
                        /* We don't want any cleanup in the child */
 
185
                        _exit(EXIT_FAILURE);
 
186
                default:
 
187
                        break;
 
188
        } 
 
189
 
 
190
 
191
 
 
192
/**
 
193
 * opd_do_read - enter processing loop
 
194
 * @param buf  buffer to read into
 
195
 * @param size  size of buffer
 
196
 *
 
197
 * Read some of a buffer from the device and process
 
198
 * the contents.
 
199
 */
 
200
static void opd_do_read(char * buf, size_t size)
 
201
{
 
202
        opd_open_pipe();
 
203
 
 
204
        while (1) {
 
205
                ssize_t count = -1;
 
206
 
 
207
                /* loop to handle EINTR */
 
208
                while (count < 0) {
 
209
                        count = op_read_device(devfd, buf, size);
 
210
 
 
211
                        /* we can lose an alarm or a hup but
 
212
                         * we don't care.
 
213
                         */
 
214
                        if (signal_alarm) {
 
215
                                signal_alarm = 0;
 
216
                                opd_alarm();
 
217
                        }
 
218
 
 
219
                        if (signal_hup) {
 
220
                                signal_hup = 0;
 
221
                                opd_sighup();
 
222
                        }
 
223
 
 
224
                        if (signal_term)
 
225
                                opd_sigterm();
 
226
 
 
227
                        if (signal_child)
 
228
                                opd_sigchild();
 
229
 
 
230
                        if (signal_usr1) {
 
231
                                signal_usr1 = 0;
 
232
                                perfmon_start();
 
233
                        }
 
234
 
 
235
                        if (signal_usr2) {
 
236
                                signal_usr2 = 0;
 
237
                                perfmon_stop();
 
238
                        }
 
239
 
 
240
                        if (is_jitconv_requested()) {
 
241
                                verbprintf(vmisc, "Start opjitconv was triggered\n");
 
242
                                opd_do_jitdumps();
 
243
                        }
 
244
                }
 
245
 
 
246
                opd_do_samples(buf, count);
 
247
        }
 
248
        
 
249
        opd_close_pipe();
 
250
}
 
251
 
 
252
 
 
253
/** opd_alarm - sync files and report stats */
 
254
static void opd_alarm(void)
 
255
{
 
256
        sfile_sync_files();
 
257
        opd_print_stats();
 
258
        alarm(60 * 10);
 
259
}
 
260
 
 
261
 
 
262
/** re-open files for logrotate/opcontrol --reset */
 
263
static void opd_sighup(void)
 
264
{
 
265
        printf("Received SIGHUP.\n");
 
266
        /* We just close them, and re-open them lazily as usual. */
 
267
        sfile_close_files();
 
268
        close(1);
 
269
        close(2);
 
270
        opd_open_logfile();
 
271
}
 
272
 
 
273
 
 
274
static void clean_exit(void)
 
275
{
 
276
        perfmon_exit();
 
277
        unlink(op_lock_file);
 
278
}
 
279
 
 
280
 
 
281
static void opd_sigterm(void)
 
282
{
 
283
        opd_do_jitdumps();
 
284
        opd_print_stats();
 
285
        printf("oprofiled stopped %s", op_get_time());
 
286
        opd_ext_deinitialize();
 
287
 
 
288
        exit(EXIT_FAILURE);
 
289
}
 
290
 
 
291
/* SIGCHLD received from JIT dump child process. */
 
292
static void opd_sigchild(void)
 
293
{
 
294
        int child_status;
 
295
        wait(&child_status);
 
296
        jit_conversion_running = 0;
 
297
        if (WIFEXITED(child_status) && (!WEXITSTATUS(child_status))) {
 
298
                verbprintf(vmisc, "JIT dump processing complete.\n");
 
299
        } else {
 
300
                printf("JIT dump processing exited abnormally: %d\n",
 
301
                       WEXITSTATUS(child_status));
 
302
        }
 
303
 
 
304
}
 
305
 
 
306
static void opd_26_init(void)
 
307
{
 
308
        size_t i;
 
309
        size_t opd_buf_size;
 
310
        unsigned long long start_time = 0ULL;
 
311
        struct timeval tv;
 
312
 
 
313
        opd_create_vmlinux(vmlinux, kernel_range);
 
314
        opd_create_xen(xenimage, xen_range);
 
315
 
 
316
        opd_buf_size = opd_read_fs_int("/dev/oprofile/", "buffer_size", 1);
 
317
        kernel_pointer_size = opd_read_fs_int("/dev/oprofile/", "pointer_size", 1);
 
318
 
 
319
        s_buf_bytesize = opd_buf_size * kernel_pointer_size;
 
320
 
 
321
        sbuf = xmalloc(s_buf_bytesize);
 
322
 
 
323
        opd_reread_module_info();
 
324
 
 
325
        for (i = 0; i < OPD_MAX_STATS; i++)
 
326
                opd_stats[i] = 0;
 
327
 
 
328
        perfmon_init();
 
329
 
 
330
        cookie_init();
 
331
        sfile_init();
 
332
        anon_init();
 
333
 
 
334
        /* must be /after/ perfmon_init() at least */
 
335
        if (atexit(clean_exit)) {
 
336
                perfmon_exit();
 
337
                perror("oprofiled: couldn't set exit cleanup: ");
 
338
                exit(EXIT_FAILURE);
 
339
        }
 
340
 
 
341
        /* trigger kernel module setup before returning control to opcontrol */
 
342
        opd_open_files();
 
343
        gettimeofday(&tv, NULL);
 
344
        start_time = 0ULL;
 
345
        start_time = tv.tv_sec;
 
346
        sprintf(start_time_str, "%llu", start_time);
 
347
                  
 
348
}
 
349
 
 
350
 
 
351
static void opd_26_start(void)
 
352
{
 
353
        /* simple sleep-then-process loop */
 
354
        opd_do_read(sbuf, s_buf_bytesize);
 
355
}
 
356
 
 
357
 
 
358
static void opd_26_exit(void)
 
359
{
 
360
        opd_print_stats();
 
361
        printf("oprofiled stopped %s", op_get_time());
 
362
 
 
363
        free(sbuf);
 
364
        free(vmlinux);
 
365
        /* FIXME: free kernel images, sfiles etc. */
 
366
}
 
367
 
 
368
struct oprofiled_ops opd_26_ops = {
 
369
        .init = opd_26_init,
 
370
        .start = opd_26_start,
 
371
        .exit = opd_26_exit,
 
372
};