diff options
-rw-r--r-- | src/allocators.c | 12 | ||||
-rw-r--r-- | src/app.c | 120 | ||||
-rw-r--r-- | src/callgraph.c | 44 | ||||
-rw-r--r-- | src/frames.c | 6 | ||||
-rw-r--r-- | src/frames.h | 4 | ||||
-rw-r--r-- | src/memfault.h | 21 | ||||
-rw-r--r-- | src/timeline.c | 4 | ||||
-rw-r--r-- | src/utils.c | 39 |
8 files changed, 161 insertions, 89 deletions
diff --git a/src/allocators.c b/src/allocators.c index 5fb52e3..9d6bf13 100644 --- a/src/allocators.c +++ b/src/allocators.c @@ -647,17 +647,23 @@ allocators_init (Allocators *self) renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Count", - renderer, "text", COUNT, NULL); + renderer, NULL); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer, + cell_layout_pretty_print_uint, GUINT_TO_POINTER (COUNT), NULL); gtk_tree_view_append_column (&self->tv, column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Size", - renderer, "text", SIZE, NULL); + renderer, NULL); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer, + cell_layout_pretty_print_uint64, GUINT_TO_POINTER (SIZE), NULL); gtk_tree_view_append_column (&self->tv, column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Pages", - renderer, "text", NPAGES, NULL); + renderer, NULL); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer, + cell_layout_pretty_print_uint, GUINT_TO_POINTER (NPAGES), NULL); gtk_tree_view_append_column (&self->tv, column); gtk_tree_view_set_grid_lines (&self->tv, GTK_TREE_VIEW_GRID_LINES_VERTICAL); @@ -9,6 +9,8 @@ #include "callgraph.h" #include "frames.h" +typedef struct _chunk Chunk; + struct _app { GtkWidget *window; struct { @@ -35,10 +37,63 @@ struct _app { GArray *events; GTcpSocket *tcp; + Chunk *chunks, *full_chunks; +}; + +struct _chunk { + struct _chunk *next; + guint used, size; + gchar mem[0]; }; static GQuark app_quark; +static guint +pow2_max (guint n, guint min) +{ + while (n < min) + n <<= 1; + return n; +} + +gpointer +app_alloc (App *app, guint size) +{ + Chunk *c; + gpointer mem; + + for (c = app->chunks; c != NULL; c = c->next) { + if (c->used + size <= c->size) + break; + } + if (c == NULL) { + guint len = pow2_max (4<<20, size); + c = g_malloc (sizeof (Chunk) + len); + c->size = len; + c->used = 0; + c->next = app->chunks; + app->chunks = c; + } + + mem = c->mem + c->used; + c->used += size; + + if (c->used + 128 > c->size) { + if (app->chunks == c) { + app->chunks = c->next; + } else { + Chunk *prev; + for (prev = app->chunks; prev->next != c; prev = prev->next) + ; + prev->next = c->next; + } + c->next = app->full_chunks; + app->full_chunks = c; + } + + return mem; +} + static gboolean readn (int fd, gpointer data, gsize len) { @@ -132,23 +187,20 @@ read_allocator (App *app, int fd, guint time) A = g_hash_table_lookup (app->allocators_by_addr, GUINT_TO_POINTER (key)); if (A == NULL) { - A = g_slice_new (Allocator); + A = app_alloc (app, sizeof (Allocator)); At = &A->time[0]; - if (! readn (fd, &A->n_frames, sizeof (A->n_frames))) { - g_slice_free (Allocator, A); + if (! readn (fd, &A->n_frames, sizeof (A->n_frames))) return NULL; - } - A->ips = g_malloc (sizeof (guint) * A->n_frames + + A->ips = app_alloc (app, + sizeof (guint) * A->n_frames + sizeof (const gchar *) * 2 * A->n_frames); A->functions = (const gchar **) (A->ips + A->n_frames); A->functions_srcloc = A->functions + A->n_frames; - if (! readn (fd, A->ips, A->n_frames * sizeof (guint))) { - g_free (A->ips); - g_slice_free (Allocator, A); - } + if (! readn (fd, A->ips, A->n_frames * sizeof (guint))) + return NULL; for (n = 0; n < A->n_frames; n++) { Frame *frame = frames_get (app->frames, A->ips[n]); @@ -164,13 +216,12 @@ read_allocator (App *app, int fd, guint time) g_assert (A->time_tail->time < time); - At = g_slice_new (AllocatorTime); + At = app_alloc (app, sizeof (AllocatorTime)); A->time_tail->next = At; if (! readn (fd, &n_frames, sizeof (n_frames)) || ! discardn (fd, A->n_frames * sizeof (guint))) { - g_slice_free (AllocatorTime, At); return NULL; } @@ -214,10 +265,11 @@ read_allocator (App *app, int fd, guint time) do { if (! readn (fd, &tid, sizeof (tid))) return NULL; + if (tid == 0) break; - f->next = g_slice_new (ThreadFaults); + f->next = app_alloc (app, sizeof (ThreadFaults)); f = f->next; f->tid = tid; @@ -336,18 +388,17 @@ load_allocators (GIOChannel *io, App *app) gint len; int fd; Block *blocks; - gchar *client; + gchar client[1024]; gint pid, time; guint n_allocs, n_blocks; fd = g_io_channel_unix_get_fd (io); if (! readn (fd, &len, sizeof (len))) return FALSE; - client = g_malloc (len + 1); - if (! readn (fd, client, len)) { - g_free (client); + g_return_val_if_fail ((guint) len < G_N_ELEMENTS (client), FALSE); + if (! readn (fd, client, len)) return FALSE; - } + client[len] = '\0'; app_set_client_name (app, client); @@ -395,7 +446,6 @@ load_allocators (GIOChannel *io, App *app) g_free (file); if (directory < buf || directory > bp) g_free (directory); - g_free (client); return FALSE; } @@ -422,35 +472,31 @@ load_allocators (GIOChannel *io, App *app) n_allocs = 0; while (count--) { Allocator *A = read_allocator (app, fd, time); - if (A == NULL) { - g_free (client); + if (A == NULL) return FALSE; - } + n_allocs += A->time_tail->n_allocs; } /* blocks */ - if (! readn (fd, &count, sizeof (count))) { - g_free (client); + if (! readn (fd, &count, sizeof (count))) return FALSE; - } + blocks = NULL; n_blocks = count; while (count--) { Block *new_blocks = read_block (fd, app->allocators_by_addr, blocks); - if (new_blocks == NULL) { - g_free (client); + if (new_blocks == NULL) return FALSE; - } + blocks = new_blocks; } /* events */ - if (! readn (fd, &count, sizeof (count))) { - g_free (client); + if (! readn (fd, &count, sizeof (count))) return FALSE; - } + while (count--) { Event ev; gchar c; @@ -462,16 +508,13 @@ load_allocators (GIOChannel *io, App *app) ! readn (fd, &ev.base.tid, sizeof (ev.base.tid)) || ! readn (fd, &allocator, sizeof (allocator))) { - g_free (client); return FALSE; } ev.base.allocator = g_hash_table_lookup (app->allocators_by_addr, GUINT_TO_POINTER (allocator)); - if (ev.base.allocator == NULL) { - g_free (client); + if (ev.base.allocator == NULL) return FALSE; - } ev.type = c; switch (ev.type) { @@ -479,7 +522,6 @@ load_allocators (GIOChannel *io, App *app) if (! readn (fd, &ev.alloc.addr, sizeof (ev.alloc.addr)) || ! readn (fd, &ev.alloc.size, sizeof (ev.alloc.size))) { - g_free (client); return FALSE; } @@ -491,15 +533,14 @@ load_allocators (GIOChannel *io, App *app) ! readn (fd, &ev.realloc.new_addr, sizeof (ev.realloc.new_addr)) || ! readn (fd, &ev.realloc.new_size, sizeof (ev.realloc.new_size))) { - g_free (client); return FALSE; } break; case DEALLOC: if (! readn (fd, &ev.dealloc.addr, sizeof (ev.dealloc.addr)) || - ! readn (fd, &ev.dealloc.size, sizeof (ev.dealloc.size))) { - g_free (client); + ! readn (fd, &ev.dealloc.size, sizeof (ev.dealloc.size))) + { return FALSE; } break; @@ -512,7 +553,6 @@ load_allocators (GIOChannel *io, App *app) app_set_blocks (app, blocks); app_set_status (app, client, time, n_allocs, n_blocks, app->call_graph->n_frames); - g_free (client); return TRUE; } @@ -915,7 +955,7 @@ int main gtk_init (&argc, &argv); app_quark = g_quark_from_static_string ("«App»"); - app.frames = frames_create (); + app.frames = frames_create (&app); app.events = g_array_new (FALSE, FALSE, sizeof (Event)); app.allocators_by_addr = g_hash_table_new (NULL, NULL); diff --git a/src/callgraph.c b/src/callgraph.c index 0caeaa9..4f77fbf 100644 --- a/src/callgraph.c +++ b/src/callgraph.c @@ -461,44 +461,6 @@ call_graph_search_equal_func (GtkTreeModel *model, } static void -pretty_print_uint (GtkCellLayout *layout, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - guint v; - char buf[80]; - gint len; - - gtk_tree_model_get (model, iter, GPOINTER_TO_UINT (data), &v, -1); - - len = g_snprintf (buf + 40, 40, "%u", v); - pretty_print_number (buf + 40, len, buf); - - g_object_set (G_OBJECT (cell), "text", buf, NULL); -} - -static void -pretty_print_uint64 (GtkCellLayout *layout, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - guint64 v; - char buf[160]; - gint len; - - gtk_tree_model_get (model, iter, GPOINTER_TO_UINT (data), &v, -1); - - len = g_snprintf (buf + 80, 80, "%" G_GUINT64_FORMAT, v); - pretty_print_number (buf + 80, len, buf); - - g_object_set (G_OBJECT (cell), "text", buf, NULL); -} - -static void call_graph_init (CallGraph *self) { GtkTreeStore *store; @@ -520,21 +482,21 @@ call_graph_init (CallGraph *self) column = gtk_tree_view_column_new_with_attributes ("Allocs", renderer, NULL); gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer, - pretty_print_uint, GUINT_TO_POINTER (CG_ALLOCS), NULL); + cell_layout_pretty_print_uint, GUINT_TO_POINTER (CG_ALLOCS), NULL); gtk_tree_view_append_column (&self->tv, column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Frees", renderer, NULL); gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer, - pretty_print_uint, GUINT_TO_POINTER (CG_FREES), NULL); + cell_layout_pretty_print_uint, GUINT_TO_POINTER (CG_FREES), NULL); gtk_tree_view_append_column (&self->tv, column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Bytes", renderer, NULL); gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer, - pretty_print_uint64, GUINT_TO_POINTER (CG_BYTES), NULL); + cell_layout_pretty_print_uint64, GUINT_TO_POINTER (CG_BYTES), NULL); gtk_tree_view_append_column (&self->tv, column); renderer = g_object_new (cell_renderer_distribution_get_type (), NULL); diff --git a/src/frames.c b/src/frames.c index 3683c76..0eb810f 100644 --- a/src/frames.c +++ b/src/frames.c @@ -2,6 +2,7 @@ #include "frames.h" struct _frames { + App *app; GHashTable *frames; GList *alloc_fns; @@ -79,7 +80,7 @@ frames_add (Frames *frames, if (f != NULL) return; - f = g_slice_new (Frame); + f = app_alloc (frames->app, sizeof (Frame)); f->ip = ip; tmp = NULL; if (function == NULL && object != NULL) { @@ -235,11 +236,12 @@ srcloc_equal (gconstpointer A, gconstpointer B) } Frames * -frames_create (void) +frames_create (App *app) { Frames *frames; frames = g_new (Frames, 1); + frames->app = app; frames->frames = g_hash_table_new_full (NULL, NULL, NULL, _frame_destroy); frames->alloc_fns = NULL; frames->alloc_fns_serial = 0; diff --git a/src/frames.h b/src/frames.h index ec07c27..dfb0bf3 100644 --- a/src/frames.h +++ b/src/frames.h @@ -1,6 +1,8 @@ #ifndef FRAMES_H #define FRAMES_H +#include "memfault.h" + G_BEGIN_DECLS typedef struct _frame { @@ -51,7 +53,7 @@ const gchar * frames_get_string (Frames *frames, const gchar *str); Frames * -frames_create (void); +frames_create (App *app); void frames_destroy (Frames *frames); diff --git a/src/memfault.h b/src/memfault.h index 899d781..e0b45ee 100644 --- a/src/memfault.h +++ b/src/memfault.h @@ -120,6 +120,9 @@ typedef union _event { App * app_get (GtkWidget *widget); +gpointer +app_alloc (App *app, guint size); + gboolean app_add_alloc_fn (App *app, const gchar *pattern, GError **error); @@ -179,7 +182,23 @@ app_find_prev_event_for_addr_range (App *app, guint time, guint min, guint max); void pretty_print_number (const char *number, gint len, char *output); -gdouble median_double(gdouble *v, guint n); +void +cell_layout_pretty_print_uint (GtkCellLayout *layout, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); + +void +cell_layout_pretty_print_uint64 (GtkCellLayout *layout, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); + +gdouble +median_double (gdouble *v, guint n); + G_END_DECLS #endif /* MEMFAULT_H */ diff --git a/src/timeline.c b/src/timeline.c index e7d0a98..90dafa5 100644 --- a/src/timeline.c +++ b/src/timeline.c @@ -344,11 +344,13 @@ timeline_new (void) void timeline_add_datum (Timeline *tl, guint time, Allocator *A) { - TimelineData *data = g_slice_new (TimelineData); + TimelineData *data; TimelineData *prev; guint64 bytes; guint blocks; + data = app_alloc (app_get (&tl->widget), sizeof (TimelineData)); + prev = tl->tail; if (tl->tail != NULL) { g_assert (time > tl->tail->time); diff --git a/src/utils.c b/src/utils.c index f34b49c..5ad779f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -20,6 +20,45 @@ pretty_print_number (const char *number, gint len, char *output) } } +void +cell_layout_pretty_print_uint (GtkCellLayout *layout, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + guint v; + char buf[80]; + gint len; + + gtk_tree_model_get (model, iter, GPOINTER_TO_UINT (data), &v, -1); + + len = g_snprintf (buf + 40, 40, "%u", v); + pretty_print_number (buf + 40, len, buf); + + g_object_set (G_OBJECT (cell), "text", buf, NULL); +} + +void +cell_layout_pretty_print_uint64 (GtkCellLayout *layout, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + guint64 v; + char buf[160]; + gint len; + + gtk_tree_model_get (model, iter, GPOINTER_TO_UINT (data), &v, -1); + + len = g_snprintf (buf + 80, 80, "%" G_GUINT64_FORMAT, v); + pretty_print_number (buf + 80, len, buf); + + g_object_set (G_OBJECT (cell), "text", buf, NULL); +} + + #define swap(a,b) G_STMT_START{ t=v[a]; v[a]=v[b]; v[b]=t; }G_STMT_END #define MEDIAN(type) \ g##type median_##type(g##type *v, guint n)\ |