diff options
author | Søren Sandmann Pedersen <ssp@l3000.localdomain> | 2009-10-29 07:40:51 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@l3000.localdomain> | 2009-10-29 07:40:51 -0400 |
commit | 1b64f1d92446e148586972b7e885b7b81a33ba7e (patch) | |
tree | d2ab335b9f01d1b97da22d80ffef8debedc8a26a | |
parent | ae77f078d3a1ef81639a73db75b9264f1634889b (diff) |
Also filter out NMI stack
-rw-r--r-- | tracker.c | 253 |
1 files changed, 134 insertions, 119 deletions
@@ -19,7 +19,7 @@ typedef struct exit_t exit_t; struct tracker_t { StackStash *stash; - + size_t n_event_bytes; size_t n_allocated_bytes; uint8_t * events; @@ -87,16 +87,16 @@ get_lines (const char *format, pid_t pid) char *filename = g_strdup_printf (format, pid); char **result = NULL; char *contents; - + if (g_file_get_contents (filename, &contents, NULL, NULL)) { result = g_strsplit (contents, "\n", -1); - + g_free (contents); } - + g_free (filename); - + return result; } @@ -105,7 +105,7 @@ fake_new_process (tracker_t *tracker, pid_t pid) { char **lines; gboolean done = FALSE; - + if ((lines = get_lines ("/proc/%d/cmdline", pid))) { if (lines[0] && strlen (lines[0]) > 0) @@ -121,7 +121,7 @@ fake_new_process (tracker_t *tracker, pid_t pid) if (!done && (lines = get_lines ("/proc/%d/status", pid))) { int i; - + for (i = 0; lines[i] != NULL; ++i) { if (strncmp ("Name:", lines[i], 5) == 0) @@ -148,11 +148,11 @@ static void fake_new_map (tracker_t *tracker, pid_t pid) { char **lines; - + if ((lines = get_lines ("/proc/%d/maps", pid))) { int i; - + for (i = 0; lines[i] != NULL; ++i) { char file[256]; @@ -161,13 +161,13 @@ fake_new_map (tracker_t *tracker, pid_t pid) gulong offset; gulong inode; int count; - + file[255] = '\0'; - + count = sscanf ( lines[i], "%lx-%lx %*15s %lx %*x:%*x %lu %255s", &start, &end, &offset, &inode, file); - + if (count == 5) { if (strcmp (file, "[vdso]") == 0) @@ -181,11 +181,11 @@ fake_new_map (tracker_t *tracker, pid_t pid) offset = 0; inode = 0; } - + tracker_add_map (tracker, pid, start, end, offset, inode, file); } } - + g_strfreev (lines); } } @@ -195,24 +195,24 @@ populate_from_proc (tracker_t *tracker) { GDir *proc = g_dir_open ("/proc", 0, NULL); const char *name; - + if (!proc) return; - + while ((name = g_dir_read_name (proc))) { pid_t pid; char *end; - + pid = strtol (name, &end, 10); - + if (*end == 0) { fake_new_process (tracker, pid); fake_new_map (tracker, pid); } } - + g_dir_close (proc); } @@ -229,7 +229,7 @@ time_diff (const GTimeVal *first, { double first_ms = timeval_to_ms (first); double second_ms = timeval_to_ms (second); - + return first_ms - second_ms; } @@ -238,21 +238,21 @@ tracker_new (void) { tracker_t *tracker = g_new0 (tracker_t, 1); GTimeVal before, after; - + tracker->n_event_bytes = 0; tracker->n_allocated_bytes = DEFAULT_SIZE; tracker->events = g_malloc (DEFAULT_SIZE); - + tracker->stash = stack_stash_new (NULL); - + g_get_current_time (&before); - + populate_from_proc (tracker); - + g_get_current_time (&after); - + g_print ("Time to populate %f\n", time_diff (&after, &before)); - + return tracker; } @@ -281,14 +281,14 @@ tracker_append (tracker_t *tracker, if (tracker->n_allocated_bytes - tracker->n_event_bytes < n_bytes) { size_t new_size = tracker->n_allocated_bytes * 2; - + tracker->events = g_realloc (tracker->events, new_size); - + tracker->n_allocated_bytes = new_size; } - + g_assert (tracker->n_allocated_bytes - tracker->n_event_bytes >= n_bytes); - + memcpy (tracker->events + tracker->n_event_bytes, event, n_bytes); tracker->n_event_bytes += n_bytes; @@ -303,7 +303,7 @@ tracker_add_process (tracker_t * tracker, event.header = MAKE_HEADER (NEW_PROCESS, pid); COPY_STRING (event.command_line, command_line); - + tracker_append (tracker, &event, sizeof (event)); } @@ -341,14 +341,14 @@ tracker_add_map (tracker_t * tracker, const char *filename) { new_map_t event; - + event.header = MAKE_HEADER (NEW_MAP, pid); COPY_STRING (event.filename, filename); event.start = start; event.end = end; event.offset = offset; event.inode = inode; - + tracker_append (tracker, &event, sizeof (event)); } @@ -359,10 +359,10 @@ tracker_add_sample (tracker_t *tracker, int n_ips) { sample_t event; - + event.header = MAKE_HEADER (SAMPLE, pid); event.trace = stack_stash_add_trace (tracker->stash, ips, n_ips, 1); - + tracker_append (tracker, &event, sizeof (event)); } @@ -374,9 +374,9 @@ typedef struct map_t map_t; struct process_t { pid_t pid; - + char * comm; - + GPtrArray * maps; }; @@ -411,33 +411,33 @@ create_map (state_t *state, new_map_t *new_map) map_t *map; int i; pid_t pid = GET_PID (new_map->header); - + process = g_hash_table_lookup ( state->processes_by_pid, GINT_TO_POINTER (pid)); - + if (!process) return; - + map = g_new0 (map_t, 1); map->filename = g_strdup (new_map->filename); map->start = new_map->start; map->end = new_map->end; map->offset = new_map->offset; map->inode = new_map->inode; - + /* Remove existing maps that overlap the new one */ for (i = 0; i < process->maps->len; ++i) { map_t *m = process->maps->pdata[i]; - + if (m->start < map->end && m->end > map->start) { destroy_map (m); - + g_ptr_array_remove_index (process->maps, i); } } - + g_ptr_array_add (process->maps, map); } @@ -445,16 +445,16 @@ static void destroy_process (process_t *process) { int i; - + g_free (process->comm); - + for (i = 0; i < process->maps->len; ++i) { map_t *map = process->maps->pdata[i]; - + destroy_map (map); } - + g_ptr_array_free (process->maps, TRUE); g_free (process); } @@ -463,7 +463,7 @@ static void create_process (state_t *state, new_process_t *new_process) { process_t *process = g_new0 (process_t, 1); - + process->pid = GET_PID (new_process->header); process->comm = g_strdup (new_process->command_line); process->maps = g_ptr_array_new (); @@ -471,7 +471,7 @@ create_process (state_t *state, new_process_t *new_process) #if 0 g_print ("new comm process %d\n", new_process->pid); #endif - + g_hash_table_insert ( state->processes_by_pid, GINT_TO_POINTER (process->pid), process); } @@ -503,21 +503,21 @@ process_fork (state_t *state, fork_t *fork) #if 0 g_print ("new child %d\n", fork->child_pid); #endif - + process->pid = fork->child_pid; process->comm = g_strdup (parent? parent->comm : "<unknown>"); process->maps = g_ptr_array_new (); - + if (parent) { for (i = 0; i < parent->maps->len; ++i) { map_t *map = copy_map (parent->maps->pdata[i]); - + g_ptr_array_add (process->maps, map); } } - + g_hash_table_insert ( state->processes_by_pid, GINT_TO_POINTER (process->pid), process); } @@ -533,7 +533,7 @@ process_exit (state_t *state, exit_t *exit) #if 0 g_print ("Exit for %d\n", exit->pid); #endif - + /* ignore for now */ } @@ -541,7 +541,7 @@ static void free_process (gpointer data) { process_t *process = data; - + destroy_process (process); } @@ -549,19 +549,19 @@ static state_t * state_new (void) { state_t *state = g_new0 (state_t, 1); - + state->processes_by_pid = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, free_process); - + state->unique_symbols = g_hash_table_new (g_direct_hash, g_direct_equal); state->unique_comms = g_hash_table_new (g_str_hash, g_str_equal); state->bin_files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)bin_file_free); - + return state; -} +} static void state_free (state_t *state) @@ -570,7 +570,7 @@ state_free (state_t *state) g_hash_table_destroy (state->unique_symbols); g_hash_table_destroy (state->unique_comms); g_hash_table_destroy (state->bin_files); - + g_free (state); } @@ -584,27 +584,27 @@ static void parse_kallsym_line (const char *line, GArray *table) { char **tokens = g_strsplit_set (line, " \t", -1); - + if (tokens[0] && tokens[1] && tokens[2]) { glong address; char *endptr; - + address = strtoul (tokens[0], &endptr, 16); - + if (*endptr == '\0' && (strcmp (tokens[1], "T") == 0 || strcmp (tokens[1], "t") == 0)) { kernel_symbol_t sym; - + sym.address = address; sym.name = g_strdup (tokens[2]); - + g_array_append_val (table, sym); } } - + g_strfreev (tokens); } @@ -614,24 +614,24 @@ parse_kallsyms (const char *kallsyms, { const char *sol; const char *eol; - + sol = kallsyms; eol = strchr (sol, '\n'); while (eol) { char *line = g_strndup (sol, eol - sol); - + parse_kallsym_line (line, table); - + g_free (line); - + sol = eol + 1; eol = strchr (sol, '\n'); } - + if (table->len <= 1) return FALSE; - + return TRUE; } @@ -640,7 +640,7 @@ compare_syms (gconstpointer a, gconstpointer b) { const kernel_symbol_t *sym_a = a; const kernel_symbol_t *sym_b = b; - + if (sym_a->address > sym_b->address) return 1; else if (sym_a->address == sym_b->address) @@ -665,16 +665,16 @@ do_lookup (kernel_symbol_t *symbols, { if (address >= symbols[last].address) return &(symbols[last]); - + last--; } - + return NULL; } else { int mid = (first + last) / 2; - + if (symbols[mid].address > address) return do_lookup (symbols, address, first, mid); else @@ -687,11 +687,11 @@ get_kernel_symbols (void) { static GArray *kernel_syms; static gboolean initialized = FALSE; - + #if 0 find_kernel_binary(); #endif - + if (!initialized) { char *kallsyms; @@ -700,7 +700,7 @@ get_kernel_symbols (void) if (kallsyms) { kernel_syms = g_array_new (TRUE, TRUE, sizeof (kernel_symbol_t)); - + if (parse_kallsyms (kallsyms, kernel_syms)) { g_array_sort (kernel_syms, compare_syms); @@ -711,24 +711,25 @@ get_kernel_symbols (void) kernel_syms = NULL; } } - + g_free (kallsyms); } - + if (!kernel_syms) { g_print ("Warning: /proc/kallsyms could not be " "read. Kernel symbols will not be available\n"); } - + initialized = TRUE; } - + return kernel_syms; } static const char skip_kernel_symbols[][32] = { + /* IRQ stack */ "common_interrupt", "apic_timer_interrupt", "smp_apic_timer_interrupt", @@ -739,6 +740,20 @@ static const char skip_kernel_symbols[][32] = "__perf_event_overflow", "perf_prepare_sample", "perf_callchain", + + /* NMI stack */ + "nmi_stack_correct", + "do_nmi", + "notify_die", + "atomic_notifier_call_chain", + "notifier_call_chain", + "perf_event_nmi_handler", + "intel_pmu_handle_irq", + "perf_event_overflow", + "__perf_event_overflow", + "perf_prepare_sample", + "perf_callchain", + "" }; @@ -750,12 +765,12 @@ lookup_kernel_symbol (gulong address) const char *sym; const char *s; int i; - + if (ksyms->len == 0) return NULL; - + result = do_lookup ((kernel_symbol_t *)ksyms->data, address, 0, ksyms->len - 1); - + sym = result? result->name : NULL; @@ -791,14 +806,14 @@ static char * unique_dup (GHashTable *unique_symbols, const char *sym) { char *result; - + result = g_hash_table_lookup (unique_symbols, sym); if (!result) { result = elf_demangle (sym); g_hash_table_insert (unique_symbols, (char *)sym, result); } - + return result; } @@ -806,15 +821,15 @@ static map_t * process_locate_map (process_t *process, gulong addr) { int i; - + for (i = 0; i < process->maps->len; ++i) { map_t *map = process->maps->pdata[i]; - + if (addr >= map->start && addr < map->end) return map; } - + return NULL; } @@ -837,7 +852,7 @@ make_message (state_t *state, const char *format, ...) else { result = message; - + g_hash_table_insert (state->unique_comms, result, result); } @@ -866,9 +881,9 @@ lookup_symbol (state_t *state, gboolean kernel) { const char *sym; - + g_assert (process); - + if (kernel) { sym = lookup_kernel_symbol (address); @@ -876,7 +891,7 @@ lookup_symbol (state_t *state, else { map_t *map = process_locate_map (process, address); - + if (!map) { sym = make_message (state, "No map [%s]", process->comm); @@ -885,7 +900,7 @@ lookup_symbol (state_t *state, { bin_file_t *bin_file = state_get_bin_file (state, map->filename); const bin_symbol_t *bin_sym; - + address -= map->start; address += map->offset; @@ -899,12 +914,12 @@ lookup_symbol (state_t *state, else { bin_sym = bin_file_lookup_symbol (bin_file, address); - + sym = bin_symbol_get_name (bin_file, bin_sym); } } } - + if (sym) return unique_dup (state->unique_symbols, sym); else @@ -916,7 +931,7 @@ struct context_info_t { enum perf_callchain_context context; char name[32]; -}; +}; static const context_info_t context_info[] = { @@ -934,15 +949,15 @@ static const context_info_t * get_context_info (enum perf_callchain_context context) { int i; - + for (i = 0; i < sizeof (context_info) / sizeof (context_info[0]); ++i) { const context_info_t *info = &context_info[i]; - + if (info->context == context) return info; } - + return NULL; } @@ -960,7 +975,7 @@ process_sample (state_t *state, StackStash *resolved, sample_t *sample) process = g_hash_table_lookup ( state->processes_by_pid, GINT_TO_POINTER (pid)); - + if (!process) { static gboolean warned; @@ -973,7 +988,7 @@ process_sample (state_t *state, StackStash *resolved, sample_t *sample) } return; } - + len = 5; for (n = sample->trace; n != NULL; n = n->parent) len++; @@ -982,14 +997,14 @@ process_sample (state_t *state, StackStash *resolved, sample_t *sample) resolved_traces = g_new (uint64_t, len); else resolved_traces = stack_addrs; - + len = 0; for (n = sample->trace; n != NULL; n = n->parent) { uint64_t address = n->data; const context_info_t *new_context; const char *symbol; - + new_context = get_context_info (address); if (new_context) { @@ -997,16 +1012,16 @@ process_sample (state_t *state, StackStash *resolved, sample_t *sample) symbol = unique_dup (state->unique_symbols, context->name); else symbol = NULL; - + context = new_context; } else { gboolean kernel = context && context->context == PERF_CONTEXT_KERNEL; - + symbol = lookup_symbol (state, process, address, kernel); } - + if (symbol) resolved_traces[len++] = POINTER_TO_U64 (symbol); } @@ -1021,9 +1036,9 @@ process_sample (state_t *state, StackStash *resolved, sample_t *sample) resolved_traces[len++] = POINTER_TO_U64 (unique_dup (state->unique_symbols, context->name)); } - + cmdline = make_message (state, "[%s]", process->comm); - + resolved_traces[len++] = POINTER_TO_U64 (cmdline); resolved_traces[len++] = POINTER_TO_U64 ( unique_dup (state->unique_symbols, everything)); @@ -1042,22 +1057,22 @@ tracker_create_profile (tracker_t *tracker) Profile *profile; state_t *state; uint8_t *event; - + state = state_new (); resolved_stash = stack_stash_new (g_free); - + event = tracker->events; while (event < end) { event_type_t type = GET_TYPE (*(uint32_t *)event); - + switch (type) { case NEW_PROCESS: create_process (state, (new_process_t *)event); event += sizeof (new_process_t); break; - + case NEW_MAP: create_map (state, (new_map_t *)event); event += sizeof (new_map_t); @@ -1072,7 +1087,7 @@ tracker_create_profile (tracker_t *tracker) process_exit (state, (exit_t *)event); event += sizeof (exit_t); break; - + case SAMPLE: process_sample (state, resolved_stash, (sample_t *)event); event += sizeof (sample_t); @@ -1084,6 +1099,6 @@ tracker_create_profile (tracker_t *tracker) state_free (state); stack_stash_unref (resolved_stash); - + return profile; } |