00001
00012 #include "config.h"
00013
00014 #include "opd_proc.h"
00015 #include "opd_mapping.h"
00016 #include "opd_24_stats.h"
00017 #include "opd_sample_files.h"
00018 #include "opd_image.h"
00019 #include "opd_parse_proc.h"
00020 #include "opd_kernel.h"
00021 #include "opd_printf.h"
00022 #include "oprofiled.h"
00023
00024 #include "op_sample_file.h"
00025 #include "op_config_24.h"
00026 #include "op_interface.h"
00027 #include "op_libiberty.h"
00028 #include "op_deviceio.h"
00029 #include "op_events.h"
00030 #include "op_get_time.h"
00031 #include "op_fileio.h"
00032
00033 #include <stdio.h>
00034 #include <errno.h>
00035 #include <fcntl.h>
00036 #include <unistd.h>
00037 #include <stdlib.h>
00038
00039 fd_t hashmapdevfd;
00040
00041 int cpu_number;
00042
00043 static fd_t devfd;
00044 static fd_t notedevfd;
00045 static struct op_buffer_head * sbuf;
00046 static size_t s_buf_bytesize;
00047 static struct op_note * nbuf;
00048 static size_t n_buf_bytesize;
00049
00050 static void opd_sighup(void);
00051 static void opd_alarm(void);
00052 static void opd_sigterm(void);
00053
00054
00061 static void op_open_files(void)
00062 {
00063 hashmapdevfd = op_open_device(op_hash_device);
00064 if (hashmapdevfd == -1) {
00065 perror("Failed to open hash map device");
00066 exit(EXIT_FAILURE);
00067 }
00068
00069 notedevfd = op_open_device(op_note_device);
00070 if (notedevfd == -1) {
00071 if (errno == EINVAL)
00072 fprintf(stderr, "Failed to open note device. Possibly you have passed incorrect\n"
00073 "parameters. Check /var/log/messages.");
00074 else
00075 perror("Failed to open note device");
00076 exit(EXIT_FAILURE);
00077 }
00078
00079 devfd = op_open_device(op_device);
00080 if (devfd == -1) {
00081 if (errno == EINVAL)
00082 fprintf(stderr, "Failed to open device. Possibly you have passed incorrect\n"
00083 "parameters. Check /var/log/messages.");
00084 else
00085 perror("Failed to open profile device");
00086 exit(EXIT_FAILURE);
00087 }
00088
00089 opd_init_hash_map();
00090
00091
00092 printf("Using log file %s\n", op_log_file);
00093
00094
00095 close(0);
00096 close(1);
00097
00098 if (open("/dev/null", O_RDONLY) == -1) {
00099 perror("oprofiled: couldn't re-open stdin as /dev/null: ");
00100 exit(EXIT_FAILURE);
00101 }
00102
00103 opd_open_logfile();
00104
00105 printf("oprofiled started %s", op_get_time());
00106 fflush(stdout);
00107 }
00108
00109
00110 static void opd_do_samples(struct op_buffer_head const * buf);
00111 static void opd_do_notes(struct op_note const * opd_buf, size_t count);
00112
00120 static void opd_shutdown(struct op_buffer_head * buf, size_t size, struct op_note * nbuf, size_t nsize)
00121 {
00122 ssize_t count = -1;
00123 ssize_t ncount = -1;
00124
00125
00126
00127 if (fcntl(devfd, F_SETFL, fcntl(devfd, F_GETFL) | O_NONBLOCK) < 0) {
00128 perror("Failed to set non-blocking read for device: ");
00129 exit(EXIT_FAILURE);
00130 }
00131
00132
00133 while (ncount < 0)
00134 ncount = op_read_device(notedevfd, nbuf, nsize);
00135
00136 if (ncount > 0)
00137 opd_do_notes(nbuf, ncount);
00138
00139
00140
00141
00142
00143
00144
00145 while (1) {
00146 count = op_read_device(devfd, buf, size);
00147 if (count < 0 && errno == EAGAIN)
00148 break;
00149 verbprintf(vmisc, "Shutting down, state %d\n", buf->state);
00150 opd_do_samples(buf);
00151 }
00152 }
00153
00154
00165 static void opd_do_read(struct op_buffer_head * buf, size_t size, struct op_note * nbuf, size_t nsize)
00166 {
00167 while (1) {
00168 ssize_t count = -1;
00169 ssize_t ncount = -1;
00170
00171
00172 while (count < 0)
00173 count = op_read_device(devfd, buf, size);
00174
00175 while (ncount < 0)
00176 ncount = op_read_device(notedevfd, nbuf, nsize);
00177
00178 opd_do_notes(nbuf, ncount);
00179 opd_do_samples(buf);
00180
00181
00182
00183 if (signal_alarm) {
00184 signal_alarm = 0;
00185 opd_alarm();
00186 }
00187
00188 if (signal_hup) {
00189 signal_hup = 0;
00190 opd_sighup();
00191 }
00192
00193 if (signal_term)
00194 opd_sigterm();
00195
00196
00197 if (buf->state == STOPPING) {
00198 verbprintf(vmisc, "Shutting down by request.\n");
00199 opd_shutdown(buf, size, nbuf, nsize);
00200 return;
00201 }
00202 }
00203 }
00204
00212 static void opd_do_notes(struct op_note const * opd_buf, size_t count)
00213 {
00214 uint i;
00215 struct op_note const * note;
00216
00217 for (i = 0; i < count/sizeof(struct op_note); i++) {
00218 note = &opd_buf[i];
00219
00220 opd_24_stats[OPD_NOTIFICATIONS]++;
00221
00222 switch (note->type) {
00223 case OP_MAP:
00224 case OP_EXEC:
00225 if (note->type == OP_EXEC)
00226 opd_handle_exec(note->pid, note->tgid);
00227 opd_handle_mapping(note);
00228 break;
00229
00230 case OP_FORK:
00231 opd_handle_fork(note);
00232 break;
00233
00234 case OP_DROP_MODULES:
00235 opd_clear_module_info();
00236 break;
00237
00238 case OP_EXIT:
00239 opd_handle_exit(note);
00240 break;
00241
00242 default:
00243 fprintf(stderr, "Received unknown notification type %u\n", note->type);
00244 abort();
00245 break;
00246 }
00247 }
00248 }
00249
00262 static void opd_do_samples(struct op_buffer_head const * opd_buf)
00263 {
00264 uint i;
00265 struct op_sample const * buffer = opd_buf->buffer;
00266
00267 opd_24_stats[OPD_DUMP_COUNT]++;
00268
00269 verbprintf(vmisc, "Read buffer of %d entries for cpu %d.\n",
00270 (unsigned int)opd_buf->count, opd_buf->cpu_nr);
00271
00272 if (separate_cpu)
00273 cpu_number = opd_buf->cpu_nr;
00274 for (i = 0; i < opd_buf->count; i++) {
00275 verbprintf(vsamples, "%.6u: EIP: 0x%.8lx pid: %.6d\n",
00276 i, buffer[i].eip, buffer[i].pid);
00277 opd_put_sample(&buffer[i]);
00278 }
00279 }
00280
00281
00285 static void opd_alarm(void)
00286 {
00287 opd_sync_samples_files();
00288
00289 opd_age_procs();
00290
00291 opd_print_24_stats();
00292
00293 alarm(60 * 10);
00294 }
00295
00296
00297
00298 static void opd_sighup(void)
00299 {
00300 printf("Received SIGHUP.\n");
00301 close(1);
00302 close(2);
00303 opd_open_logfile();
00304
00305 opd_for_each_image(opd_close_image_samples_files);
00306 }
00307
00308
00309 static void clean_exit(void)
00310 {
00311 opd_cleanup_hash_name();
00312 op_free_events();
00313 unlink(op_lock_file);
00314 }
00315
00316
00317 static void opd_sigterm(void)
00318 {
00319 opd_print_24_stats();
00320 printf("oprofiled stopped %s", op_get_time());
00321 exit(EXIT_FAILURE);
00322 }
00323
00324
00325 static void opd_24_init(void)
00326 {
00327 size_t i;
00328 int opd_buf_size = OP_DEFAULT_BUF_SIZE;
00329 int opd_note_buf_size = OP_DEFAULT_NOTE_SIZE;
00330
00331 if (!no_vmlinux)
00332 opd_parse_kernel_range(kernel_range);
00333 opd_buf_size = opd_read_fs_int(OP_MOUNT, "bufsize", 1);
00334 opd_note_buf_size = opd_read_fs_int(OP_MOUNT, "notesize", 1);
00335
00336 s_buf_bytesize = sizeof(struct op_buffer_head) + opd_buf_size * sizeof(struct op_sample);
00337
00338 sbuf = xmalloc(s_buf_bytesize);
00339
00340 n_buf_bytesize = opd_note_buf_size * sizeof(struct op_note);
00341 nbuf = xmalloc(n_buf_bytesize);
00342
00343 opd_init_images();
00344 opd_init_procs();
00345 opd_init_kernel_image();
00346
00347 for (i = 0; i < OPD_MAX_STATS; i++)
00348 opd_24_stats[i] = 0;
00349
00350 if (atexit(clean_exit)) {
00351 perror("oprofiled: couldn't set exit cleanup: ");
00352 exit(EXIT_FAILURE);
00353 }
00354 }
00355
00356
00357 static void opd_24_start(void)
00358 {
00359 op_open_files();
00360
00361
00362 opd_get_ascii_procs();
00363
00364
00365 opd_do_read(sbuf, s_buf_bytesize, nbuf, n_buf_bytesize);
00366 }
00367
00368
00369 static void opd_24_exit(void)
00370 {
00371 opd_print_24_stats();
00372 printf("oprofiled stopped %s", op_get_time());
00373
00374 free(sbuf);
00375 free(nbuf);
00376 opd_clear_module_info();
00377 opd_proc_cleanup();
00378
00379 opd_for_each_image(opd_delete_image);
00380 }
00381
00382
00383 struct oprofiled_ops opd_24_ops = {
00384 .init = opd_24_init,
00385 .start = opd_24_start,
00386 .exit = opd_24_exit
00387 };