main.c: Add old default to the skip funcs, add command line option
[memprof.git] / src / detailwin.c
blob11dec9d06a10683812c265b664360ebb6f3c7e41
1 /* -*- mode: C; c-file-style: "linux" -*- */
3 /* MemProf -- memory profiler and leak detector
4 * Copyright 2006 Carsten Haitzler
5 * Copyright 2009 Holger Hans Peter Freyther
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 /*====*/
23 #define _GNU_SOURCE
25 #include "config.h"
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
33 #include <regex.h>
34 #include <signal.h>
35 #include <sys/wait.h>
38 #include <glade/glade.h>
39 #include <gtk/gtk.h>
41 #include "gui.h"
42 #include "memprof.h"
44 static void
45 dw_draw_memstats(ProcessWindow *pwin)
47 GtkWidget *widget;
48 GdkPixmap *pixmap;
49 gint64 i, j, x, y, w, h, hh;
51 widget = pwin->time_graph;
52 w = widget->allocation.width;
53 h = widget->allocation.height;
54 if (!widget->window) return;
55 pixmap = gdk_pixmap_new(widget->window, w, h, -1);
56 gdk_draw_rectangle(pixmap,
57 widget->style->base_gc[GTK_STATE_NORMAL],
58 TRUE,
59 0, 0, w, h);
60 for (i = 0; i < MEMSTATS; i++)
62 x = w - i;
63 if (x < 0) break;
64 if (pwin->usage_high > 0)
65 hh = (h * pwin->memstats[i][1]) / pwin->usage_high;
66 else
67 hh = 0;
68 y = h - hh;
69 gdk_draw_rectangle(pixmap,
70 widget->style->base_gc[GTK_STATE_SELECTED],
71 TRUE,
72 x, y, 1, hh);
73 if (pwin->usage_high > 0)
74 hh = (h * pwin->memstats[i][0]) / pwin->usage_high;
75 else
76 hh = 0;
77 y = h - hh;
78 gdk_draw_rectangle(pixmap,
79 widget->style->text_gc[GTK_STATE_NORMAL],
80 TRUE,
81 x, y, 1, hh);
83 if (pwin->usage_high > 0)
85 GdkGC *gc;
87 gc = gdk_gc_new(pixmap);
88 gdk_gc_copy(gc, widget->style->dark_gc[GTK_STATE_NORMAL]);
89 gdk_gc_set_line_attributes(gc, 0, GDK_LINE_ON_OFF_DASH,
90 GDK_CAP_BUTT, GDK_JOIN_MITER);
91 for (j = 0, i = 0; i < pwin->usage_high; i += (256 * 1024), j++)
93 if (j > 3) j = 0;
94 y = h - ((i * h) / pwin->usage_high);
95 if (j == 0)
96 gdk_draw_line(pixmap, widget->style->dark_gc[GTK_STATE_NORMAL],
97 0, y, w, y);
98 else
99 gdk_draw_line(pixmap, gc,
100 0, y, w, y);
102 gdk_gc_unref(gc);
104 gdk_draw_pixmap(widget->window,
105 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
106 pixmap, 0, 0, 0, 0, w, h);
107 gdk_pixmap_unref(pixmap);
110 typedef struct _Mem
112 GtkWidget *widget;
113 GdkPixmap *pixmap;
114 guint w, h, bpp;
115 gulong mtotal;
116 GList *regs;
117 } Mem;
119 typedef struct _MemReg
121 void *start;
122 unsigned long size;
123 int y, h;
124 } MemReg;
126 static void
127 dw_draw_memmap_foreach(gpointer key, gpointer value, gpointer data)
129 Mem *mem;
130 Block *block;
131 guint x, y, w, i;
132 GdkPixmap *pixmap;
133 GdkGC *gc;
134 gulong addr;
135 guint bpp, memw;
136 GList *l;
137 MemReg *reg;
140 mem = data;
141 block = value;
142 bpp = mem->bpp;
143 addr = (gulong)block->addr;
144 for (i = 0, l = mem->regs; l; l = l->next, i++)
146 reg = l->data;
147 if ((addr >= (gulong)reg->start) &&
148 (addr < (gulong)(reg->start + reg->size)))
149 break;
150 reg = NULL;
152 if (!reg) return;
153 addr = addr - (gulong)reg->start;
154 w = (gulong)(addr + block->size + (bpp / 2)) / bpp;
155 x = (gulong)(addr) / bpp;
156 w -= x;
157 memw = mem->w;
158 y = reg->y + (x / memw);
159 x -= (y * memw);
160 pixmap = mem->pixmap;
161 if (i & 0x1)
162 gc = mem->widget->style->fg_gc[GTK_STATE_PRELIGHT];
163 else
164 gc = mem->widget->style->fg_gc[GTK_STATE_NORMAL];
165 gdk_draw_rectangle(pixmap, gc, TRUE, x, y, w, 1);
166 if ((x + w) > mem->w)
167 gdk_draw_rectangle(pixmap, gc, TRUE, 0, y + 1, w - (memw - x), 1);
170 static void
171 dw_draw_memmap(ProcessWindow *pwin)
173 GtkWidget *widget;
174 GdkPixmap *pixmap;
175 guint w, h, y, bpl, i;
176 Mem mem;
177 GList *l;
179 widget = pwin->mem_map;
180 w = widget->allocation.width;
181 h = widget->allocation.height;
182 if (!widget->window) return;
183 pixmap = gdk_pixmap_new(widget->window, w, h, -1);
184 gdk_draw_rectangle(pixmap,
185 widget->style->base_gc[GTK_STATE_NORMAL],
186 TRUE,
187 0, 0, w, h);
188 mem.regs = NULL;
189 mem.widget = widget;
190 mem.pixmap = pixmap;
191 mem.w = w;
192 mem.h = h;
193 mem.mtotal = 0;
195 gchar buffer[1024];
196 FILE *in;
197 gchar perms[26];
198 gchar file[256];
199 gulong start, end;
200 guint major, minor, inode;
202 snprintf(buffer, 1023, "/proc/%d/maps", pwin->process->pid);
204 in = fopen(buffer, "r");
205 if (!in)
207 g_warning("Failed to open: '%s'", buffer);
208 return;
211 while (fgets(buffer, 1023, in))
213 file[0] = 0;
214 int count = sscanf(buffer, "%lx-%lx %15s %*x %u:%u %u %255s",
215 &start, &end, perms, &major, &minor, &inode,
216 file);
217 if (count >= 5)
219 if ((!strcmp(perms, "rw-p")) && (inode == 0))
221 MemReg *reg;
223 reg = g_malloc(sizeof(MemReg));
224 reg->start = GSIZE_TO_POINTER(start);
225 reg->size = end - start;
226 mem.mtotal += reg->size;
227 mem.regs = g_list_append(mem.regs, reg);
231 fclose (in);
233 bpl = (mem.mtotal + h - 1) / h;
234 y = 0;
235 for (i = 0, l = mem.regs; l; l = l->next, i++)
237 MemReg *reg;
239 reg = l->data;
240 reg->h = ((reg->size * h) + bpl - 1) / mem.mtotal;
241 reg->y = y;
242 y += reg->h;
243 if (i & 0x1)
244 gdk_draw_rectangle(pixmap,
245 widget->style->base_gc[GTK_STATE_INSENSITIVE],
246 TRUE,
247 0, reg->y, w, reg->h);
249 mem.bpp = (bpl + w - 1) / w;
250 if (mem.bpp < 1) mem.bpp = 1;
252 g_hash_table_foreach(pwin->process->block_table,
253 dw_draw_memmap_foreach,
254 &mem);
256 for (l = mem.regs; l; l = l->next) g_free(l->data);
257 g_list_free(mem.regs);
259 gdk_draw_pixmap(widget->window,
260 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
261 pixmap, 0, 0, 0, 0, w, h);
262 gdk_pixmap_unref(pixmap);
265 gboolean
266 time_graph_expose_event(GtkWidget *widget, GdkEventExpose *event, ProcessWindow *pwin)
268 if (!pwin->process) return FALSE;
269 dw_draw_memstats(pwin);
270 return FALSE;
273 gboolean
274 mem_map_expose_event(GtkWidget *widget, GdkEventExpose *event, ProcessWindow *pwin)
276 if (!pwin->process) return FALSE;
277 dw_draw_memmap(pwin);
278 return FALSE;
281 void
282 dw_update(ProcessWindow *pwin)
284 guint i;
285 if (!pwin->process) return;
286 for (i = MEMSTATS - 1; i > 0; i--)
288 pwin->memstats[i][0] = pwin->memstats[i - 1][0];
289 pwin->memstats[i][1] = pwin->memstats[i - 1][1];
291 pwin->memstats[0][0] = pwin->process->bytes_used;
292 pwin->memstats[0][1] = pwin->usage_high;
293 dw_draw_memstats(pwin);
294 dw_draw_memmap(pwin);