summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2007-12-04 16:52:52 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2007-12-04 16:52:52 +0000
commitf3ba4a775af355dae3511470ad46e2111418dde8 (patch)
tree3a5b4981d1caec06dc50c8c9c90d6f35e94f4277 /src
parent87ed08fb805a6af242b5563f1a34f5d93c7ca173 (diff)
Add an initial client summary.
Diffstat (limited to 'src')
-rw-r--r--src/allocators-store.c488
-rw-r--r--src/allocators.c524
-rw-r--r--src/allocators.h72
-rw-r--r--src/app.c68
-rw-r--r--src/client.h69
-rw-r--r--src/odin.h7
-rw-r--r--src/summary.c106
7 files changed, 838 insertions, 496 deletions
diff --git a/src/allocators-store.c b/src/allocators-store.c
new file mode 100644
index 0000000..f702bbb
--- /dev/null
+++ b/src/allocators-store.c
@@ -0,0 +1,488 @@
+/*
+ This file is part of odin, a memory profiler with fragmentation analysis.
+
+ Copyright (C) 2007 Chris Wilson <chris@chris-wilson.co.uk>
+
+ odin is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3 of the
+ License, or (at your option) any later version.
+
+ odin is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with odin. If not, see <http://www.gnu.org/licenses/>/
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "odin.h"
+#include "allocators.h"
+
+struct _allocators_store {
+ GObject object;
+
+ GCompareFunc sum_allocators_cmp;
+ GPtrArray *allocators;
+ struct {
+ guint size;
+ struct _sum_allocator **nodes;
+ } ht;
+ struct _sum_allocator *sums;
+
+ Chunk *sum_allocator_chunks;
+};
+
+typedef struct _allocators_store_class {
+ GObjectClass parent_class;
+} AllocatorsStoreClass;
+
+static void
+allocators_store_tree_model_init (GtkTreeModelIface *iface);
+
+static GType
+allocators_store_get_type (void);
+
+G_DEFINE_TYPE_WITH_CODE (AllocatorsStore, allocators_store, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+ allocators_store_tree_model_init))
+
+
+static struct _sum_allocator *
+_sum_allocator_alloc (AllocatorsStore *store)
+{
+ gpointer mem;
+ gsize size = sizeof (struct _sum_allocator);
+
+#ifndef G_ENABLE_DEBUG
+ Chunk *c = store->sum_allocator_chunks;
+ if (c == NULL || c->used + size > c->size) {
+ guint len = size * (32<<10);
+ c = g_malloc (sizeof (Chunk) + len);
+ c->size = len;
+ c->used = 0;
+ c->next = store->sum_allocator_chunks;
+ store->sum_allocator_chunks = c;
+ }
+
+ mem = c->mem + c->used;
+ c->used += size;
+#else
+ mem = g_malloc (size);
+#endif
+
+ return mem;
+}
+
+static gint
+_sum_allocators_cmp_by_size (gconstpointer A, gconstpointer B)
+{
+ const struct _sum_allocator * const *aa = A, * const *bb = B;
+ const struct _sum_allocator *a = *aa, *b = *bb;
+ gint cmp;
+
+ if (b->size == 0)
+ return 1;
+ if (a->size == 0)
+ return -1;
+
+ cmp = b->size - a->size;
+ if (cmp)
+ return cmp;
+
+ cmp = b->count - a->count;
+ if (cmp)
+ return cmp;
+
+ cmp = b->n_pages - a->n_pages;
+ if (cmp)
+ return cmp;
+
+ return b->n_pages * 4096 / b->size * b->count - a->n_pages * 4096 / a->size * a->count;
+}
+
+static void
+allocators_store_finalize (GObject *obj)
+{
+ AllocatorsStore *self = (AllocatorsStore *) obj;
+ Chunk *c;
+
+ c = self->sum_allocator_chunks;
+ self->sum_allocator_chunks = NULL;
+ while (c != NULL) {
+ Chunk *next = c->next;
+ g_free (c);
+ c = next;
+ }
+
+ g_ptr_array_free (self->allocators, TRUE);
+ g_free (self->ht.nodes);
+
+ G_OBJECT_CLASS (allocators_store_parent_class)->finalize (obj);
+}
+
+static void
+allocators_store_class_init (AllocatorsStoreClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ object_class->finalize = allocators_store_finalize;
+}
+
+
+/* GtkTreeModelIface */
+
+static GtkTreeModelFlags
+allocators_store_get_flags (GtkTreeModel *tree_model)
+{
+ return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint
+allocators_store_get_n_columns (GtkTreeModel *tree_model)
+{
+ return ALLOCATORS_N_COLUMNS;
+}
+
+static GType
+allocators_store_get_column_type (GtkTreeModel *tree_model,
+ gint index)
+{
+ switch (index) {
+ case ALLOCATORS_FRAME: return G_TYPE_STRING;
+ case ALLOCATORS_SIZE: return G_TYPE_UINT64;
+ case ALLOCATORS_COUNT: return G_TYPE_UINT;
+ case ALLOCATORS_NPAGES: return G_TYPE_UINT;
+ default: return G_TYPE_INVALID;
+ }
+}
+
+static gboolean
+allocators_store_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ AllocatorsStore *self = (AllocatorsStore *) tree_model;
+ guint n;
+
+ n = gtk_tree_path_get_depth (path);
+ g_return_val_if_fail (n == 1, FALSE);
+
+ n = gtk_tree_path_get_indices (path)[0];
+ if (n >= self->allocators->len)
+ return FALSE;
+
+ iter->user_data = g_ptr_array_index (self->allocators, n);
+ iter->stamp = 1;
+ return TRUE;
+}
+
+static GtkTreePath *
+allocators_store_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ GtkTreePath *path = gtk_tree_path_new ();
+ struct _sum_allocator *sum = iter->user_data;
+ gtk_tree_path_append_index (path, sum->index);
+ return path;
+}
+
+static void
+allocators_store_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value)
+{
+ struct _sum_allocator *sum = iter->user_data;
+ switch (column) {
+ case ALLOCATORS_FRAME:
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, sum->frame);
+ break;
+
+ case ALLOCATORS_SIZE:
+ g_value_init (value, G_TYPE_UINT64);
+ g_value_set_uint64 (value, sum->size);
+ break;
+
+ case ALLOCATORS_COUNT:
+ g_value_init (value, G_TYPE_UINT);
+ g_value_set_uint (value, sum->count);
+ break;
+
+ case ALLOCATORS_NPAGES:
+ g_value_init (value, G_TYPE_UINT);
+ g_value_set_uint (value, sum->n_pages);
+ break;
+ }
+}
+
+static gboolean
+allocators_store_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ AllocatorsStore *self = (AllocatorsStore *) tree_model;
+ struct _sum_allocator *sum = iter->user_data;
+ GPtrArray *array = self->allocators;
+ guint index = sum->index;
+
+ if (index >= array->len - 1)
+ return FALSE;
+
+ iter->user_data = g_ptr_array_index (array, index + 1);
+ return TRUE;
+}
+
+static gboolean
+allocators_store_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ return parent == NULL;
+}
+
+static gboolean
+allocators_store_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return FALSE;
+}
+
+static gint
+allocators_store_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return 0;
+}
+
+static gboolean
+allocators_store_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
+{
+ AllocatorsStore *self = (AllocatorsStore *) tree_model;
+ GPtrArray *array;
+
+ if (parent != NULL)
+ return FALSE;
+
+ array = self->allocators;
+ if ((guint) n >= array->len)
+ return FALSE;
+
+ iter->stamp = 1;
+ iter->user_data = g_ptr_array_index (array, n);
+ return TRUE;
+}
+
+static gboolean
+allocators_store_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ return FALSE;
+}
+
+static void
+allocators_store_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = allocators_store_get_flags;
+ iface->get_n_columns = allocators_store_get_n_columns;
+ iface->get_column_type = allocators_store_get_column_type;
+ iface->get_iter = allocators_store_get_iter;
+ iface->get_path = allocators_store_get_path;
+ iface->get_value = allocators_store_get_value;
+ iface->iter_next = allocators_store_iter_next;
+ iface->iter_children = allocators_store_iter_children;
+ iface->iter_has_child = allocators_store_iter_has_child;
+ iface->iter_n_children = allocators_store_iter_n_children;
+ iface->iter_nth_child = allocators_store_iter_nth_child;
+ iface->iter_parent = allocators_store_iter_parent;
+}
+
+static void
+allocators_store_init (AllocatorsStore *self)
+{
+ self->allocators = g_ptr_array_new ();
+ self->sum_allocators_cmp = _sum_allocators_cmp_by_size;
+
+ self->ht.size = g_spaced_primes_closest (40000); /* XXX */
+ self->ht.nodes = g_new0 (struct _sum_allocator *, self->ht.size);
+}
+
+AllocatorsStore *
+allocators_store_new (void)
+{
+ return g_object_new (allocators_store_get_type (), NULL);
+}
+
+void
+allocators_store_set_cmp (AllocatorsStore *store, GCompareFunc cmp)
+{
+ store->sum_allocators_cmp = cmp;
+}
+
+struct _sum_allocator *
+allocators_store_get_sums (AllocatorsStore *store)
+{
+ return store->sums;
+}
+
+struct _sum_allocator *
+allocators_store_get_sum (AllocatorsStore *store, const gchar *fn)
+{
+ guint index = ((gulong) fn ^ 6017773UL) % store->ht.size;
+ struct _sum_allocator *sum = store->ht.nodes[index];
+ while (sum != NULL && sum->frame != fn)
+ sum = sum->ht_next;
+ return sum;
+}
+
+struct _sum_allocator *
+allocators_store_new_sum (AllocatorsStore *store, const gchar *fn)
+{
+ struct _sum_allocator *sum;
+ guint index;
+
+ sum = _sum_allocator_alloc (store);
+ sum->next = store->sums;
+ store->sums = sum;
+
+ sum->index = sum->old_index = -1;
+ sum->size = 0;
+ sum->count = 0;
+ sum->n_pages = 0;
+ sum->min = (gulong) -1;
+ sum->max = 0;
+ sum->sorted = FALSE;
+ sum->blocks = NULL;
+
+ sum->frame = fn;
+
+ index = ((gulong) fn ^ 6017773UL) % store->ht.size;
+ sum->ht_next = store->ht.nodes[index];
+ store->ht.nodes[index] = sum;
+
+ return sum;
+}
+
+void
+allocators_store_reset_sums (AllocatorsStore *store)
+{
+ struct _sum_allocator *sum;
+
+ for (sum = store->sums; sum != NULL; sum = sum->next) {
+ sum->old_index = sum->index;
+ sum->index = -1;
+ sum->size = 0;
+ sum->count = 0;
+ sum->blocks = 0;
+ sum->n_pages = 0;
+ sum->min = (gulong) -1;
+ sum->max = 0;
+ sum->sorted = FALSE;
+ }
+}
+
+struct _GtkTreePath { /* XXX */
+ gint depth;
+ gint *indices;
+};
+
+void
+allocators_store_update (AllocatorsStore *store)
+{
+ GtkTreePath path;
+ GtkTreeIter iter;
+ gint index[1];
+ guint old_len, n;
+ gint *new_order;
+ struct _sum_allocator *sum;
+ GPtrArray *allocators;
+
+ path.indices = index;
+ iter.stamp = 1;
+
+ if (store->allocators && store->allocators->len > 1) {
+ gboolean reordered = FALSE;
+
+ old_len = store->allocators->len;
+ g_ptr_array_sort (store->allocators, store->sum_allocators_cmp);
+ new_order = g_newa (gint, old_len);
+ path.depth = 1;
+ for (n = 0; n < old_len; n++) {
+ sum = g_ptr_array_index (store->allocators, n);
+ sum->index = n;
+ if (sum->index != sum->old_index)
+ reordered = TRUE;
+
+ iter.user_data = sum;
+ path.indices[0] = n;
+ gtk_tree_model_row_changed ((GtkTreeModel *) store, &path, &iter);
+ new_order[n] = sum->old_index;
+ sum->old_index = n;
+ }
+ if (reordered) {
+ path.depth = 0;
+ gtk_tree_model_rows_reordered ((GtkTreeModel *) store,
+ &path, NULL, new_order);
+ }
+ }
+
+ allocators = g_ptr_array_new ();
+ path.depth = 1;
+ for (sum = store->sums; sum != NULL; sum = sum->next) {
+ if (sum->count) {
+ g_ptr_array_add (allocators, sum);
+ } else {
+ if (sum->old_index != (guint) -1) {
+ g_assert (store->allocators != NULL);
+ path.indices[0] = sum->index;
+ gtk_tree_model_row_deleted ((GtkTreeModel *) store, &path);
+ for (n = sum->old_index; n < store->allocators->len; n++) {
+ ((struct _sum_allocator *) g_ptr_array_index (store->allocators, n))->index--;
+ }
+ }
+ }
+ }
+ g_ptr_array_free (store->allocators, TRUE);
+
+ g_ptr_array_sort (allocators, store->sum_allocators_cmp);
+ store->allocators = allocators;
+ for (n = 0; n < allocators->len; n++) {
+ sum = g_ptr_array_index (allocators, n);
+ sum->index = n;
+
+ if (sum->old_index == (guint) -1) {
+ iter.user_data = sum;
+ path.indices[0] = n;
+ gtk_tree_model_row_inserted ((GtkTreeModel *) store, &path, &iter);
+ }
+ }
+}
+
+void
+allocators_store_update_from_allocators (AllocatorsStore *store,
+ Allocator *allocators)
+{
+ Allocator *A;
+ struct _sum_allocator *sum;
+
+ allocators_store_reset_sums (store);
+
+ for (A = allocators; A != NULL; A = A->next) {
+ sum = allocators_store_get_sum (store, A->alloc_fn);
+
+ if (sum == NULL)
+ sum = allocators_store_new_sum (store, A->alloc_fn);
+
+ sum->size += A->time_tail->bytes;
+ sum->count += A->time_tail->n_allocs;
+ }
+
+ allocators_store_update (store);
+}
diff --git a/src/allocators.c b/src/allocators.c
index 74af289..7b97235 100644
--- a/src/allocators.c
+++ b/src/allocators.c
@@ -26,40 +26,11 @@
#include <stdlib.h>
#include "odin.h"
+#include "allocators.h"
#include "block.h"
#define _(x) x
-struct _sum_allocator {
- guint index, old_index;
- const gchar *frame;
- guint64 size;
- guint count;
- guint n_pages;
- gulong min, max;
- Block **blocks;
- gboolean sorted;
- struct _sum_allocator *next, *ht_next;
-};
-
-typedef struct _allocators_store {
- GObject object;
-
- GPtrArray *allocators;
- struct {
- guint size;
- struct _sum_allocator **nodes;
- } ht;
- struct _sum_allocator *sums;
-
- Chunk *sum_allocator_chunks;
-} AllocatorsStore;
-
-typedef struct _allocators_store_class {
- GObjectClass parent_class;
-} AllocatorsStoreClass;
-
-
struct _allocators {
GtkTreeView tv;
@@ -77,81 +48,36 @@ allocators_get_type (void);
G_DEFINE_TYPE (Allocators, allocators, GTK_TYPE_TREE_VIEW)
-static void
-allocators_store_tree_model_init (GtkTreeModelIface *iface);
-
-static GType
-allocators_store_get_type (void);
-
-G_DEFINE_TYPE_WITH_CODE (AllocatorsStore, allocators_store, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
- allocators_store_tree_model_init))
-enum {
- FRAME,
- COUNT,
- NPAGES,
- SIZE,
- N_COLUMNS,
-};
-
enum {
PROP_0 = 0,
PROP_BLOCKS,
};
-static struct _sum_allocator *
-_sum_allocator_alloc (AllocatorsStore *store)
-{
- gpointer mem;
- gsize size = sizeof (struct _sum_allocator);
-
-#ifndef G_ENABLE_DEBUG
- Chunk *c = store->sum_allocator_chunks;
- if (c == NULL || c->used + size > c->size) {
- guint len = size * (32<<10);
- c = g_malloc (sizeof (Chunk) + len);
- c->size = len;
- c->used = 0;
- c->next = store->sum_allocator_chunks;
- store->sum_allocator_chunks = c;
- }
-
- mem = c->mem + c->used;
- c->used += size;
-#else
- mem = g_malloc (size);
-#endif
-
- return mem;
-}
-
-static struct _sum_allocator *
-sum_get (AllocatorsStore *store, const gchar *fn)
-{
- guint index = ((gulong) fn ^ 6017773) % store->ht.size;
- struct _sum_allocator *sum = store->ht.nodes[index];
- while (sum != NULL && sum->frame != fn)
- sum = sum->ht_next;
- return sum;
-}
-
-static gint
-block_cmp (gconstpointer A, gconstpointer B)
+static void
+_sum_allocators_count_pages (struct _sum_allocator *sum)
{
- const Block * const *aa = A, * const *bb = B;
- const Block *a = *aa, *b = *bb;
- const Allocator *Aa = a->allocator, *Ab = b->allocator;
- gint cmp;
-
- cmp = Ab->time_tail->n_allocs - Aa->time_tail->n_allocs;
- if (cmp)
- return cmp;
+ guint32 pages[1024];
+ guint pagesize = sysconf (_SC_PAGESIZE);
+ gulong n = ((sum->max - sum->min) / pagesize + 32) & ~31;
- cmp = b->size - a->size;
- if (cmp)
- return cmp;
+ if (n > 32 * G_N_ELEMENTS (pages)) {
+ sum->n_pages = block_array_count_pages (sum->blocks, sum->count);
+ } else {
+ gulong min = sum->min;
- return a->addr - b->addr;
+ memset (pages, 0, n / 8);
+ for (n = 0; n < sum->count; n++) {
+ const Block *block = sum->blocks[n];
+ gulong p = (block->addr - min) / pagesize;
+ gulong last_page = (block->addr + block->size - min) / pagesize;
+ do {
+ if ((pages[p / 32] & (1 << (p & 31 ))) == 0) {
+ pages [p / 32] |= 1 << (p & 31);
+ sum->n_pages++;
+ }
+ } while (++p <= last_page);
+ }
+ }
}
static gint
@@ -182,261 +108,13 @@ _sum_allocators_cmp (gconstpointer A, gconstpointer B)
}
static void
-allocators_store_finalize (GObject *obj)
-{
- AllocatorsStore *self = (AllocatorsStore *) obj;
- Chunk *c;
-
- c = self->sum_allocator_chunks;
- self->sum_allocator_chunks = NULL;
- while (c != NULL) {
- Chunk *next = c->next;
- g_free (c);
- c = next;
- }
-
- g_ptr_array_free (self->allocators, TRUE);
- g_free (self->ht.nodes);
-
- G_OBJECT_CLASS (allocators_store_parent_class)->finalize (obj);
-}
-
-static void
-allocators_store_class_init (AllocatorsStoreClass *klass)
-{
- GObjectClass *object_class = (GObjectClass *) klass;
-
- object_class->finalize = allocators_store_finalize;
-}
-
-
-/* GtkTreeModelIface */
-
-static GtkTreeModelFlags
-allocators_store_get_flags (GtkTreeModel *tree_model)
-{
- return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
-}
-
-static gint
-allocators_store_get_n_columns (GtkTreeModel *tree_model)
-{
- return N_COLUMNS;
-}
-
-static GType
-allocators_store_get_column_type (GtkTreeModel *tree_model,
- gint index)
-{
- switch (index) {
- case FRAME: return G_TYPE_STRING;
- case SIZE: return G_TYPE_UINT64;
- case COUNT: return G_TYPE_UINT;
- case NPAGES: return G_TYPE_UINT;
- default: return G_TYPE_INVALID;
- }
-}
-
-static gboolean
-allocators_store_get_iter (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreePath *path)
-{
- AllocatorsStore *self = (AllocatorsStore *) tree_model;
- guint n;
-
- n = gtk_tree_path_get_depth (path);
- g_return_val_if_fail (n == 1, FALSE);
-
- n = gtk_tree_path_get_indices (path)[0];
- if (n >= self->allocators->len)
- return FALSE;
-
- iter->user_data = g_ptr_array_index (self->allocators, n);
- iter->stamp = 1;
- return TRUE;
-}
-
-static GtkTreePath *
-allocators_store_get_path (GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- GtkTreePath *path = gtk_tree_path_new ();
- struct _sum_allocator *sum = iter->user_data;
- gtk_tree_path_append_index (path, sum->index);
- return path;
-}
-
-static void
-allocators_store_get_value (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gint column,
- GValue *value)
-{
- struct _sum_allocator *sum = iter->user_data;
- switch (column) {
- case FRAME:
- g_value_init (value, G_TYPE_STRING);
- g_value_set_string (value, sum->frame);
- break;
-
- case SIZE:
- g_value_init (value, G_TYPE_UINT64);
- g_value_set_uint64 (value, sum->size);
- break;
-
- case COUNT:
- g_value_init (value, G_TYPE_UINT);
- g_value_set_uint (value, sum->count);
- break;
-
- case NPAGES:
- g_value_init (value, G_TYPE_UINT);
- g_value_set_uint (value, sum->n_pages);
- break;
- }
-}
-
-static gboolean
-allocators_store_iter_next (GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- AllocatorsStore *self = (AllocatorsStore *) tree_model;
- struct _sum_allocator *sum = iter->user_data;
- GPtrArray *array = self->allocators;
- guint index = sum->index;
-
- if (index >= array->len - 1)
- return FALSE;
-
- iter->user_data = g_ptr_array_index (array, index + 1);
- return TRUE;
-}
-
-static gboolean
-allocators_store_iter_children (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent)
-{
- return parent == NULL;
-}
-
-static gboolean
-allocators_store_iter_has_child (GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- return FALSE;
-}
-
-static gint
-allocators_store_iter_n_children (GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- return 0;
-}
-
-static gboolean
-allocators_store_iter_nth_child (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent,
- gint n)
-{
- AllocatorsStore *self = (AllocatorsStore *) tree_model;
- GPtrArray *array;
-
- if (parent != NULL)
- return FALSE;
-
- array = self->allocators;
- if ((guint) n >= array->len)
- return FALSE;
-
- iter->stamp = 1;
- iter->user_data = g_ptr_array_index (array, n);
- return TRUE;
-}
-
-static gboolean
-allocators_store_iter_parent (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *child)
-{
- return FALSE;
-}
-
-static void
-allocators_store_tree_model_init (GtkTreeModelIface *iface)
-{
- iface->get_flags = allocators_store_get_flags;
- iface->get_n_columns = allocators_store_get_n_columns;
- iface->get_column_type = allocators_store_get_column_type;
- iface->get_iter = allocators_store_get_iter;
- iface->get_path = allocators_store_get_path;
- iface->get_value = allocators_store_get_value;
- iface->iter_next = allocators_store_iter_next;
- iface->iter_children = allocators_store_iter_children;
- iface->iter_has_child = allocators_store_iter_has_child;
- iface->iter_n_children = allocators_store_iter_n_children;
- iface->iter_nth_child = allocators_store_iter_nth_child;
- iface->iter_parent = allocators_store_iter_parent;
-}
-
-static void
-allocators_store_init (AllocatorsStore *self)
-{
- self->allocators = g_ptr_array_new ();
-
- self->ht.size = g_spaced_primes_closest (40000); /* XXX */
- self->ht.nodes = g_new0 (struct _sum_allocator *, self->ht.size);
-}
-
-static void
-_sum_allocators_add_to_array (struct _sum_allocator *sum, GPtrArray *array)
-{
- guint32 pages[1024];
- guint pagesize = sysconf (_SC_PAGESIZE);
- gulong n = ((sum->max - sum->min) / pagesize + 32) & ~31;
-
- g_ptr_array_add (array, sum);
-
- if (n > 32 * G_N_ELEMENTS (pages)) {
- sum->n_pages = block_array_count_pages (sum->blocks, sum->count);
- } else {
- gulong min = sum->min;
-
- memset (pages, 0, n / 8);
- for (n = 0; n < sum->count; n++) {
- const Block *block = sum->blocks[n];
- gulong p = (block->addr - min) / pagesize;
- gulong last_page = (block->addr + block->size - min) / pagesize;
- do {
- if ((pages[p / 32] & (1 << (p & 31 ))) == 0) {
- pages [p / 32] |= 1 << (p & 31);
- sum->n_pages++;
- }
- } while (++p <= last_page);
- }
- }
-}
-
-struct _GtkTreePath { /* XXX */
- gint depth;
- gint *indices;
-};
-
-static void
allocators_set_blocks (Allocators *self, Block *blocks)
{
Block *b, **block_mem;
AllocatorsStore *store;
- GtkTreePath path;
- GtkTreeIter iter;
- gint index[1];
struct _sum_allocator *sum, *sums;
gulong pagesize = sysconf (_SC_PAGESIZE);
- guint n, count, old_len;
- gint *new_order;
- GPtrArray *allocators;
+ guint count;
self->blocks = blocks;
@@ -444,44 +122,16 @@ allocators_set_blocks (Allocators *self, Block *blocks)
return;
store = self->store;
- sums = self->store->sums;
- for (sum = sums; sum != NULL; sum = sum->next) {
- sum->old_index = sum->index;
- sum->index = -1;
- sum->size = 0;
- sum->count = 0;
- sum->n_pages = 0;
- sum->min = (gulong) -1;
- sum->max = 0;
- sum->sorted = FALSE;
- }
+ allocators_store_reset_sums (store);
count = 0;
for (b = blocks; b != NULL; b = b->next) {
Allocator *A = b->allocator;
- sum = sum_get (store, A->alloc_fn);
-
- if (sum == NULL) {
- guint index;
-
- sum = _sum_allocator_alloc (store);
- sum->index = sum->old_index = -1;
- sum->size = 0;
- sum->count = 0;
- sum->n_pages = 0;
- sum->min = (gulong) -1;
- sum->max = 0;
- sum->sorted = FALSE;
- sum->next = sums;
- sums = sum;
-
- sum->frame = A->alloc_fn;
-
- index = ((gulong) A->alloc_fn ^ 6017773) % store->ht.size;
- sum->ht_next = store->ht.nodes[index];
- store->ht.nodes[index] = sum;
- }
+
+ sum = allocators_store_get_sum (store, A->alloc_fn);
+ if (sum == NULL)
+ sum = allocators_store_new_sum (store, A->alloc_fn);
if (b->addr < sum->min)
sum->min = b->addr;
@@ -492,13 +142,18 @@ allocators_set_blocks (Allocators *self, Block *blocks)
sum->count++;
count++;
}
- store->sums = sums;
- sum->min &= ~(pagesize - 1);
- sum->max = (sum->max + pagesize) & ~(pagesize - 1);
+
+ sums = allocators_store_get_sums (store);
self->blocks_mem = g_renew (Block *, self->blocks_mem, count);
block_mem = self->blocks_mem;
for (sum = sums; sum != NULL; sum = sum->next) {
+ if (sum->count == 0)
+ continue;
+
+ sum->min &= ~(pagesize - 1);
+ sum->max = (sum->max + pagesize) & ~(pagesize - 1);
+
sum->blocks = block_mem;
block_mem += sum->count;
sum->count = 0;
@@ -506,74 +161,18 @@ allocators_set_blocks (Allocators *self, Block *blocks)
for (b = blocks; b != NULL; b = b->next) {
Allocator *A = b->allocator;
- sum = sum_get (store, A->alloc_fn);
+ sum = allocators_store_get_sum (store, A->alloc_fn);
+ g_assert (sum != NULL);
sum->blocks[sum->count++] = b;
}
+ for (sum = sums; sum != NULL; sum = sum->next)
+ if (sum->count)
+ _sum_allocators_count_pages (sum);
- path.indices = index;
- iter.stamp = 1;
-
- if (store->allocators && store->allocators->len > 1) {
- gboolean reordered = FALSE;
-
- old_len = store->allocators->len;
- g_ptr_array_sort (store->allocators, _sum_allocators_cmp);
- new_order = g_newa (gint, old_len);
- path.depth = 1;
- for (n = 0; n < old_len; n++) {
- sum = g_ptr_array_index (store->allocators, n);
- sum->index = n;
- if (sum->index != sum->old_index)
- reordered = TRUE;
-
- iter.user_data = sum;
- path.indices[0] = n;
- gtk_tree_model_row_changed ((GtkTreeModel *) store, &path, &iter);
- new_order[n] = sum->old_index;
- sum->old_index = n;
- }
- if (reordered) {
- path.depth = 0;
- gtk_tree_model_rows_reordered ((GtkTreeModel *) store,
- &path, NULL, new_order);
- }
- }
-
- allocators = g_ptr_array_new ();
- path.depth = 1;
- for (sum = sums; sum != NULL; sum = sum->next) {
- if (sum->count) {
- _sum_allocators_add_to_array (sum, allocators);
- } else {
- if (sum->old_index != (guint) -1) {
- g_assert (store->allocators != NULL);
- path.indices[0] = sum->index;
- gtk_tree_model_row_deleted ((GtkTreeModel *) store, &path);
- for (n = sum->old_index; n < store->allocators->len; n++) {
- ((struct _sum_allocator *) g_ptr_array_index (store->allocators, n))->index--;
- }
- }
-
- }
- }
- g_ptr_array_free (store->allocators, TRUE);
-
- g_ptr_array_sort (allocators, _sum_allocators_cmp);
- store->allocators = allocators;
- for (n = 0; n < allocators->len; n++) {
- sum = g_ptr_array_index (allocators, n);
- sum->index = n;
-
- if (sum->old_index == (guint) -1) {
- iter.user_data = sum;
- path.indices[0] = n;
- gtk_tree_model_row_inserted ((GtkTreeModel *) store, &path, &iter);
- }
- }
+ allocators_store_update (store);
}
-
static void
allocators_set_property (GObject *obj, guint id, const GValue *v, GParamSpec *spec)
{
@@ -602,6 +201,26 @@ allocators_get_property (GObject *obj, guint id, GValue *v, GParamSpec *spec)
}
}
+static gint
+block_cmp (gconstpointer A, gconstpointer B)
+{
+ const Block * const *aa = A, * const *bb = B;
+ const Block *a = *aa, *b = *bb;
+ const Allocator *Aa = a->allocator, *Ab = b->allocator;
+ gint cmp;
+
+ cmp = Ab->time_tail->n_allocs - Aa->time_tail->n_allocs;
+ if (cmp)
+ return cmp;
+
+ cmp = b->size - a->size;
+ if (cmp)
+ return cmp;
+
+ return a->addr - b->addr;
+}
+
+
static gboolean
allocators_query_tooltip (GtkWidget *widget,
gint x,
@@ -800,28 +419,28 @@ allocators_init (Allocators *self)
"width-chars", 50,
NULL);
column = gtk_tree_view_column_new_with_attributes ("Allocator",
- renderer, "text", FRAME, NULL);
+ renderer, "text", ALLOCATORS_FRAME, NULL);
gtk_tree_view_append_column (&self->tv, column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Count",
renderer, NULL);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer,
- cell_layout_pretty_print_uint, GUINT_TO_POINTER (COUNT), NULL);
+ cell_layout_pretty_print_uint, GUINT_TO_POINTER (ALLOCATORS_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, NULL);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer,
- cell_layout_pretty_print_uint64, GUINT_TO_POINTER (SIZE), NULL);
+ cell_layout_pretty_print_uint64, GUINT_TO_POINTER (ALLOCATORS_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, NULL);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer,
- cell_layout_pretty_print_uint, GUINT_TO_POINTER (NPAGES), NULL);
+ cell_layout_pretty_print_uint, GUINT_TO_POINTER (ALLOCATORS_NPAGES), NULL);
gtk_tree_view_append_column (&self->tv, column);
gtk_tree_view_set_grid_lines (&self->tv, GTK_TREE_VIEW_GRID_LINES_VERTICAL);
@@ -831,7 +450,8 @@ allocators_init (Allocators *self)
gtk_widget_set_has_tooltip (GTK_WIDGET (self), TRUE);
- self->store = g_object_new (allocators_store_get_type (), NULL);
+ self->store = allocators_store_new ();
+ allocators_store_set_cmp (self->store, _sum_allocators_cmp);
gtk_tree_view_set_model (&self->tv, GTK_TREE_MODEL (self->store));
}
@@ -846,7 +466,8 @@ allocators_reset (Allocators *self)
{
g_object_unref (self->store);
- self->store = g_object_new (allocators_store_get_type (), NULL);
+ self->store = allocators_store_new ();
+ allocators_store_set_cmp (self->store, _sum_allocators_cmp);
gtk_tree_view_set_model (&self->tv, GTK_TREE_MODEL (self->store));
}
@@ -880,7 +501,8 @@ allocators_select_blocks (Allocators *self, GSList *blocks)
GtkTreeIter iter;
GtkTreePath *path;
- iter.user_data = sum_get (self->store, b->allocator->alloc_fn);
+ iter.user_data = allocators_store_get_sum (self->store,
+ b->allocator->alloc_fn);
iter.stamp = 1;
path = gtk_tree_model_get_path (model, &iter);
gtk_tree_view_expand_to_path (&self->tv, path);
diff --git a/src/allocators.h b/src/allocators.h
new file mode 100644
index 0000000..ca73469
--- /dev/null
+++ b/src/allocators.h
@@ -0,0 +1,72 @@
+/*
+ This file is part of odin, a memory profiler with fragmentation analysis.
+
+ Copyright (C) 2007 Chris Wilson <chris@chris-wilson.co.uk>
+
+ odin is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3 of the
+ License, or (at your option) any later version.
+
+ odin is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with odin. If not, see <http://www.gnu.org/licenses/>/
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef ALLOCATORS_H
+#define ALLOCATORS_H
+
+struct _sum_allocator {
+ guint index, old_index;
+ const gchar *frame;
+ guint64 size;
+ guint count;
+ guint n_pages;
+ gulong min, max;
+ Block **blocks;
+ gboolean sorted;
+ struct _sum_allocator *next, *ht_next;
+};
+
+typedef struct _allocators_store AllocatorsStore;
+
+enum {
+ ALLOCATORS_FRAME,
+ ALLOCATORS_COUNT,
+ ALLOCATORS_NPAGES,
+ ALLOCATORS_SIZE,
+ ALLOCATORS_N_COLUMNS,
+};
+
+AllocatorsStore *
+allocators_store_new (void);
+
+void
+allocators_store_set_cmp (AllocatorsStore *store, GCompareFunc cmp);
+
+struct _sum_allocator *
+allocators_store_get_sums (AllocatorsStore *store);
+
+struct _sum_allocator *
+allocators_store_get_sum (AllocatorsStore *store, const gchar *fn);
+
+struct _sum_allocator *
+allocators_store_new_sum (AllocatorsStore *store, const gchar *fn);
+
+void
+allocators_store_reset_sums (AllocatorsStore *store);
+
+void
+allocators_store_update (AllocatorsStore *store);
+
+void
+allocators_store_update_from_allocators (AllocatorsStore *store,
+ Allocator *allocators);
+
+#endif /* ALLOCATORS_H */
diff --git a/src/app.c b/src/app.c
index de426c1..ea3a2f6 100644
--- a/src/app.c
+++ b/src/app.c
@@ -32,6 +32,7 @@
#include <errno.h>
#include "odin.h"
+#include "client.h"
#include "block.h"
#include "callgraph.h"
#include "frames.h"
@@ -39,47 +40,10 @@
#include "lwp-events.h"
-struct _client {
- enum {
- LWP,
- VALGRIND
- } type;
- gboolean active;
-
- gchar *name;
- GPid pid;
- gboolean terminated;
-
- guint last;
-
- Allocator *allocators;
- struct {
- guint size;
- guint nnodes;
- Allocator **nodes;
- } allocator_by_addr;
-
- Block *blocks;
- struct {
- guint size;
- guint nnodes;
- Block **nodes;
- } block_by_addr;
-
- Frames frames;
-
- CallGraphStore *call_graph;
-
- GArray *events;
-
- Chunk *perm_chunks;
- Chunk *block_chunks;
- Block *block_free_list;
-};
-
struct _app {
GdkCursor *busy_cursor;
GtkWidget *window;
+ GtkWidget *summary;
struct {
GtkWidget *allocators;
GtkWidget *block_map;
@@ -667,7 +631,7 @@ _client_update_alloc_fn (Client *client)
}
static void
-app_update_allocators (App *app, guint time)
+app_update_allocators (App *app, Client *client, guint time)
{
_client_update_alloc_fn (&app->client);
@@ -679,9 +643,19 @@ app_update_allocators (App *app, guint time)
timeline_add_datum ((Timeline *) app->timeline, &app->client,
time, app->client.allocators);
+ summary_update ((Summary *) app->summary, client);
+
app->client.last = time;
}
+static void
+app_update_client (App *app, Client *client, guint time)
+{
+ app_update_allocators (app, client, time);
+ app_set_blocks (app, client->blocks);
+}
+
+
static gboolean
vg_read (GIOChannel *io, App *app)
{
@@ -865,9 +839,8 @@ vg_read (GIOChannel *io, App *app)
g_array_append_val (app->client.events, ev);
}
- app_update_allocators (app, time);
- app_set_blocks (app, app->client.blocks = blocks);
-
+ app->client.blocks = blocks;
+ app_update_client (app, &app->client, time);
app_update_status (app);
return TRUE;
@@ -961,6 +934,8 @@ main_window_create (App *app)
app->allocations.tree_map = call_graph_tree_map_new ();
app->allocations.ring = call_graph_ring_new ();
+ app->summary = summary_new ();
+
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (app->allocations.call_graph));
g_signal_connect (selection, "changed",
G_CALLBACK (call_graph_selection_changed),
@@ -1004,6 +979,11 @@ main_window_create (App *app)
gtk_box_pack_start (GTK_BOX (vbox), app->statusbar, FALSE, FALSE, 2);
gtk_widget_show (app->statusbar);
+ label = gtk_label_new ("Summary");
+ gtk_notebook_append_page (GTK_NOTEBOOK (app->notebook), app->summary, label);
+ gtk_widget_show (label);
+ gtk_widget_show (app->summary);
+
hbox = gtk_hbox_new (FALSE, 2);
label = gtk_label_new ("Allocation Map");
gtk_notebook_append_page (GTK_NOTEBOOK (app->notebook), hbox, label);
@@ -1601,14 +1581,12 @@ lwp_read (GIOChannel *io, App *app)
}
}
- app_update_allocators (app, time);
- app_set_blocks (app, app->client.blocks);
-
if (app->client.pid) {
if (! _get_pid_cmd (app->client.pid, client, G_N_ELEMENTS (client)))
strcpy (client, "«unknown»");
_app_set_client_name (app, client);
}
+ app_update_client (app, &app->client, time);
app_update_status (app);
return TRUE;
diff --git a/src/client.h b/src/client.h
new file mode 100644
index 0000000..7131b86
--- /dev/null
+++ b/src/client.h
@@ -0,0 +1,69 @@
+/*
+ This file is part of odin, a memory profiler with fragmentation analysis.
+
+ Copyright (C) 2007 Chris Wilson <chris@chris-wilson.co.uk>
+
+ odin is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3 of the
+ License, or (at your option) any later version.
+
+ odin is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with odin. If not, see <http://www.gnu.org/licenses/>/
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include <gtk/gtk.h>
+
+#include "frames.h"
+
+G_BEGIN_DECLS
+
+struct _client {
+ enum {
+ LWP,
+ VALGRIND
+ } type;
+ gboolean active;
+
+ gchar *name;
+ GPid pid;
+ gboolean terminated;
+
+ guint last;
+
+ Allocator *allocators;
+ struct {
+ guint size;
+ guint nnodes;
+ Allocator **nodes;
+ } allocator_by_addr;
+
+ Block *blocks;
+ struct {
+ guint size;
+ guint nnodes;
+ Block **nodes;
+ } block_by_addr;
+
+ Frames frames;
+
+ CallGraphStore *call_graph;
+
+ GArray *events;
+
+ Chunk *perm_chunks;
+ Chunk *block_chunks;
+ Block *block_free_list;
+};
+
+#endif /* CLIENT_H */
diff --git a/src/odin.h b/src/odin.h
index a7c34fd..21fb619 100644
--- a/src/odin.h
+++ b/src/odin.h
@@ -39,6 +39,7 @@ typedef struct _allocators Allocators;
typedef struct _block_map BlockMap;
typedef struct _call_graph CallGraph;
typedef struct _procmap Procmap;
+typedef struct _summary Summary;
typedef struct _timeline Timeline;
typedef struct _call_graph_frame CallGraphFrame;
@@ -229,6 +230,12 @@ procmap_new (void);
G_CONST_RETURN Event *
app_find_prev_event_for_addr_range (App *app, guint time, gulong min, gulong max);
+GtkWidget *
+summary_new (void);
+
+void
+summary_update (Summary *summary, Client *client);
+
void
pretty_print_number (const char *number, gint len, char *output);
diff --git a/src/summary.c b/src/summary.c
new file mode 100644
index 0000000..44167fe
--- /dev/null
+++ b/src/summary.c
@@ -0,0 +1,106 @@
+/*
+ This file is part of odin, a memory profiler with fragmentation analysis.
+
+ Copyright (C) 2007 Chris Wilson <chris@chris-wilson.co.uk>
+
+ odin is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3 of the
+ License, or (at your option) any later version.
+
+ odin is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with odin. If not, see <http://www.gnu.org/licenses/>/
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include <gtk/gtk.h>
+
+#include "odin.h"
+#include "client.h"
+#include "allocators.h"
+
+struct _summary {
+ GtkFrame bin;
+
+ AllocatorsStore *store;
+};
+
+typedef struct _summary_class {
+ GtkFrameClass parent_class;
+} SummaryClass;
+
+static GType
+summary_get_type (void);
+
+G_DEFINE_TYPE (Summary, summary, GTK_TYPE_FRAME)
+
+static void
+summary_class_init (SummaryClass *klass)
+{
+}
+
+static void
+summary_init (Summary *self)
+{
+ GtkWidget *w, *sw;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ self->store = allocators_store_new ();
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_container_add (GTK_CONTAINER (self), sw);
+ gtk_widget_show (sw);
+
+ w = gtk_tree_view_new_with_model ((GtkTreeModel *) self->store);
+ gtk_container_add (GTK_CONTAINER (sw), w);
+ gtk_widget_show (w);
+
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (G_OBJECT (renderer),
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ "ellipsize-set", TRUE,
+ "width-chars", 50,
+ NULL);
+ column = gtk_tree_view_column_new_with_attributes ("Allocator",
+ renderer, "text", ALLOCATORS_FRAME, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (w), 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,
+ cell_layout_pretty_print_uint64, GUINT_TO_POINTER (ALLOCATORS_SIZE),
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (w), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Count",
+ renderer, NULL);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer,
+ cell_layout_pretty_print_uint, GUINT_TO_POINTER (ALLOCATORS_COUNT),
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (w), column);
+
+}
+
+GtkWidget *
+summary_new (void)
+{
+ return g_object_new (summary_get_type (), NULL);
+}
+
+void
+summary_update (Summary *summary, Client *client)
+{
+ allocators_store_update_from_allocators (summary->store,
+ client->allocators);
+}