TODO, plus a number of other fixes

This commit is contained in:
Søren Sandmann Pedersen
2009-09-08 19:35:03 -04:00
parent 75c5a39c72
commit 09ffea0d57
3 changed files with 132 additions and 43 deletions

32
TODO
View File

@ -23,14 +23,30 @@ Before 1.0.4:
Before 1.2: Before 1.2:
* How to deal with forks and mmaps seemingly happening after
samples. This can happen when a process migrates between CPUs.
There doesn't seem to be any way to get this information in a
guaranteed correct way.
* How to deal with processes that exit before we can get their maps?
Such a process can never cause events itself, but it may fork a
child that does. There is no way to get the maps for that child. A
possible solution would be to optionally generate mmap event after
forks. Userspace would turn this off when it was done with the
initial gathering of processes.
* Find out why the busy cursor stays active after you hit start
* Kernel binary when available, is better than kallsyms. * Kernel binary when available, is better than kallsyms.
* Hack around gtk+ bug where it mispositions the window. * Hack around gtk+ bug where it mispositions the window.
* Counters must not be destroyed during tracker setup. They have to exist * Counters must not be destroyed during tracker setup. They have to
but be disabled so that we can track creation of processes. exist but be disabled so that we can track creation of processes.
* Check that we don't use too much memory (in particular with the timeline). * Check that we don't use too much memory (in particular with the
timeline).
* Fix names. "new process" is really "exec" * Fix names. "new process" is really "exec"
@ -49,8 +65,8 @@ Before 1.2:
* Get rid of process.c * Get rid of process.c
* On 32 bit, NMI stackframes are not filtered out which leads to * On 32 bit, NMI stackframes are not filtered out which leads to wrong
wrong kernel traces kernel traces
* Can we track kernel modules being inserted/removed? * Can we track kernel modules being inserted/removed?
@ -66,7 +82,7 @@ Before 1.2:
* Sometimes it get samples for unknown processes. This may be due to * Sometimes it get samples for unknown processes. This may be due to
forking without execing. forking without execing.
* Give an informative error message if run as root * Give an informative error message if not run as root
* What are the events generated for pid 0 and pid 1? They have no * What are the events generated for pid 0 and pid 1? They have no
stacktrace, and an eip in the kernel. stacktrace, and an eip in the kernel.
@ -75,13 +91,13 @@ Before 1.2:
32 bits vs 64 bits. Or use C++ like behdad does in harfbuzz? 32 bits vs 64 bits. Or use C++ like behdad does in harfbuzz?
* We often get "No map". I suspect this is because the vdso stackframe * We often get "No map". I suspect this is because the vdso stackframe
is broken. is strange.
* Find out why gtk_tree_view_columns_autosize() apparently doesn't * Find out why gtk_tree_view_columns_autosize() apparently doesn't
work on empty tree views. work on empty tree views.
* Write my own tree model? There is still performance issues in * Write my own tree model? There is still performance issues in
footreestore. FooTreeStore.
* Hack to disable recursion for binaries without symbols causes the * Hack to disable recursion for binaries without symbols causes the
symbols to not work the way other symbols do. A better approach is symbols to not work the way other symbols do. A better approach is

View File

@ -48,7 +48,9 @@ typedef struct exit_event_t exit_event_t;
typedef struct fork_event_t fork_event_t; typedef struct fork_event_t fork_event_t;
typedef union counter_event_t counter_event_t; typedef union counter_event_t counter_event_t;
static void process_event (Collector *collector, counter_event_t *event); static void process_event (Collector *collector,
counter_t *counter,
counter_event_t *event);
struct counter_t struct counter_t
{ {
@ -254,7 +256,7 @@ on_read (gpointer data)
if (header->type == PERF_EVENT_SAMPLE) if (header->type == PERF_EVENT_SAMPLE)
collector->n_samples++; collector->n_samples++;
process_event (collector, (counter_event_t *)header); process_event (collector, counter, (counter_event_t *)header);
} }
tail += header->size; tail += header->size;
@ -332,12 +334,9 @@ counter_new (Collector *collector,
attr.wakeup_events = 100000; attr.wakeup_events = 100000;
attr.disabled = TRUE; attr.disabled = TRUE;
if (cpu == 0) attr.mmap = 1;
{ attr.comm = 1;
attr.mmap = 1; attr.task = 1;
attr.comm = 1;
attr.task = 1;
}
fd = sysprof_perf_counter_open (&attr, -1, cpu, -1, 0); fd = sysprof_perf_counter_open (&attr, -1, cpu, -1, 0);
@ -375,6 +374,12 @@ counter_enable (counter_t *counter)
ioctl (counter->fd, PERF_COUNTER_IOC_ENABLE); ioctl (counter->fd, PERF_COUNTER_IOC_ENABLE);
} }
static void
counter_disable (counter_t *counter)
{
ioctl (counter->fd, PERF_COUNTER_IOC_DISABLE);
}
static void static void
counter_free (counter_t *counter) counter_free (counter_t *counter)
{ {
@ -390,29 +395,64 @@ counter_free (counter_t *counter)
/* /*
* Collector * Collector
*/ */
static void
enable_counters (Collector *collector)
{
GList *list;
for (list = collector->counters; list != NULL; list = list->next)
{
counter_t *counter = list->data;
counter_enable (counter);
}
}
static void
disable_counters (Collector *collector)
{
GList *list;
for (list = collector->counters; list != NULL; list = list->next)
{
counter_t *counter = list->data;
counter_disable (counter);
}
}
void void
collector_reset (Collector *collector) collector_reset (Collector *collector)
{ {
gboolean restart = FALSE; /* Disable the counters so that we won't track
* the activity of tracker_free()/tracker_new()
*
* They will still record fork/mmap/etc. so
* we can keep an accurate log of process creation
*/
if (collector->counters) if (collector->counters)
{ {
collector_stop (collector); g_print ("disable counters\n");
restart = TRUE;
disable_counters (collector);
} }
if (collector->tracker) if (collector->tracker)
{ {
tracker_free (collector->tracker); tracker_free (collector->tracker);
collector->tracker = NULL; collector->tracker = tracker_new ();
} }
collector->n_samples = 0; collector->n_samples = 0;
g_get_current_time (&collector->latest_reset); g_get_current_time (&collector->latest_reset);
if (restart) if (collector->counters)
collector_start (collector, NULL); {
g_print ("enable counters\n");
enable_counters (collector);
}
} }
/* callback is called whenever a new sample arrives */ /* callback is called whenever a new sample arrives */
@ -446,7 +486,7 @@ process_mmap (Collector *collector, mmap_event_t *mmap)
static void static void
process_comm (Collector *collector, comm_event_t *comm) process_comm (Collector *collector, comm_event_t *comm)
{ {
g_print ("comm: pid: %d\n", comm->pid); g_print ("pid, tid: %d %d", comm->pid, comm->tid);
tracker_add_process (collector->tracker, tracker_add_process (collector->tracker,
comm->pid, comm->pid,
@ -456,7 +496,8 @@ process_comm (Collector *collector, comm_event_t *comm)
static void static void
process_fork (Collector *collector, fork_event_t *fork) process_fork (Collector *collector, fork_event_t *fork)
{ {
g_print ("fork: ppid: %d pid: %d\n", fork->ppid, fork->pid); g_print ("ppid: %d pid: %d ptid: %d tid %d",
fork->ppid, fork->pid, fork->ptid, fork->tid);
tracker_add_fork (collector->tracker, fork->ppid, fork->pid); tracker_add_fork (collector->tracker, fork->ppid, fork->pid);
} }
@ -464,6 +505,8 @@ process_fork (Collector *collector, fork_event_t *fork)
static void static void
process_exit (Collector *collector, exit_event_t *exit) process_exit (Collector *collector, exit_event_t *exit)
{ {
g_print ("for %d %d", exit->pid, exit->tid);
tracker_add_exit (collector->tracker, exit->pid); tracker_add_exit (collector->tracker, exit->pid);
} }
@ -474,6 +517,8 @@ process_sample (Collector *collector,
uint64_t *ips; uint64_t *ips;
int n_ips; int n_ips;
g_print ("pid, tid: %d %d", sample->pid, sample->tid);
if (sample->n_ips == 0) if (sample->n_ips == 0)
{ {
uint64_t trace[3]; uint64_t trace[3];
@ -508,8 +553,27 @@ process_sample (Collector *collector,
static void static void
process_event (Collector *collector, process_event (Collector *collector,
counter_t *counter,
counter_event_t *event) counter_event_t *event)
{ {
char *name;
switch (event->header.type)
{
case PERF_EVENT_MMAP: name = "mmap"; break;
case PERF_EVENT_LOST: name = "lost"; break;
case PERF_EVENT_COMM: name = "comm"; break;
case PERF_EVENT_EXIT: name = "exit"; break;
case PERF_EVENT_THROTTLE: name = "throttle"; break;
case PERF_EVENT_UNTHROTTLE: name = "unthrottle"; break;
case PERF_EVENT_FORK: name = "fork"; break;
case PERF_EVENT_READ: name = "read"; break;
case PERF_EVENT_SAMPLE: name = "samp"; break;
default: name = "unknown"; break;
}
g_print ("cpu %d :: %s :: ", counter->cpu, name);
switch (event->header.type) switch (event->header.type)
{ {
case PERF_EVENT_MMAP: case PERF_EVENT_MMAP:
@ -545,10 +609,11 @@ process_event (Collector *collector,
break; break;
default: default:
g_warning ("Got unknown event: %d (%d)\n", g_warning ("unknown event: %d (%d)\n", event->header.type, event->header.size);
event->header.type, event->header.size);
break; break;
} }
g_print ("\n");
} }
gboolean gboolean
@ -556,7 +621,6 @@ collector_start (Collector *collector,
GError **err) GError **err)
{ {
int n_cpus = get_n_cpus (); int n_cpus = get_n_cpus ();
GList *list;
int i; int i;
if (!collector->tracker) if (!collector->tracker)
@ -568,14 +632,8 @@ collector_start (Collector *collector,
collector->counters = g_list_append (collector->counters, counter); collector->counters = g_list_append (collector->counters, counter);
} }
/* Hack to make sure we parse the kernel symbols before
* starting collection, so the parsing doesn't interfere
* with the profiling.
*/
for (list = collector->counters; list != NULL; list = list->next) enable_counters (collector);
counter_enable (list->data);
return TRUE; return TRUE;
} }

View File

@ -104,6 +104,7 @@ fake_new_process (tracker_t *tracker, pid_t pid)
if (lines[0] && strlen (lines[0]) > 0) if (lines[0] && strlen (lines[0]) > 0)
{ {
tracker_add_process (tracker, pid, lines[0]); tracker_add_process (tracker, pid, lines[0]);
done = TRUE; done = TRUE;
} }
@ -131,6 +132,9 @@ fake_new_process (tracker_t *tracker, pid_t pid)
g_strfreev (lines); g_strfreev (lines);
} }
if (!done)
g_print ("failed to fake %d\n", pid);
} }
static void static void
@ -460,6 +464,8 @@ create_process (state_t *state, new_process_t *new_process)
process->pid = new_process->pid; process->pid = new_process->pid;
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 ();
g_print ("new comm process %d\n", new_process->pid);
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);
@ -482,7 +488,9 @@ process_fork (state_t *state, fork_t *fork)
process_t *parent = g_hash_table_lookup ( process_t *parent = g_hash_table_lookup (
state->processes_by_pid, GINT_TO_POINTER (fork->pid)); state->processes_by_pid, GINT_TO_POINTER (fork->pid));
#if 0
if (parent) if (parent)
#endif
{ {
process_t *process = g_new0 (process_t, 1); process_t *process = g_new0 (process_t, 1);
int i; int i;
@ -490,26 +498,33 @@ process_fork (state_t *state, fork_t *fork)
g_print ("new child %d\n", fork->child_pid); g_print ("new child %d\n", fork->child_pid);
process->pid = fork->child_pid; process->pid = fork->child_pid;
process->comm = g_strdup (parent->comm); process->comm = g_strdup (parent? parent->comm : "<unknown>");
process->maps = g_ptr_array_new (); process->maps = g_ptr_array_new ();
for (i = 0; i < parent->maps->len; ++i) if (parent)
{ {
map_t *map = copy_map (parent->maps->pdata[i]); for (i = 0; i < parent->maps->len; ++i)
{
g_ptr_array_add (process->maps, map); map_t *map = copy_map (parent->maps->pdata[i]);
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);
} }
#if 0
else else
g_print ("no parent for %d\n", fork->child_pid); g_print ("no parent for %d\n", fork->child_pid);
#endif
} }
static void static void
process_exit (state_t *state, exit_t *exit) process_exit (state_t *state, exit_t *exit)
{ {
g_print ("Exit for %d\n", exit->pid);
/* ignore for now */ /* ignore for now */
} }
@ -989,7 +1004,7 @@ tracker_create_profile (tracker_t *tracker)
break; break;
case EXIT: case EXIT:
process_exit (state, (exit_t *)exit); process_exit (state, (exit_t *)event);
event += sizeof (exit_t); event += sizeof (exit_t);
break; break;