From: Erik van der Kouwe Date: Fri, 10 Aug 2012 18:49:40 +0000 (+0000) Subject: Write raw sprofile traces to preserve all information as well as save space X-Git-Tag: v3.2.1~392 X-Git-Url: http://zhaoyanbai.com/repos/html/index.html?a=commitdiff_plain;h=10cbc9bd118166f09cc732913b187c96e10a0686;p=minix.git Write raw sprofile traces to preserve all information as well as save space --- diff --git a/commands/profile/profile.c b/commands/profile/profile.c index 970036de2..bdd4ed65a 100644 --- a/commands/profile/profile.c +++ b/commands/profile/profile.c @@ -23,7 +23,7 @@ #define EMEM 3 #define EOUTFILE 4 #define EFREQ 5 -#define EACTION 6 +#define EACTION 6 #define START 1 #define STOP 2 @@ -75,13 +75,15 @@ int create_named_pipe(void); int alloc_mem(void); int init_outfile(void); int write_outfile(void); -int detach(void); +int write_outfile_cprof(void); +int write_outfile_sprof(void); +void detach(void); int main(int argc, char *argv[]) { int res; - if (res = handle_args(argc, argv)) { + if ((res = handle_args(argc, argv))) { switch(res) { case ESYNTAX: printf("Error in parameters.\n"); @@ -111,7 +113,7 @@ int main(int argc, char *argv[]) * Check the frequency when we know the intr type. Only selected values * are correct for RTC */ - if (action == START && intr_type == PROF_RTC && + if (action == START && intr_type == PROF_RTC && (freq < MIN_FREQ || freq > MAX_FREQ)) { printf("Incorrect frequency.\n"); return 1; @@ -205,7 +207,7 @@ int handle_args(int argc, char *argv[]) action = RESET; } } - + /* No action specified. */ if (!action) return EHELP; @@ -220,7 +222,7 @@ int handle_args(int argc, char *argv[]) if (freq == 0) freq = DEF_FREQ; /* default frequency */ } return 0; -} +} int start() @@ -247,7 +249,7 @@ int start() if (sprofile(PROF_START, mem_size, freq, intr_type, &sprof_info, mem_ptr)) { perror("sprofile"); - printf("Error starting profiling.\n"); + fprintf(stderr, "Error starting profiling.\n"); return 1; } @@ -259,7 +261,7 @@ int start() dup2(log_fd, 2); if ((npipe_fd = open(NPIPE, O_WRONLY)) < 0) { - printf("Unable to open named pipe %s.\n", NPIPE); + fprintf(stderr, "Unable to open named pipe %s.\n", NPIPE); return 1; } else /* Synchronize with stopper process. */ @@ -272,9 +274,9 @@ int start() mem_used = sprof_info.mem_used; if (mem_used == -1) { - printf("WARNING: Profiling was stopped prematurely due to "); - printf("insufficient memory.\n"); - printf("Try increasing available memory using the -m switch.\n"); + fprintf(stderr, "WARNING: Profiling was stopped prematurely due to "); + fprintf(stderr, "insufficient memory.\n"); + fprintf(stderr, "Try increasing available memory using the -m switch.\n"); } if (write_outfile()) return 1; @@ -303,12 +305,12 @@ int stop() if (sprofile(PROF_STOP, 0, 0, 0, 0, 0)) { perror("sprofile"); - printf("Error stopping profiling.\n"); + fprintf(stderr, "Error stopping profiling.\n"); return 1; } else printf("Statistical profiling stopped.\n"); if ((npipe_fd = open(NPIPE, O_RDONLY)) < 0) { - printf("Unable to open named pipe %s.\n", NPIPE); + fprintf(stderr, "Unable to open named pipe %s.\n", NPIPE); return 1; } else /* Synchronize with starter process. */ @@ -338,26 +340,26 @@ int get() if (cprofile(PROF_GET, mem_size, &cprof_info, mem_ptr)) { perror("cprofile"); - printf("Error getting data.\n"); + fprintf(stderr, "Error getting data.\n"); return 1; } mem_used = cprof_info.mem_used; if (mem_used == -1) { - printf("ERROR: unable to get data due to insufficient memory.\n"); - printf("Try increasing available memory using the -m switch.\n"); + fprintf(stderr, "ERROR: unable to get data due to insufficient memory.\n"); + fprintf(stderr, "Try increasing available memory using the -m switch.\n"); } else if (cprof_info.err) { - printf("ERROR: the following error(s) happened during profiling:\n"); + fprintf(stderr, "ERROR: the following error(s) happened during profiling:\n"); if (cprof_info.err & CPROF_CPATH_OVERRUN) - printf(" call path overrun\n"); + fprintf(stderr, " call path overrun\n"); if (cprof_info.err & CPROF_STACK_OVERRUN) - printf(" call stack overrun\n"); + fprintf(stderr, " call stack overrun\n"); if (cprof_info.err & CPROF_TABLE_OVERRUN) - printf(" hash table overrun\n"); - printf("Try changing values in /usr/src/include/minix/profile.h "); - printf("and then rebuild the system.\n"); + fprintf(stderr, " hash table overrun\n"); + fprintf(stderr, "Try changing values in /usr/src/include/minix/profile.h "); + fprintf(stderr, "and then rebuild the system.\n"); } else if (write_outfile()) return 1; @@ -378,7 +380,7 @@ int reset() if (cprofile(PROF_RESET, 0, 0, 0)) { perror("cprofile"); - printf("Error resetting data.\n"); + fprintf(stderr, "Error resetting data.\n"); return 1; } @@ -389,8 +391,8 @@ int reset() int alloc_mem() { if ((mem_ptr = malloc(mem_size)) == 0) { - printf("Unable to allocate memory.\n"); - printf("Used chmem to increase available proces memory?\n"); + fprintf(stderr, "Unable to allocate memory.\n"); + fprintf(stderr, "Used chmem to increase available proces memory?\n"); return 1; } else memset(mem_ptr, '\0', mem_size); @@ -401,7 +403,7 @@ int alloc_mem() int init_outfile() { if ((outfile_fd = open(outfile, O_CREAT | O_TRUNC | O_WRONLY)) <= 0) { - printf("Unable to create outfile %s.\n", outfile); + fprintf(stderr, "Unable to create outfile %s.\n", outfile); return 1; } else chmod(outfile, S_IRUSR | S_IWUSR); @@ -412,14 +414,14 @@ int init_outfile() int create_named_pipe() { if ((mkfifo(NPIPE, S_IRUSR | S_IWUSR) == -1) && (errno != EEXIST)) { - printf("Unable to create named pipe %s.\n", NPIPE); + fprintf(stderr, "Unable to create named pipe %s.\n", NPIPE); return 1; } else return 0; } -int detach() +void detach() { setsid(); (void) chdir("/"); @@ -456,26 +458,46 @@ static char * get_proc_name(endpoint_t ep) int write_outfile() { - int n, towrite, written = 0; - char *buf = mem_ptr; + ssize_t n; + int written; char header[80]; - struct sprof_sample *sample; printf("Writing to %s ...", outfile); /* Write header. */ if (SPROF) - sprintf(header, "stat\n%d %d %d %d\n", sprof_info.total_samples, - sprof_info.idle_samples, - sprof_info.system_samples, - sprof_info.user_samples); + sprintf(header, "stat\n%u %u %u\n", sizeof(struct sprof_info_s), + sizeof(struct sprof_sample), + sizeof(struct sprof_proc)); else sprintf(header, "call\n%u %u\n", CPROF_CPATH_MAX_LEN, CPROF_PROCNAME_LEN); n = write(outfile_fd, header, strlen(header)); - if (n < 0) { printf("Error writing to outfile %s.\n", outfile); return 1; } + if (n < 0) { + fprintf(stderr, "Error writing to outfile %s.\n", outfile); + return 1; + } + + /* for sprofile, raw data will do; cprofile is handled by a script that needs + * some preprocessing to be done by us + */ + if (SPROF) { + written = write_outfile_sprof(); + } else { + written = write_outfile_cprof(); + } + if (written < 0) return -1; + + printf(" header %d bytes, data %d bytes.\n", strlen(header), written); + return 0; +} + +int write_outfile_cprof() +{ + int towrite, written = 0; + struct sprof_sample *sample; /* Write data. */ towrite = mem_used == -1 ? mem_size : mem_used; @@ -500,8 +522,8 @@ int write_outfile() memcpy(entry + 8, &sample->pc, 4); if (write(outfile_fd, entry, 12) != 12) { - printf("Error writing to outfile %s.\n", outfile); - return 1; + fprintf(stderr, "Error writing to outfile %s.\n", outfile); + return -1; } towrite -= sizeof(struct sprof_sample); sample++; @@ -509,8 +531,28 @@ int write_outfile() written += 12; } - printf(" header %d bytes, data %d bytes.\n", strlen(header), written); - - return 0; + return written; } +int write_outfile_sprof() +{ + int towrite; + ssize_t written, written_total = 0; + + /* write profiling totals */ + written = write(outfile_fd, &sprof_info, sizeof(sprof_info)); + if (written != sizeof(sprof_info)) goto error; + written_total += written; + + /* write raw samples */ + towrite = mem_used == -1 ? mem_size : mem_used; + written = write(outfile_fd, mem_ptr, towrite); + if (written != towrite) goto error; + written_total += written; + + return written_total; + +error: + fprintf(stderr, "Error writing to outfile %s.\n", outfile); + return -1; +} diff --git a/commands/sprofalyze/sprofalyze.c b/commands/sprofalyze/sprofalyze.c index ad3125c90..48426ee06 100755 --- a/commands/sprofalyze/sprofalyze.c +++ b/commands/sprofalyze/sprofalyze.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -10,6 +11,8 @@ /* user-configurable settings */ #define BINARY_HASHTAB_SIZE 1024 +#define ENDPOINT_HASHTAB_SIZE 1024 + #define DEBUG 0 #define NM "/usr/pkg/bin/nm" @@ -24,8 +27,6 @@ static const char *src_path = "/usr/src"; /* types */ -#define BINARY_NAME_SIZE 8 - #define LINE_WIDTH 80 #define SYMBOL_NAME_SIZE 52 @@ -56,7 +57,7 @@ struct pc_map_l1 { }; struct binary_info { - char name[BINARY_NAME_SIZE]; + char name[PROC_NAME_LEN]; const char *path; int samples; struct symbol_count *symbols; @@ -66,16 +67,23 @@ struct binary_info { char no_more_warnings; }; -struct trace_sample { - char name[BINARY_NAME_SIZE]; - uint32_t pc; +struct endpoint_info { + endpoint_t endpoint; + struct binary_info *binary; + struct endpoint_info *hashtab_next; +}; + +union sprof_record { + struct sprof_sample sample; + struct sprof_proc proc; }; /* global variables */ static struct binary_info *binaries; static struct binary_info *binary_hashtab[BINARY_HASHTAB_SIZE]; +static struct endpoint_info *endpoint_hashtab[ENDPOINT_HASHTAB_SIZE]; static double minimum_perc = 1.0; -static int samples_idle, samples_system, samples_total, samples_user; +static struct sprof_info_s sprof_info; /* prototypes */ static struct binary_info *binary_add(const char *path); @@ -87,6 +95,8 @@ static const char *binary_name(const char *path); static int compare_binaries(const void *p1, const void *p2); static int compare_symbols(const void *p1, const void *p2); static int count_symbols(const struct binary_info *binary, int threshold); +static void dprint_symbols(const struct binary_info *binary); +static struct endpoint_info **endpoint_hashtab_get_ptr(endpoint_t endpoint); static void load_trace(const char *path); static void *malloc_checked(size_t size); static unsigned name_hash(const char *name); @@ -103,7 +113,11 @@ static int read_newline(FILE *file); static void read_nm_line(FILE *file, int line, char *name, char *type, unsigned long *addr, unsigned long *size); static void read_to_whitespace(FILE *file, char *buffer, size_t size); -static void sample_store(const struct trace_sample *sample); +static size_t sample_process(const union sprof_record *data, size_t size, + int *samples_read); +static struct binary_info *sample_load_binary(const struct sprof_proc *sample); +static void sample_store(struct binary_info *binary, + const struct sprof_sample *sample); static char *strdup_checked(const char *s); static void usage(const char *argv0); @@ -181,7 +195,7 @@ static struct binary_info *binary_add(const char *path) { /* get filename */ name = binary_name(path); dprintf("adding binary \"%s\" with name \"%.*s\"\n", - path, BINARY_NAME_SIZE, name); + path, PROC_NAME_LEN, name); if (strlen(name) == 0) { fprintf(stderr, "error: path \"%s\" does not " "contain a filename\n", path); @@ -195,7 +209,7 @@ static struct binary_info *binary_add(const char *path) { "previously specified\n", path, (*ptr)->path); return *ptr; } - dprintf("using %.*s from \"%s\"\n", BINARY_NAME_SIZE, name, path); + dprintf("using %.*s from \"%s\"\n", PROC_NAME_LEN, name, path); /* allocate new binary_info */ binary = MALLOC_CHECKED(struct binary_info, 1); @@ -232,7 +246,7 @@ static struct binary_info *binary_find(const char *name) { /* search for it */ dprintf("searching for binary \"%.*s\" in \"%s\"\n", - BINARY_NAME_SIZE, name, src_path); + PROC_NAME_LEN, name, src_path); for (i = 0; i < LENGTHOF(default_binaries); i++) { snprintf(path, sizeof(path), "%s/%s", src_path, default_binaries[i]); @@ -241,7 +255,7 @@ static struct binary_info *binary_find(const char *name) { if (*current_name) { /* paths not ending in slash: use if name matches */ if (strncmp(name, current_name, - BINARY_NAME_SIZE) != 0) { + PROC_NAME_LEN) != 0) { continue; } } else { @@ -250,8 +264,8 @@ static struct binary_info *binary_find(const char *name) { */ path_end = path + strlen(path); snprintf(path_end, sizeof(path) - (path_end - path), - "%.*s/%.*s", BINARY_NAME_SIZE, name, - BINARY_NAME_SIZE, name); + "%.*s/%.*s", PROC_NAME_LEN, name, + PROC_NAME_LEN, name); } /* use access to find out whether the binary exists and is @@ -278,11 +292,11 @@ static struct binary_info **binary_hashtab_get_ptr(const char *name) { /* get pointer to location of the binary in hash table */ ptr = &binary_hashtab[name_hash(name) % BINARY_HASHTAB_SIZE]; while ((binary = *ptr) && strncmp(binary->name, name, - BINARY_NAME_SIZE) != 0) { + PROC_NAME_LEN) != 0) { ptr = &binary->hashtab_next; } - dprintf("looked up \"%.*s\" in hash table, %sfound\n", - BINARY_NAME_SIZE, name, *ptr ? "" : "not "); + dprintf("looked up binary \"%.*s\" in hash table, %sfound\n", + PROC_NAME_LEN, name, *ptr ? "" : "not "); return ptr; } @@ -306,12 +320,9 @@ static void binary_load_pc_map(struct binary_info *binary_info) { /* does the file exist? */ if (access(binary_info->path, R_OK) < 0) { - if (!binary_info->no_more_warnings) { - fprintf(stderr, "warning: \"%s\" does not exist or " - "not readable.\n", binary_info->path); - fprintf(stderr, " Did you do a make?\n"); - binary_info->no_more_warnings = 1; - } + fprintf(stderr, "warning: \"%s\" does not exist or " + "not readable.\n", binary_info->path); + fprintf(stderr, " Did you do a make?\n"); return; } @@ -425,11 +436,37 @@ static int count_symbols(const struct binary_info *binary, int threshold) { return result; } +static void dprint_symbols(const struct binary_info *binary) { +#if DEBUG + const struct symbol_count *symbol; + + for (symbol = binary->symbols; symbol; symbol = symbol->next) { + dprintf("addr=0x%.8lx samples=%8d name=\"%.*s\"\n", + (unsigned long) symbol->addr, symbol->samples, + SYMBOL_NAME_SIZE, symbol->name); + } +#endif +} + +static struct endpoint_info **endpoint_hashtab_get_ptr(endpoint_t endpoint) { + struct endpoint_info *epinfo, **ptr; + + /* get pointer to location of the binary in hash table */ + ptr = &endpoint_hashtab[(unsigned) endpoint % ENDPOINT_HASHTAB_SIZE]; + while ((epinfo = *ptr) && epinfo->endpoint != endpoint) { + ptr = &epinfo->hashtab_next; + } + dprintf("looked up endpoint %ld in hash table, %sfound\n", + (long) endpoint, *ptr ? "" : "not "); + return ptr; +} + static void load_trace(const char *path) { + char buffer[1024]; + size_t bufindex, bufsize; FILE *file; - int s_idle, s_system, s_total, s_user; + unsigned size_info, size_sample, size_proc; int samples_read; - struct trace_sample sample; /* open trace file */ file = fopen(path, "rb"); @@ -440,31 +477,54 @@ static void load_trace(const char *path) { } /* check file format and update totals */ - if (fscanf(file, "stat\n%d %d %d %d\n", - &s_total, &s_idle, &s_system, &s_user) != 4) { + if (fscanf(file, "stat\n%u %u %u\n", + &size_info, &size_sample, &size_proc) != 3) { fprintf(stderr, "error: file \"%s\" does not contain an " "sprofile trace\n", path); exit(1); } - samples_total += s_total; - samples_idle += s_idle; - samples_system += s_system; - samples_user += s_user; + if ((size_info != sizeof(struct sprof_info_s)) || + (size_sample != sizeof(struct sprof_sample)) || + (size_proc != sizeof(struct sprof_proc))) { + fprintf(stderr, "error: file \"%s\" is incompatible with this " + "version of sprofalyze; recompile sprofalyze with the " + "MINIX version that created this file\n", path); + exit(1); + } + if (fread(&sprof_info, sizeof(sprof_info), 1, file) != 1) { + fprintf(stderr, "error: totals missing in file \"%s\"\n", path); + exit(1); + } /* read and store samples */ samples_read = 0; - while (fread(&sample, sizeof(sample), 1, file) == 1) { - sample_store(&sample); - samples_read++; + bufindex = 0; + bufsize = 0; + for (;;) { + /* enough left in the buffer? */ + if (bufsize - bufindex < sizeof(union sprof_record)) { + /* not enough, read some more */ + memmove(buffer, buffer + bufindex, bufsize - bufindex); + bufsize -= bufindex; + bufindex = 0; + bufsize += fread(buffer + bufsize, 1, + sizeof(buffer) - bufsize, file); + + /* are we done? */ + if (bufsize == 0) break; + } + + /* process sample record (either struct sprof_sample or + * struct sprof_proc) + */ + bufindex += sample_process( + (const union sprof_record *) (buffer + bufindex), + bufsize - bufindex, &samples_read); } - if (samples_read != s_system) { + if (samples_read != sprof_info.system_samples) { fprintf(stderr, "warning: number of system samples (%d) in " "\"%s\" does not match number of records (%d)\n", - s_system, path, samples_read); - } - if (!feof(file)) { - fprintf(stderr, "warning: partial sample at end of \"%s\", " - "was the trace file truncated?\n", path); + sprof_info.system_samples, path, samples_read); } fclose(file); } @@ -486,10 +546,10 @@ static unsigned name_hash(const char *name) { unsigned r = 0; /* remember: strncpy initializes all bytes */ - for (i = 0; i < BINARY_NAME_SIZE && name[i]; i++) { + for (i = 0; i < PROC_NAME_LEN && name[i]; i++) { r = r * 31 + name[i]; } - dprintf("name_hash(\"%.*s) = 0x%.8x\n", BINARY_NAME_SIZE, name, r); + dprintf("name_hash(\"%.*s\") = 0x%.8x\n", PROC_NAME_LEN, name, r); return r; } @@ -504,16 +564,16 @@ static void print_report(void) { printf("Showing processes and functions using at least %3.0f%% " "time.\n\n", minimum_perc); printf(" System process ticks: %10d (%3.0f%%)\n", - samples_system, percent(samples_system, samples_total)); + sprof_info.system_samples, percent(sprof_info.system_samples, sprof_info.total_samples)); printf(" User process ticks: %10d (%3.0f%%) " "Details of system process\n", - samples_user, percent(samples_user, samples_total)); + sprof_info.user_samples, percent(sprof_info.user_samples, sprof_info.total_samples)); printf(" Idle time ticks: %10d (%3.0f%%) " "samples, aggregated and\n", - samples_idle, percent(samples_idle, samples_total)); + sprof_info.idle_samples, percent(sprof_info.idle_samples, sprof_info.total_samples)); printf(" ---------- ---- " "per process, are below.\n"); - printf(" Total ticks: %10d (100%%)\n\n", samples_total); + printf(" Total ticks: %10d (100%%)\n\n", sprof_info.total_samples); print_report_overall(); print_reports_per_binary(); @@ -526,7 +586,7 @@ static void print_report_overall(void) { int sample_threshold; /* count number of symbols to display */ - sample_threshold = samples_system * minimum_perc / 100; + sample_threshold = sprof_info.system_samples * minimum_perc / 100; symbol_count = 0; for (binary = binaries; binary; binary = binary->next) { symbol_count += count_symbols(binary, sample_threshold); @@ -549,9 +609,9 @@ static void print_report_overall(void) { /* report most common symbols overall */ print_separator(); printf("Total system process time %*d samples\n", - LINE_WIDTH - 34, samples_system); + LINE_WIDTH - 34, sprof_info.system_samples); print_separator(); - print_report_symbols(symbols_sorted, symbol_count, samples_system, 1); + print_report_symbols(symbols_sorted, symbol_count, sprof_info.system_samples, 1); free(symbols_sorted); } @@ -579,8 +639,8 @@ static void print_report_per_binary(const struct binary_info *binary) { /* report most common symbols for this binary */ print_separator(); printf("%-*.*s %4.1f%% of system process samples\n", - LINE_WIDTH - 32, BINARY_NAME_SIZE, binary->name, - percent(binary->samples, samples_system)); + LINE_WIDTH - 32, PROC_NAME_LEN, binary->name, + percent(binary->samples, sprof_info.system_samples)); print_separator(); print_report_symbols(symbols_sorted, symbol_count, binary->samples, 0); free(symbols_sorted); @@ -613,7 +673,7 @@ static void print_reports_per_binary(void) { compare_binaries); /* display reports for binaries with enough samples */ - sample_threshold = samples_system * minimum_perc / 100; + sample_threshold = sprof_info.system_samples * minimum_perc / 100; samples_shown = 0; for (i = 0; i < binary_count; i++) { if (binaries_sorted[i]->samples < sample_threshold) break; @@ -622,8 +682,8 @@ static void print_reports_per_binary(void) { } print_separator(); printf("processes <%3.0f%% (not showing functions) %*.1f%% of system " - "process samples\n", minimum_perc, LINE_WIDTH - 60, - percent(samples_system - samples_shown, samples_system)); + "process samples\n", minimum_perc, LINE_WIDTH - 67, + percent(sprof_info.system_samples - samples_shown, sprof_info.system_samples)); print_separator(); free(binaries_sorted); @@ -636,7 +696,7 @@ static void print_report_symbols(struct symbol_count **symbols, struct symbol_count *symbol; /* find out how much space we have available */ - process_width = show_process ? (BINARY_NAME_SIZE + 1) : 0; + process_width = show_process ? (PROC_NAME_LEN + 1) : 0; bar_width = LINE_WIDTH - process_width - SYMBOL_NAME_WIDTH - 17; /* print the symbol lines */ @@ -647,7 +707,7 @@ static void print_report_symbols(struct symbol_count **symbols, symbol = symbols[i]; printf("%*.*s %*.*s ", process_width, - show_process ? BINARY_NAME_SIZE : 0, + show_process ? PROC_NAME_LEN : 0, symbol->binary->name, SYMBOL_NAME_WIDTH, SYMBOL_NAME_WIDTH, @@ -672,10 +732,10 @@ static void print_report_symbols(struct symbol_count **symbols, /* print remainder and summary */ print_separator(); - printf("%-*.*s%*d 100.0%%\n\n", BINARY_NAME_SIZE, BINARY_NAME_SIZE, + printf("%-*.*s%*d 100.0%%\n\n", PROC_NAME_LEN, PROC_NAME_LEN, (show_process || symbol_count == 0) ? "total" : symbols[0]->binary->name, - LINE_WIDTH - BINARY_NAME_SIZE - 7, total); + LINE_WIDTH - PROC_NAME_LEN - 7, total); } static void print_separator(void) { @@ -786,43 +846,80 @@ static void read_to_whitespace(FILE *file, char *buffer, size_t size) { if (size > 0) *buffer = 0; } -static void sample_store(const struct trace_sample *sample) { +static size_t sample_process(const union sprof_record *data, size_t size, + int *samples_read) { + struct endpoint_info *epinfo, **ptr; + + assert(data); + assert(samples_read); + + /* do we have a proper sample? */ + if (size < sizeof(data->proc) && size < sizeof(data->sample)) { + goto error; + } + + /* do we know this endpoint? */ + ptr = endpoint_hashtab_get_ptr(data->proc.proc); + if ((epinfo = *ptr)) { + /* endpoint known, store sample */ + if (size < sizeof(data->sample)) goto error; + sample_store(epinfo->binary, &data->sample); + (*samples_read)++; + return sizeof(data->sample); + } + + /* endpoint not known, add it */ + *ptr = epinfo = MALLOC_CHECKED(struct endpoint_info, 1); + memset(epinfo, 0, sizeof(struct endpoint_info)); + epinfo->endpoint = data->proc.proc; + + /* fetch binary based on process name in sample */ + if (size < sizeof(data->proc)) goto error; + epinfo->binary = sample_load_binary(&data->proc); + return sizeof(data->proc); + +error: + fprintf(stderr, "warning: partial sample at end of trace, " + "was the trace file truncated?\n"); + return size; +} + +static struct binary_info *sample_load_binary( + const struct sprof_proc *sample) { struct binary_info *binary; - int index_l1; - char path[PATH_MAX + 1]; - struct pc_map_l2 *pc_map_l2; - struct symbol_count *symbol; /* locate binary */ binary = binary_find(sample->name); if (!binary) { fprintf(stderr, "warning: ignoring unknown binary \"%.*s\"\n", - BINARY_NAME_SIZE, sample->name); + PROC_NAME_LEN, sample->name); fprintf(stderr, " did you include this executable in " "the configuration?\n"); fprintf(stderr, " (use -b to add additional " "binaries)\n"); - - /* prevent additional warnings by adding bogus binary */ - snprintf(path, sizeof(path), "/DOESNOTEXIST/%.*s", - BINARY_NAME_SIZE, sample->name); - binary = binary_add(strdup_checked(path)); - binary->no_more_warnings = 1; - return; + return NULL; } /* load symbols if this hasn't been done yet */ - if (!binary->pc_map) { - binary_load_pc_map(binary); - if (!binary->pc_map) return; - } + if (!binary->pc_map) binary_load_pc_map(binary); + + return binary; +} + +static void sample_store(struct binary_info *binary, + const struct sprof_sample *sample) { + unsigned long index_l1; + struct pc_map_l2 *pc_map_l2; + struct symbol_count *symbol; + + if (!binary || !binary->pc_map) return; /* find the applicable symbol (two-level lookup) */ - index_l1 = sample->pc / PC_MAP_L2_SIZE; + index_l1 = (unsigned long) sample->pc / PC_MAP_L2_SIZE; assert(index_l1 < PC_MAP_L1_SIZE); pc_map_l2 = binary->pc_map->l1[index_l1]; if (pc_map_l2) { - symbol = pc_map_l2->l2[sample->pc % PC_MAP_L2_SIZE]; + symbol = pc_map_l2->l2[(unsigned long) sample->pc % PC_MAP_L2_SIZE]; } else { symbol = NULL; } @@ -836,6 +933,7 @@ static void sample_store(const struct trace_sample *sample) { "version\n"); fprintf(stderr, " path: \"%s\"\n", binary->path); binary->no_more_warnings = 1; + dprint_symbols(binary); } } @@ -855,5 +953,18 @@ static void usage(const char *argv0) { printf("usage:\n"); printf(" %s [-p percentage] [-s src-tree-path] " "[-b binary]... file...\n", argv0); + printf("\n"); + printf("sprofalyze aggregates one or more sprofile traces and"); + printf("reports where time was spent.\n"); + printf("\n"); + printf("arguments:\n"); + printf("-p specifies the cut-off percentage below which binaries\n"); + printf(" and functions will not be displayed\n"); + printf("-s specifies the root of the source tree where sprofalyze\n"); + printf(" should search for unstripped binaries to extract symbols\n"); + printf(" from\n"); + printf("-b specifies an additional system binary in the trace that\n"); + printf(" is not in the source tree; may be specified multiple\n"); + printf(" times\n"); exit(1); }