From: Philippe E. <ph...@us...> - 2004-01-18 02:21:47
|
Update of /cvsroot/oprofile/oprofile/daemon In directory sc8-pr-cvs1:/tmp/cvs-serv25275/daemon Modified Files: init.c opd_events.c opd_events.h opd_interface.h opd_mangling.c opd_mangling.h opd_sfile.c opd_sfile.h opd_stats.c opd_stats.h opd_trans.c opd_trans.h oprofiled.c oprofiled.h Log Message: merge BRANCH_CALLGRAPH to HEAD Index: init.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/init.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -p -d -r1.3 -r1.4 --- init.c 9 Nov 2003 17:58:23 -0000 1.3 +++ init.c 18 Jan 2004 02:21:13 -0000 1.4 @@ -222,8 +222,8 @@ static void opd_26_init(void) opd_create_vmlinux(vmlinux, kernel_range); - opd_buf_size = opd_read_fs_int("/dev/oprofile/", "buffer_size"); - kernel_pointer_size = opd_read_fs_int("/dev/oprofile/", "pointer_size"); + opd_buf_size = opd_read_fs_int("/dev/oprofile/", "buffer_size", 1); + kernel_pointer_size = opd_read_fs_int("/dev/oprofile/", "pointer_size", 1); s_buf_bytesize = opd_buf_size * kernel_pointer_size; Index: opd_events.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_events.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -p -d -r1.1 -r1.2 --- opd_events.c 27 Oct 2003 02:27:25 -0000 1.1 +++ opd_events.c 18 Jan 2004 02:21:13 -0000 1.2 @@ -141,7 +141,7 @@ struct opd_event * find_counter_event(un void fill_header(struct opd_header * header, unsigned long counter, - int is_kernel, time_t mtime) + int is_kernel, int cg_to_is_kernel, time_t mtime) { struct opd_event * event = find_counter_event(counter); @@ -153,6 +153,7 @@ void fill_header(struct opd_header * hea header->ctr_count = event->count; header->ctr_um = event->um; header->is_kernel = is_kernel; + header->cg_to_is_kernel = cg_to_is_kernel; header->cpu_speed = cpu_speed; header->mtime = mtime; } Index: opd_events.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_events.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -p -d -r1.1 -r1.2 --- opd_events.h 27 Oct 2003 02:27:25 -0000 1.1 +++ opd_events.h 18 Jan 2004 02:21:13 -0000 1.2 @@ -37,6 +37,6 @@ struct opd_header; /** fill the sample file header with event info etc. */ void fill_header(struct opd_header * header, unsigned long counter, - int is_kernel, time_t mtime); + int is_kernel, int cg_to_is_kernel, time_t mtime); #endif /* OPD_EVENTS_H */ Index: opd_interface.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_interface.h,v retrieving revision 1.2 retrieving revision 1.3 diff -u -p -d -r1.2 -r1.3 --- opd_interface.h 24 Sep 2003 21:21:14 -0000 1.2 +++ opd_interface.h 18 Jan 2004 02:21:13 -0000 1.3 @@ -20,6 +20,8 @@ #define KERNEL_EXIT_SWITCH_CODE 5 #define MODULE_LOADED_CODE 6 #define CTX_TGID_CODE 7 -#define LAST_CODE 8 +#define TRACE_BEGIN_CODE 8 +#define TRACE_END_CODE 9 +#define LAST_CODE 10 #endif /* OPD_INTERFACE_H */ Index: opd_mangling.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_mangling.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -p -d -r1.14 -r1.15 --- opd_mangling.c 27 Oct 2003 02:27:25 -0000 1.14 +++ opd_mangling.c 18 Jan 2004 02:21:13 -0000 1.15 @@ -33,7 +33,7 @@ static char const * get_dep_name(struct sfile const * sf) { - /* don't add a useless depname */ + /* avoid to call find_cookie(), caller can recover using image_name */ if (sf->cookie == sf->app_cookie) return NULL; @@ -48,7 +48,8 @@ static char const * get_dep_name(struct } -static char * mangle_filename(struct sfile const * sf, int counter) +static char * +mangle_filename(struct sfile * last, struct sfile const * sf, int counter, int cg) { char * mangled; struct mangle_values values; @@ -67,8 +68,8 @@ static char * mangle_filename(struct sfi return NULL; values.dep_name = get_dep_name(sf); - if (values.dep_name) - values.flags |= MANGLE_DEP_NAME; + if (!values.dep_name) + values.dep_name = values.image_name; if (separate_thread) { values.flags |= MANGLE_TGID | MANGLE_TID; @@ -81,6 +82,16 @@ static char * mangle_filename(struct sfi values.cpu = sf->cpu; } + if (cg) { + values.flags |= MANGLE_CALLGRAPH; + if (last->kernel) + values.cg_image_name = last->kernel->name; + else + values.cg_image_name = find_cookie(last->cookie); + if (!values.cg_image_name) + return NULL; + } + values.event_name = event->name; values.count = event->count; values.unit_mask = event->um; @@ -91,16 +102,14 @@ static char * mangle_filename(struct sfi } -int opd_open_sample_file(struct sfile * sf, int counter) +int opd_open_sample_file(samples_odb_t * file, struct sfile * last, + struct sfile * sf, int counter, int cg) { char * mangled; - samples_odb_t * file; char const * binary; int err; - file = &sf->files[counter]; - - mangled = mangle_filename(sf, counter); + mangled = mangle_filename(last, sf, counter, cg); if (!mangled) return EINVAL; @@ -109,7 +118,7 @@ int opd_open_sample_file(struct sfile * create_path(mangled); - sfile_get(sf); + sfile_get(sf); /* locking sf will lock associated cg files too */ retry: err = odb_open(file, mangled, ODB_RDWR, sizeof(struct opd_header)); @@ -135,6 +144,7 @@ retry: binary = sf->kernel->name; fill_header(file->base_memory, counter, !!sf->kernel, + last ? !!last->kernel : 0, binary ? op_get_mtime(binary) : 0); out: Index: opd_mangling.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_mangling.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -p -d -r1.1 -r1.2 --- opd_mangling.h 24 Sep 2003 21:21:15 -0000 1.1 +++ opd_mangling.h 18 Jan 2004 02:21:13 -0000 1.2 @@ -12,18 +12,22 @@ #ifndef OPD_MANGLING_H #define OPD_MANGLING_H +#include "odb_hash.h" + struct sfile; /* * opd_open_sample_file - open a sample file * @param sf sfile to open sample file for * @param counter counter number + * @param cg if this is a callgraph file * * Open image sample file for the sfile, counter * counter and set up memory mappings for it. * * Returns 0 on success. */ -int opd_open_sample_file(struct sfile * sf, int counter); +int opd_open_sample_file(samples_odb_t * file, struct sfile * last, + struct sfile * sf, int counter, int cg); #endif /* OPD_MANGLING_H */ Index: opd_sfile.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_sfile.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -p -d -r1.14 -r1.15 --- opd_sfile.c 4 Nov 2003 04:26:45 -0000 1.14 +++ opd_sfile.c 18 Jan 2004 02:21:13 -0000 1.15 @@ -122,9 +122,11 @@ create_sfile(struct transient const * tr sf->cpu = 0; sf->kernel = ki; - for (i = 0 ; i < op_nr_counters ; ++i) { + for (i = 0 ; i < op_nr_counters ; ++i) odb_init(&sf->files[i]); - } + + for (i = 0; i < CG_HASH_TABLE_SIZE; ++i) + list_init(&sf->cg_files[i]); if (separate_thread) { sf->tid = trans->tid; @@ -195,16 +197,96 @@ lru: } -static samples_odb_t * get_file(struct sfile * sf, uint counter) +static size_t cg_hash(cookie_t from, cookie_t to, size_t counter) { - if (!sf->files[counter].base_memory) - opd_open_sample_file(sf, counter); + /* FIXME: better hash ? */ + return ((from >> 32) ^ from ^ (to >> 32) ^ to ^ counter) % CG_HASH_TABLE_SIZE; +} + + +static samples_odb_t * get_file(struct sfile * sf, struct sfile * last, + uint counter, int cg) +{ + samples_odb_t * file = &sf->files[counter]; + + if (cg) { + struct cg_hash_entry * temp; + size_t hash = cg_hash(last->cookie, sf->cookie, counter); + struct list_head * pos; + list_for_each(pos, &sf->cg_files[hash]) { + temp = list_entry(pos, struct cg_hash_entry, next); + if (temp->from == last->cookie && + temp->to == sf->cookie && + temp->counter == counter) + break; + } + + if (pos == &sf->cg_files[hash]) { + temp = xmalloc(sizeof(struct cg_hash_entry)); + odb_init(&temp->file); + temp->from = last->cookie; + temp->to = sf->cookie; + temp->counter = counter; + list_add(&temp->next, &sf->cg_files[hash]); + } else { + temp = list_entry(pos, struct cg_hash_entry, next); + } + + file = &temp->file; + } + + if (!file->base_memory) + opd_open_sample_file(file, last, sf, counter, cg); /* Error is logged by opd_open_sample_file */ - if (!sf->files[counter].base_memory) + if (!file->base_memory) return NULL; - return &sf->files[counter]; + return file; +} + + +static void sfile_log_arc(struct transient const * trans) +{ + int err; + vma_t from = trans->pc; + vma_t to = trans->last_pc; + uint64_t key; + samples_odb_t * file; + + file = get_file(trans->current, trans->last, trans->event, 1); + + /* absolute value -> offset */ + if (trans->current->kernel) + to -= trans->current->kernel->start; + + if (trans->last->kernel) + from -= trans->last->kernel->start; + +#if 0 + if (verbose) + verbose_sample(sf, pc, counter); +#endif + + if (!file) { + opd_stats[OPD_LOST_SAMPLEFILE]++; + return; + } + +#if 0 + opd_stats[OPD_SAMPLES]++; + opd_stats[sf->kernel ? OPD_KERNEL : OPD_PROCESS]++; +#endif + + /* Possible narrowings to 32-bit value only. */ + key = to & (0xffffffff); + key |= ((uint64_t)from) << 32; + + err = odb_insert(file, key, 1); + if (err) { + fprintf(stderr, "%s\n", strerror(err)); + abort(); + } } @@ -218,26 +300,38 @@ static void verbose_sample(struct sfile } -void sfile_log_sample(struct sfile * sf, vma_t pc, uint counter) +void sfile_log_sample(struct transient const * trans) { int err; - samples_odb_t * file = get_file(sf, counter); + vma_t pc = trans->pc; + samples_odb_t * file; + + if (trans->tracing == TRACING_ON) { + /* can happen if kernel sample falls through the cracks, + * see opd_put_sample() */ + if (trans->last) + sfile_log_arc(trans); + return; + } + + file = get_file(trans->current, trans->last, trans->event, 0); /* absolute value -> offset */ - if (sf->kernel) - pc -= sf->kernel->start; + if (trans->current->kernel) + pc -= trans->current->kernel->start; if (verbose) - verbose_sample(sf, pc, counter); + verbose_sample(trans->current, pc, trans->event); - if (!file) + if (!file) { + opd_stats[OPD_LOST_SAMPLEFILE]++; return; + } opd_stats[OPD_SAMPLES]++; - opd_stats[sf->kernel ? OPD_KERNEL : OPD_PROCESS]++; + opd_stats[trans->current->kernel ? OPD_KERNEL : OPD_PROCESS]++; - /* Possible narrowing to 32-bit value only. */ - err = odb_insert(file, (unsigned long)pc, 1); + err = odb_insert(file, (uint64_t)pc, 1); if (err) { fprintf(stderr, "%s\n", strerror(err)); abort(); @@ -248,9 +342,22 @@ void sfile_log_sample(struct sfile * sf, static void kill_sfile(struct sfile * sf) { size_t i; + /* it's OK to close a non-open odb file */ for (i = 0; i < op_nr_counters; ++i) odb_close(&sf->files[i]); + + for (i = 0 ; i < CG_HASH_TABLE_SIZE; ++i) { + struct list_head * pos, * pos2; + list_for_each_safe(pos, pos2, &sf->cg_files[i]) { + struct cg_hash_entry * temp = + list_entry(pos, struct cg_hash_entry, next); + odb_close(&temp->file); + list_del(pos); + free(temp); + } + } + list_del(&sf->lru); list_del(&sf->hash); free(sf); @@ -281,6 +388,15 @@ void sfile_sync_files(void) sf = list_entry(pos, struct sfile, lru); for (i = 0; i < op_nr_counters; ++i) odb_sync(&sf->files[i]); + + for (i = 0 ; i < CG_HASH_TABLE_SIZE; ++i) { + struct list_head * pos; + list_for_each(pos, &sf->cg_files[i]) { + struct cg_hash_entry * temp = + list_entry(pos, struct cg_hash_entry, next); + odb_sync(&temp->file); + } + } } } @@ -295,6 +411,15 @@ void sfile_close_files(void) sf = list_entry(pos, struct sfile, lru); for (i = 0; i < op_nr_counters; ++i) odb_close(&sf->files[i]); + + for (i = 0 ; i < CG_HASH_TABLE_SIZE; ++i) { + struct list_head * pos; + list_for_each(pos, &sf->cg_files[i]) { + struct cg_hash_entry * temp = + list_entry(pos, struct cg_hash_entry, next); + odb_close(&temp->file); + } + } } } Index: opd_sfile.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_sfile.h,v retrieving revision 1.5 retrieving revision 1.6 diff -u -p -d -r1.5 -r1.6 --- opd_sfile.h 26 Oct 2003 00:21:07 -0000 1.5 +++ opd_sfile.h 18 Jan 2004 02:21:13 -0000 1.6 @@ -24,6 +24,18 @@ struct kernel_image; struct transient; +#define CG_HASH_TABLE_SIZE 16 + +struct cg_hash_entry { + /** cg are indexable by { from, to, counter } */ + cookie_t from; + cookie_t to; + unsigned int counter; + /** next in the hash slot */ + struct list_head next; + samples_odb_t file; +}; + /** * Each set of sample files (where a set is over the * physical counter types) will have one of these @@ -52,6 +64,9 @@ struct sfile { int ignored; /** opened sample files */ samples_odb_t files[OP_MAX_COUNTERS]; + /** hash table of opened cg sample files, this table is hashed + * on counter nr, from cookie and to cookie */ + struct list_head cg_files[CG_HASH_TABLE_SIZE]; }; /** clear any sfiles that are for the kernel */ @@ -80,7 +95,7 @@ void sfile_put(struct sfile * sf); struct sfile * sfile_find(struct transient const * trans); /** Log the sample in a previously located sfile. */ -void sfile_log_sample(struct sfile * sf, vma_t pc, uint counter); +void sfile_log_sample(struct transient const * trans); /** initialise hashes */ void sfile_init(void); Index: opd_stats.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_stats.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -p -d -r1.7 -r1.8 --- opd_stats.c 24 Sep 2003 21:21:17 -0000 1.7 +++ opd_stats.c 18 Jan 2004 02:21:13 -0000 1.8 @@ -10,9 +10,11 @@ */ #include "opd_stats.h" +#include "oprofiled.h" #include "op_get_time.h" +#include <dirent.h> #include <stdlib.h> #include <stdio.h> @@ -23,12 +25,41 @@ unsigned long opd_stats[OPD_MAX_STATS]; */ void opd_print_stats(void) { + DIR * dir; + struct dirent * dirent; + printf("\n%s\n", op_get_time()); printf("Nr. sample dumps: %lu\n", opd_stats[OPD_DUMP_COUNT]); printf("Nr. samples total: %lu\n", opd_stats[OPD_SAMPLES]); printf("Nr. kernel samples: %lu\n", opd_stats[OPD_KERNEL]); printf("Nr. lost samples (no kernel/user): %lu\n", opd_stats[OPD_NO_CTX]); printf("Nr. lost kernel samples: %lu\n", opd_stats[OPD_LOST_KERNEL]); + printf("Nr. samples lost due to sample file open failure: %lu\n", + opd_stats[OPD_LOST_SAMPLEFILE]); printf("Nr. incomplete code structs: %lu\n", opd_stats[OPD_DANGLING_CODE]); + printf("Nr. event lost due to buffer overflow: %u\n", + opd_read_fs_int("/dev/oprofile/stats", "event_lost_overflow", 0)); + printf("Nr. samples without file mapping: %u\n", + opd_read_fs_int("/dev/oprofile/stats", "sample_lost_no_mapping", 0)); + printf("Nr. samples without mm: %u\n", + opd_read_fs_int("/dev/oprofile/stats", "sample_lost_no_mm", 0)); + + if (!(dir = opendir("/dev/oprofile/stats/"))) + return; + while ((dirent = readdir(dir))) { + int cpu_nr; + char filename[256]; + if (sscanf(dirent->d_name, "cpu%d", &cpu_nr) != 1) + continue; + snprintf(filename, 256, + "/dev/oprofile/stats/%s", dirent->d_name); + printf("Nr. samples lost cpu buffer overflow: %u\n", + opd_read_fs_int(filename, "sample_lost_overflow", 0)); + printf("Nr. samples lost task exit: %u\n", + opd_read_fs_int(filename, "sample_lost_task_exit", 0)); + printf("Nr. samples received: %u\n", + opd_read_fs_int(filename, "sample_received", 0)); + } + closedir(dir); fflush(stdout); } Index: opd_stats.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_stats.h,v retrieving revision 1.6 retrieving revision 1.7 diff -u -p -d -r1.6 -r1.7 --- opd_stats.h 24 Sep 2003 21:21:17 -0000 1.6 +++ opd_stats.h 18 Jan 2004 02:21:13 -0000 1.7 @@ -19,6 +19,7 @@ enum { OPD_SAMPLES, /* nr. samples */ OPD_PROCESS, /* nr. userspace samples */ OPD_NO_CTX, /* nr. samples lost due to not knowing if in the kernel or not */ OPD_LOST_KERNEL, /* nr. kernel samples lost */ + OPD_LOST_SAMPLEFILE, /**< nr samples for which sample file can't be opened */ OPD_DUMP_COUNT, /* nr. of times buffer is read */ OPD_DANGLING_CODE, /* nr. partial code notifications (buffer overflow */ OPD_MAX_STATS /* end of stats */ Index: opd_trans.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_trans.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -p -d -r1.5 -r1.6 --- opd_trans.c 26 Oct 2003 00:21:07 -0000 1.5 +++ opd_trans.c 18 Jan 2004 02:21:13 -0000 1.6 @@ -75,6 +75,9 @@ static void opd_put_sample(struct transi event = pop_buffer_value(trans); + if (trans->tracing != TRACING_ON) + trans->event = event; + trans->pc = pc; /* sfile can change at each sample for kernel */ @@ -87,12 +90,22 @@ static void opd_put_sample(struct transi /* can happen if kernel sample falls through the cracks */ if (!trans->current) - return; + goto out; if (trans->current->ignored) - return; + goto out; - sfile_log_sample(trans->current, trans->pc, event); + /* log the sample or arc */ + sfile_log_sample(trans); + +out: + /* switch to trace mode */ + if (trans->tracing == TRACING_START) + trans->tracing = TRACING_ON; + + /* used for callgraph only */ + trans->last = trans->current; + trans->last_pc = trans->pc; } @@ -192,6 +205,20 @@ static void code_module_loaded(struct tr } +static void code_trace_begin(struct transient * trans) +{ + verbprintf("TRACE_BEGIN\n"); + trans->tracing = TRACING_START; +} + + +static void code_trace_end(struct transient * trans) +{ + verbprintf("TRACE_END\n"); + trans->tracing = TRACING_OFF; +} + + typedef void (*handler_t)(struct transient *); static handler_t handlers[LAST_CODE + 1] = { @@ -202,7 +229,9 @@ static handler_t handlers[LAST_CODE + 1] &code_kernel_enter, &code_kernel_exit, &code_module_loaded, - &code_unknown /* tgid handled differently */ + &code_unknown, /* tgid handled differently */ + &code_trace_begin, + &code_trace_end, }; @@ -211,10 +240,14 @@ void opd_process_samples(char const * bu struct transient trans = { .buffer = buffer, .remaining = count, + .tracing = TRACING_OFF, .current = NULL, + .last = NULL, .cookie = 0, .app_cookie = 0, .pc = 0, + .last_pc = 0, + .event = 0, .in_kernel = -1, .cpu = -1, .tid = -1, Index: opd_trans.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/opd_trans.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -p -d -r1.1 -r1.2 --- opd_trans.h 24 Sep 2003 21:21:17 -0000 1.1 +++ opd_trans.h 18 Jan 2004 02:21:13 -0000 1.2 @@ -17,6 +17,12 @@ struct sfile; +enum tracing_type { + TRACING_OFF, + TRACING_START, + TRACING_ON +}; + /** * Transient values used for parsing the event buffer. * Note that these are reset for each buffer read, but @@ -26,10 +32,14 @@ struct sfile; struct transient { char const * buffer; size_t remaining; + enum tracing_type tracing; struct sfile * current; + struct sfile * last; cookie_t cookie; cookie_t app_cookie; vma_t pc; + vma_t last_pc; + unsigned long event; int in_kernel; unsigned long cpu; pid_t tid; Index: oprofiled.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/oprofiled.c,v retrieving revision 1.70 retrieving revision 1.71 diff -u -p -d -r1.70 -r1.71 --- oprofiled.c 13 Nov 2003 15:22:57 -0000 1.70 +++ oprofiled.c 18 Jan 2004 02:21:13 -0000 1.71 @@ -318,11 +318,11 @@ int is_image_ignored(char const * name) /** return the int in the given oprofilefs file */ -int opd_read_fs_int(char const * path, char const * name) +int opd_read_fs_int(char const * path, char const * name, int fatal) { char filename[PATH_MAX + 1]; snprintf(filename, PATH_MAX, "%s/%s", path, name); - return op_read_int_from_file(filename); + return op_read_int_from_file(filename, fatal); } Index: oprofiled.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/daemon/oprofiled.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -p -d -r1.3 -r1.4 --- oprofiled.h 9 Nov 2003 17:58:23 -0000 1.3 +++ oprofiled.h 18 Jan 2004 02:21:13 -0000 1.4 @@ -49,8 +49,8 @@ size_t opd_hash_name(char const * name); */ int is_image_ignored(char const * name); -/** return the int in the given oprofilefs file */ -int opd_read_fs_int(char const * path, char const * name); +/** return the int in the given oprofilefs file, error is fatal if !is_fatal */ +int opd_read_fs_int(char const * path, char const * name, int is_fatal); /** global variable positioned by signal handler */ |