Initial support for fork/exit events
authorSøren Sandmann Pedersen <ssp@redhat.com>
Tue, 8 Sep 2009 06:26:04 +0000 (02:26 -0400)
committerSøren Sandmann Pedersen <ssp@redhat.com>
Tue, 8 Sep 2009 07:03:24 +0000 (03:03 -0400)
TODO
collector.c
tracker.c
tracker.h

diff --git a/TODO b/TODO
index 92cb8a0..f83a6b9 100644 (file)
--- 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.
index df0172a..56b181d 100644 (file)
@@ -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:
index f89abcf..2b93318 100644 (file)
--- 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);
index 71b33d8..098f4a1 100644 (file)
--- 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,