summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/allocators.c12
-rw-r--r--src/app.c120
-rw-r--r--src/callgraph.c44
-rw-r--r--src/frames.c6
-rw-r--r--src/frames.h4
-rw-r--r--src/memfault.h21
-rw-r--r--src/timeline.c4
-rw-r--r--src/utils.c39
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);
diff --git a/src/app.c b/src/app.c
index 18d34f7..3a77e57 100644
--- a/src/app.c
+++ b/src/app.c
@@ -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)\