#define EMEM 3
#define EOUTFILE 4
#define EFREQ 5
-#define EACTION 6
+#define EACTION 6
#define START 1
#define STOP 2
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");
* 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;
action = RESET;
}
}
-
+
/* No action specified. */
if (!action) return EHELP;
if (freq == 0) freq = DEF_FREQ; /* default frequency */
}
return 0;
-}
+}
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;
}
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. */
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;
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. */
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;
if (cprofile(PROF_RESET, 0, 0, 0)) {
perror("cprofile");
- printf("Error resetting data.\n");
+ fprintf(stderr, "Error resetting data.\n");
return 1;
}
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);
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);
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("/");
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;
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++;
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;
+}
#include <ctype.h>
#include <errno.h>
#include <limits.h>
+#include <minix/profile.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* user-configurable settings */
#define BINARY_HASHTAB_SIZE 1024
+#define ENDPOINT_HASHTAB_SIZE 1024
+
#define DEBUG 0
#define NM "/usr/pkg/bin/nm"
/* types */
-#define BINARY_NAME_SIZE 8
-
#define LINE_WIDTH 80
#define SYMBOL_NAME_SIZE 52
};
struct binary_info {
- char name[BINARY_NAME_SIZE];
+ char name[PROC_NAME_LEN];
const char *path;
int samples;
struct symbol_count *symbols;
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);
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);
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);
/* 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);
"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);
/* 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]);
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 {
*/
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
/* 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;
}
/* 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;
}
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");
}
/* 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);
}
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;
}
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();
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);
/* 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);
}
/* 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);
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;
}
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);
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 */
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,
/* 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) {
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;
}
"version\n");
fprintf(stderr, " path: \"%s\"\n", binary->path);
binary->no_more_warnings = 1;
+ dprint_symbols(binary);
}
}
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);
}