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