diff --git a/collector.c b/collector.c index 7315da99..31bfdd85 100644 --- a/collector.c +++ b/collector.c @@ -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) { - if (collector->stash) - stack_stash_unref (collector->stash); + 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; } diff --git a/sysprof.c b/sysprof.c index fd689b70..f3b8d772 100644 --- 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); } diff --git a/tracker.c b/tracker.c index 65978eb3..8970718c 100644 --- a/tracker.c +++ b/tracker.c @@ -1,5 +1,7 @@ #include #include +#include +#include #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)); } -Profile * -tracker_create_profile (tracker_t *tracker) +/* */ +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; + } + + } +}