diff options
Diffstat (limited to 'src/maps-store.c')
-rw-r--r-- | src/maps-store.c | 321 |
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; +} |