From e277712037058ef04bdc671dd070a9e0e5d3b43f Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=B8ren=20Sandmann=20Pedersen?= Date: Tue, 8 Sep 2009 02:26:04 -0400 Subject: [PATCH] Initial support for fork/exit events --- TODO | 9 ++++- collector.c | 47 ++++++++++++++++++++++++-- tracker.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- tracker.h | 5 +++ 4 files changed, 161 insertions(+), 7 deletions(-) diff --git a/TODO b/TODO index 92cb8a0..f83a6b9 100644 --- a/TODO +++ b/TODO @@ -23,7 +23,14 @@ Before 1.0.4: Before 1.2: -* Flash when double clicking in descendants view +* Counters must not be destroyed during tracker setup. They have to 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). + +* Fix names. "new process" is really "exec" + +* Fix flash when double clicking in descendants view * Find out what's up with weird two-step flash when you hit start when a profile is loaded. diff --git a/collector.c b/collector.c index df0172a..56b181d 100644 --- a/collector.c +++ b/collector.c @@ -44,6 +44,8 @@ typedef struct counter_t counter_t; typedef struct sample_event_t sample_event_t; typedef struct mmap_event_t mmap_event_t; typedef struct comm_event_t comm_event_t; +typedef struct exit_event_t exit_event_t; +typedef struct fork_event_t fork_event_t; typedef union counter_event_t counter_event_t; static void process_event (Collector *collector, counter_event_t *event); @@ -89,12 +91,30 @@ struct mmap_event_t char filename[1]; }; +struct fork_event_t +{ + struct perf_event_header header; + + uint32_t pid, ppid; + uint32_t tid, ptid; +}; + +struct exit_event_t +{ + struct perf_event_header header; + + uint32_t pid, ppid; + uint32_t tid, ptid; +}; + union counter_event_t { struct perf_event_header header; mmap_event_t mmap; comm_event_t comm; sample_event_t sample; + fork_event_t fork; + exit_event_t exit; }; struct Collector @@ -312,8 +332,13 @@ counter_new (Collector *collector, attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_CALLCHAIN; attr.wakeup_events = 100000; attr.disabled = TRUE; - attr.mmap = TRUE; - attr.comm = TRUE; + + if (cpu == 0) + { + attr.mmap = 1; + attr.comm = 1; + attr.task = 1; + } fd = sysprof_perf_counter_open (&attr, -1, cpu, -1, 0); @@ -429,12 +454,28 @@ process_mmap (Collector *collector, mmap_event_t *mmap) static void process_comm (Collector *collector, comm_event_t *comm) { + g_print ("comm: pid: %d\n", comm->pid); + tracker_add_process (collector->tracker, comm->pid, comm->comm); } static void +process_fork (Collector *collector, fork_event_t *fork) +{ + g_print ("fork: ppid: %d pid: %d\n", fork->ppid, fork->pid); + + tracker_add_fork (collector->tracker, fork->ppid, fork->pid); +} + +static void +process_exit (Collector *collector, exit_event_t *exit) +{ + tracker_add_exit (collector->tracker, exit->pid); +} + +static void process_sample (Collector *collector, sample_event_t *sample) { @@ -473,6 +514,7 @@ process_event (Collector *collector, break; case PERF_EVENT_EXIT: + process_exit (collector, &event->exit); break; case PERF_EVENT_THROTTLE: @@ -482,6 +524,7 @@ process_event (Collector *collector, break; case PERF_EVENT_FORK: + process_fork (collector, &event->fork); break; case PERF_EVENT_READ: diff --git a/tracker.c b/tracker.c index f89abcf..2b93318 100644 --- a/tracker.c +++ b/tracker.c @@ -13,6 +13,8 @@ typedef struct new_process_t new_process_t; typedef struct new_map_t new_map_t; typedef struct sample_t sample_t; +typedef struct fork_t fork_t; +typedef struct exit_t exit_t; struct tracker_t { @@ -27,7 +29,9 @@ typedef enum { NEW_PROCESS, NEW_MAP, - SAMPLE + SAMPLE, + FORK, + EXIT } event_type_t; struct new_process_t @@ -37,6 +41,19 @@ struct new_process_t char command_line[256]; }; +struct fork_t +{ + event_type_t type; + int32_t pid; + int32_t child_pid; +}; + +struct exit_t +{ + event_type_t type; + int32_t pid; +}; + struct new_map_t { event_type_t type; @@ -279,9 +296,33 @@ tracker_add_process (tracker_t * tracker, tracker_append (tracker, &event, sizeof (event)); -#if 0 g_print ("Added new process: %d (%s)\n", pid, command_line); -#endif +} + +void +tracker_add_fork (tracker_t *tracker, + pid_t pid, + pid_t child_pid) +{ + fork_t event; + + event.type = FORK; + event.pid = pid; + event.child_pid = child_pid; + + tracker_append (tracker, &event, sizeof (event)); +} + +void +tracker_add_exit (tracker_t *tracker, + pid_t pid) +{ + exit_t event; + + event.type = EXIT; + event.pid = pid; + + tracker_append (tracker, &event, sizeof (event)); } void @@ -426,6 +467,54 @@ create_process (state_t *state, new_process_t *new_process) state->processes_by_pid, GINT_TO_POINTER (process->pid), process); } +static map_t * +copy_map (map_t *map) +{ + map_t *copy = g_new0 (map_t, 1); + + *copy = *map; + copy->filename = g_strdup (map->filename); + + return copy; +} + +static void +process_fork (state_t *state, fork_t *fork) +{ + process_t *parent = g_hash_table_lookup ( + state->processes_by_pid, GINT_TO_POINTER (fork->pid)); + + if (parent) + { + process_t *process = g_new0 (process_t, 1); + int i; + + g_print ("new child %d\n", fork->child_pid); + + process->pid = fork->child_pid; + process->comm = g_strdup (parent->comm); + process->maps = g_ptr_array_new (); + + 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); + } + else + g_print ("no parent for %d\n", fork->child_pid); +} + +static void +process_exit (state_t *state, exit_t *exit) +{ + /* ignore for now */ +} + static void free_process (gpointer data) { @@ -811,7 +900,7 @@ process_sample (state_t *state, StackStash *resolved, sample_t *sample) static gboolean warned; if (!warned || sample->pid != 0) { - g_warning ("sample for unknown process %d", sample->pid); + g_print ("sample for unknown process %d\n", sample->pid); warned = TRUE; } return; @@ -890,6 +979,16 @@ tracker_create_profile (tracker_t *tracker) create_map (state, (new_map_t *)event); event += sizeof (new_map_t); break; + + case FORK: + process_fork (state, (fork_t *)event); + event += sizeof (fork_t); + break; + + case EXIT: + process_exit (state, (exit_t *)exit); + event += sizeof (exit_t); + break; case SAMPLE: process_sample (state, resolved_stash, (sample_t *)event); diff --git a/tracker.h b/tracker.h index 71b33d8..098f4a1 100644 --- a/tracker.h +++ b/tracker.h @@ -9,6 +9,11 @@ void tracker_free (tracker_t *); void tracker_add_process (tracker_t *tracker, pid_t pid, const char *command_line); +void tracker_add_fork (tracker_t *tracker, + pid_t pid, + pid_t child_pid); +void tracker_add_exit (tracker_t *tracker, + pid_t pid); void tracker_add_map (tracker_t * tracker, pid_t pid, uint64_t start, -- 2.7.4