summaryrefslogtreecommitdiff
path: root/src/maps-store.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/maps-store.c')
-rw-r--r--src/maps-store.c321
1 files changed, 321 insertions, 0 deletions
diff --git a/src/maps-store.c b/src/maps-store.c
new file mode 100644
index 0000000..963f0a9
--- /dev/null
+++ b/src/maps-store.c
@@ -0,0 +1,321 @@
+/*
+ This file is part of odin, a memory profiler with fragmentation analysis.
+
+ Copyright (C) 2009 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 <glibtop.h>
+#include <glibtop/procmap.h>
+
+#include "odin.h"
+#include "client.h"
+#include "maps.h"
+
+struct _maps_store {
+ GObject object;
+
+ App *app;
+ guint max_path;
+};
+
+typedef struct _maps_store_class {
+ GObjectClass parent_class;
+} MapsStoreClass;
+
+static void
+maps_store_tree_model_init (GtkTreeModelIface *iface);
+
+static GType
+maps_store_get_type (void);
+
+G_DEFINE_TYPE_WITH_CODE (MapsStore, maps_store, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+ maps_store_tree_model_init))
+
+static void
+maps_store_class_init (MapsStoreClass *klass)
+{
+}
+
+
+/* GtkTreeModelIface */
+
+static GtkTreeModelFlags
+maps_store_get_flags (GtkTreeModel *tree_model)
+{
+ return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint
+maps_store_get_n_columns (GtkTreeModel *tree_model)
+{
+ return MAPS_N_COLUMNS;
+}
+
+static GType
+maps_store_get_column_type (GtkTreeModel *tree_model,
+ gint index)
+{
+ switch (index) {
+ case MAPS_FILENAME: return G_TYPE_STRING;
+ case MAPS_MODE: return G_TYPE_STRING;
+ case MAPS_ADDR: return G_TYPE_ULONG;
+ case MAPS_SIZE: return G_TYPE_ULONG;
+ case MAPS_RSS: return G_TYPE_ULONG;
+ case MAPS_DIRTY: return G_TYPE_ULONG;
+ default: return G_TYPE_INVALID;
+ }
+}
+
+static gboolean
+maps_store_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ MapsStore *self = (MapsStore *) tree_model;
+ Client *client = app_get_client (self->app);
+ Map *map;
+ gulong n;
+
+ n = gtk_tree_path_get_depth (path);
+ g_return_val_if_fail (n == 1, FALSE);
+
+ n = gtk_tree_path_get_indices (path)[0];
+ map = client->mappings;
+ while (map != NULL && n--)
+ map = map->next;
+ if (map == NULL)
+ return FALSE;
+
+ iter->user_data = map;
+ iter->stamp = 1;
+ return TRUE;
+}
+
+static GtkTreePath *
+maps_store_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ Map *map = iter->user_data;
+ GtkTreePath *path;
+
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, map->index);
+ return path;
+}
+
+static void
+maps_store_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value)
+{
+ Map *map = iter->user_data;
+ switch (column) {
+ case MAPS_FILENAME:
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, map->filename ? map->filename : "");
+ break;
+
+ case MAPS_MODE: {
+ gchar perm[6];
+ perm [0] = map->perm & GLIBTOP_MAP_PERM_READ ? 'r' : '-';
+ perm [1] = map->perm & GLIBTOP_MAP_PERM_WRITE ? 'w' : '-';
+ perm [2] = map->perm & GLIBTOP_MAP_PERM_EXECUTE ? 'x' : '-';
+ perm [3] = map->perm & GLIBTOP_MAP_PERM_SHARED ? 's' : '-';
+ perm [4] = map->perm & GLIBTOP_MAP_PERM_PRIVATE ? 'p' : '-';
+ perm [5] = '\0';
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, perm);
+ break;
+ }
+
+ case MAPS_ADDR:
+ g_value_init (value, G_TYPE_ULONG);
+ g_value_set_ulong (value, (gulong) map->addr);
+ break;
+
+ case MAPS_SIZE:
+ g_value_init (value, G_TYPE_ULONG);
+ g_value_set_ulong (value, map->size);
+ break;
+
+ case MAPS_RSS:
+ g_value_init (value, G_TYPE_ULONG);
+ g_value_set_ulong (value, map->rss);
+ break;
+
+ case MAPS_DIRTY:
+ g_value_init (value, G_TYPE_ULONG);
+ g_value_set_ulong (value, map->dirty);
+ break;
+ }
+}
+
+static gboolean
+maps_store_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ Map *map = iter->user_data;
+
+ if (map->next == NULL)
+ return FALSE;
+
+ iter->user_data = map->next;
+ return TRUE;
+}
+
+static gboolean
+maps_store_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ return parent == NULL;
+}
+
+static gboolean
+maps_store_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return FALSE;
+}
+
+static gint
+maps_store_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return 0;
+}
+
+static gboolean
+maps_store_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
+{
+ MapsStore *self = (MapsStore *) tree_model;
+ Client *client = app_get_client (self->app);
+ Map *map;
+
+ if (parent != NULL)
+ return FALSE;
+
+ map = client->mappings;
+ while (--n && map != NULL)
+ map = map->next;
+ if (map == NULL)
+ return FALSE;
+
+ iter->user_data = map;
+ iter->stamp = 1;
+ return TRUE;
+}
+
+static gboolean
+maps_store_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ return FALSE;
+}
+
+static void
+maps_store_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = maps_store_get_flags;
+ iface->get_n_columns = maps_store_get_n_columns;
+ iface->get_column_type = maps_store_get_column_type;
+ iface->get_iter = maps_store_get_iter;
+ iface->get_path = maps_store_get_path;
+ iface->get_value = maps_store_get_value;
+ iface->iter_next = maps_store_iter_next;
+ iface->iter_children = maps_store_iter_children;
+ iface->iter_has_child = maps_store_iter_has_child;
+ iface->iter_n_children = maps_store_iter_n_children;
+ iface->iter_nth_child = maps_store_iter_nth_child;
+ iface->iter_parent = maps_store_iter_parent;
+}
+
+static void
+maps_store_init (MapsStore *self)
+{
+}
+
+void
+maps_store_update (MapsStore *self)
+{
+ Client *client = app_get_client (self->app);
+ glibtop_proc_map procmap;
+ glibtop_map_entry *maps;
+ Map *map;
+ guint n;
+
+ while (self->max_path--) {
+ GtkTreePath *path;
+
+ path = gtk_tree_path_new_from_indices (self->max_path, -1);
+ gtk_tree_model_row_deleted ((GtkTreeModel *) self, path);
+ gtk_tree_path_free (path);
+ }
+
+ maps = glibtop_get_proc_map (&procmap, (pid_t) client->pid);
+ for (n = 0; n < procmap.number; n++) {
+ for (map = client->mappings; map != NULL; map = map->next) {
+ if ((gulong) map->addr == maps[n].start) {
+ if (map->filename == NULL) {
+ if (maps[n].flags & (1L << GLIBTOP_MAP_ENTRY_FILENAME)) {
+ map->filename = client_add_string (client,
+ maps[n].filename);
+ } else
+ map->filename = "???";
+
+ map->perm = maps[n].perm;
+ }
+ map->rss = maps[n].rss;
+ map->dirty = maps[n].private_dirty;
+ break;
+ }
+ }
+ }
+ g_free (maps);
+
+ self->max_path = 0;
+ for (map = client->mappings; map != NULL; map = map->next) {
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ path = gtk_tree_path_new_from_indices (self->max_path, -1);
+ iter.stamp = 1;
+ iter.user_data = map;
+ gtk_tree_model_row_inserted ((GtkTreeModel *) self, path, &iter);
+ gtk_tree_path_free (path);
+ map->index = self->max_path++;
+ }
+}
+
+GtkTreeModel *
+maps_store_new (App *app)
+{
+ MapsStore *self;
+
+ self = g_object_new (maps_store_get_type (), NULL);
+ self->app = app;
+
+ return (GtkTreeModel *) self;
+}