Fake new_process and new_map events when a tracker is created
authorSøren Sandmann Pedersen <ssp@redhat.com>
Mon, 7 Sep 2009 22:18:26 +0000 (18:18 -0400)
committerSøren Sandmann Pedersen <ssp@redhat.com>
Tue, 8 Sep 2009 07:03:03 +0000 (03:03 -0400)
collector.c
sysprof.c
tracker.c

index 7315da9..31bfdd8 100644 (file)
@@ -34,6 +34,7 @@
 #include "watch.h"
 #include "process.h"
 #include "elfparser.h"
+#include "tracker.h"
 
 #include "perf_counter.h"
 #include "barrier.h"
@@ -45,7 +46,6 @@ 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 union counter_event_t counter_event_t;
-typedef void (* event_callback_t) (counter_event_t *event, gpointer data);
 
 static void process_event (Collector *collector, counter_event_t *event);
 
@@ -103,6 +103,7 @@ struct Collector
     gpointer           data;
     
     StackStash *       stash;
+    tracker_t *                tracker;
     GTimeVal           latest_reset;
 
     int                        n_samples;
@@ -240,6 +241,10 @@ map_buffer (counter_t *counter)
     int n_bytes = N_PAGES * process_get_page_size();
     void *address, *a;
 
+    /* We use the old trick of mapping the ring buffer twice
+     * consecutively, so that we don't need special-case code
+     * to deal with wrapping.
+     */
     address = mmap (NULL, n_bytes * 2 + process_get_page_size(), PROT_NONE,
                    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 
@@ -281,7 +286,7 @@ counter_new (Collector *collector,
     attr.type = PERF_TYPE_HARDWARE;
     attr.config = PERF_COUNT_HW_CPU_CYCLES;
     attr.sample_period = 1200000 ;  /* In number of clock cycles -
-                                    * use frequency instead FIXME
+                                    * FIXME: consider using frequency instead
                                     */
     attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_CALLCHAIN;
     attr.wakeup_events = 100000;
@@ -343,15 +348,34 @@ counter_free (counter_t *counter)
 void
 collector_reset (Collector *collector)
 {
+    gboolean restart = FALSE;
+    
+    if (collector->counters)
+    {
+       collector_stop (collector);
+       restart = TRUE;
+    }
+    
     if (collector->stash)
+    {
        stack_stash_unref (collector->stash);
+       collector->stash = NULL;
+    }
     
+    if (collector->tracker)
+    {
+       tracker_free (collector->tracker);
+       collector->tracker = NULL;
+    }
+
     process_flush_caches();
     
-    collector->stash = stack_stash_new (NULL);
     collector->n_samples = 0;
     
     g_get_current_time (&collector->latest_reset);
+
+    if (restart)
+       collector_start (collector, NULL);
 }
 
 /* callback is called whenever a new sample arrives */
@@ -364,6 +388,7 @@ collector_new (CollectorFunc callback,
     collector->callback = callback;
     collector->data = data;
     collector->stash = NULL;
+    collector->tracker = NULL;
     
     collector_reset (collector);
 
@@ -507,6 +532,15 @@ collector_start (Collector  *collector,
     GList *list;
     int i;
 
+    g_print ("starting\n");
+       
+    if (!collector->stash)
+       collector->stash = stack_stash_new (NULL);
+    if (!collector->tracker)
+       collector->tracker = tracker_new ();
+    
+    g_assert (collector->stash);
+    
     for (i = 0; i < n_cpus; ++i)
     {
        counter_t *counter = counter_new (collector, i);
@@ -522,6 +556,8 @@ collector_start (Collector  *collector,
 
     for (list = collector->counters; list != NULL; list = list->next)
        counter_enable (list->data);
+
+    g_print ("started\n");
     
     return TRUE;
 }
index fd689b7..f3b8d77 100644 (file)
--- a/sysprof.c
+++ b/sysprof.c
@@ -374,7 +374,7 @@ on_start_toggled (GtkWidget *widget, gpointer data)
     }
     else
     {
-       sorry (app->main_window, err->message);
+       sorry (app->main_window, err->message); 
 
        g_error_free (err);
     }
index 65978eb..8970718 100644 (file)
--- a/tracker.c
+++ b/tracker.c
@@ -1,5 +1,7 @@
 #include <glib.h>
 #include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 #include "tracker.h"
 #include "stackstash.h"
@@ -22,31 +24,31 @@ typedef enum
     NEW_PROCESS,
     NEW_MAP,
     SAMPLE
-} event_type;
+} event_type_t;
 
 struct new_process_t
 {
-    event_type type;
-    int32_t    pid;
-    char       command_line[256];
+    event_type_t       type;
+    int32_t            pid;
+    char               command_line[256];
 };
 
 struct new_map_t
 {
-    event_type type;
-    int32_t    pid;
-    char       file_name[PATH_MAX];
-    uint64_t   start;
-    uint64_t   end;
-    uint64_t   offset;
-    uint64_t   inode;
+    event_type_t       type;
+    int32_t            pid;
+    char               file_name[PATH_MAX];
+    uint64_t           start;
+    uint64_t           end;
+    uint64_t           offset;
+    uint64_t           inode;
 };
 
 struct sample_t
 {
-    event_type type;
-    int32_t    pid;
-    StackNode *        trace;
+    event_type_t       type;
+    int32_t            pid;
+    StackNode *                trace;
 };
 
 #define DEFAULT_SIZE   (1024 * 1024 * 4)
@@ -70,6 +72,136 @@ tracker_append (tracker_t *tracker,
     memcpy (tracker->events + tracker->n_event_bytes, event, n_bytes);
 }
 
+static char **
+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;
+}
+
+static void
+fake_new_process (tracker_t *tracker, pid_t pid)
+{
+    char **lines;
+
+    if ((lines = get_lines ("/proc/%d/status", pid)))
+    {
+        int i;
+
+        for (i = 0; lines[i] != NULL; ++i)
+        {
+            if (strncmp ("Name:", lines[i], 5) == 0)
+            {
+               tracker_add_process (tracker, pid, g_strstrip (strchr (lines[i], ':')));
+                break;
+            }
+        }
+
+        g_strfreev (lines);
+    }
+}
+
+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];
+            gulong start;
+            gulong end;
+            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)
+                {
+                    /* For the vdso, the kernel reports 'offset' as the
+                     * the same as the mapping addres. This doesn't make
+                     * any sense to me, so we just zero it here. There
+                     * is code in binfile.c (read_inode) that returns 0
+                     * for [vdso].
+                     */
+                    offset = 0;
+                    inode = 0;
+                }
+
+               tracker_add_map (tracker, pid, start, end, offset, inode, file);
+            }
+        }
+
+        g_strfreev (lines);
+    }
+}
+
+static void
+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);
+}
+
+
+static double
+timeval_to_ms (const GTimeVal *timeval)
+{
+    return (timeval->tv_sec * G_USEC_PER_SEC + timeval->tv_usec) / 1000.0;
+}
+
+static double
+time_diff (const GTimeVal *first,
+          const GTimeVal *second)
+{
+    double first_ms = timeval_to_ms (first);
+    double second_ms = timeval_to_ms (second);
+    
+    return first_ms - second_ms;
+}
+
 tracker_t *
 tracker_new (void)
 {
@@ -80,6 +212,16 @@ tracker_new (void)
     tracker->events = g_malloc (DEFAULT_SIZE);
 
     tracker->stash = stack_stash_new (NULL);
+
+    GTimeVal before, after;
+
+    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;
 }
@@ -87,7 +229,9 @@ tracker_new (void)
 void
 tracker_free (tracker_t *tracker)
 {
-    
+    stack_stash_unref (tracker->stash);
+    g_free (tracker->events);
+    g_free (tracker);
 }
 
 #define COPY_STRING(dest, src)                                         \
@@ -111,6 +255,10 @@ tracker_add_process (tracker_t * tracker,
     COPY_STRING (event.command_line, command_line);
 
     tracker_append (tracker, &event, sizeof (event));
+
+#if 0
+    g_print ("Added new process: %d (%s)\n", pid, command_line);
+#endif
 }
 
 void
@@ -133,6 +281,10 @@ tracker_add_map (tracker_t * tracker,
     event.inode = inode;
 
     tracker_append (tracker, &event, sizeof (event));
+
+#if 0
+    g_print ("   Added new map: %d (%s)\n", pid, filename);
+#endif
 }
 
 void
@@ -150,8 +302,63 @@ tracker_add_sample  (tracker_t *tracker,
     tracker_append (tracker, &event, sizeof (event));
 }
 
+/*  */
+typedef struct state_t state_t;
+
+struct state_t
+{
+    
+};
+
+static void
+new_process (state_t *tracker, new_process_t *new_process)
+{
+    
+}
+
+static void
+new_map (state_t *tracker, new_map_t *new_map)
+{
+    
+}
+
+static void
+sample (state_t *tracker, sample_t *sample)
+{
+    
+}
+
 Profile *
 tracker_create_profile (tracker_t *tracker)
 {
-    
+    uint8_t *end = tracker->events + tracker->n_event_bytes;
+    uint8_t *event;
+
+    event = tracker->events;
+    while (event < end)
+    {
+       event_type_t type = *(event_type_t *)event;
+       new_process_t *new_process;
+       new_map_t *new_map;
+       sample_t *sample;
+
+       switch (type)
+       {
+       case NEW_PROCESS:
+           
+           
+           break;
+           
+       case NEW_MAP:
+
+           
+           break;
+           
+       case SAMPLE:
+
+           
+           break;
+       }
+       
+    }
 }