main.c
来自「memprof source code, linux」· C语言 代码 · 共 1,816 行 · 第 1/4 页
C
1,816 行
/* -*- mode: C; c-file-style: "linux" -*- *//* MemProf -- memory profiler and leak detector * Copyright 1999, 2000, 2001, Red Hat, Inc. * Copyright 2002, Kristian Rietveld * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//*====*/#define _GNU_SOURCE#include "config.h"#include <stdarg.h>#include <stdio.h>#include <errno.h>#include <sys/wait.h>#include <signal.h>#include <glade/glade.h>#include <gnome.h>#include <gconf/gconf-client.h>#include <regex.h>#include "leakdetect.h"#include "gui.h"#include "memprof.h"#include "process.h"#include "profile.h"#include "server.h"struct _ProcessWindow { MPProcess *process; Profile *profile; GSList *leaks; GtkWidget *main_window; GtkWidget *main_notebook; GtkWidget *n_allocations_label; GtkWidget *bytes_per_label; GtkWidget *total_bytes_label; GtkWidget *profile_func_clist; GtkWidget *profile_caller_clist; GtkWidget *profile_child_clist; GtkWidget *leak_block_clist; GtkWidget *leak_stack_clist; GtkWidget *usage_max_label; GtkWidget *usage_canvas; guint usage_max; guint usage_high; guint usage_leaked; GnomeCanvasItem *usage_frame; GnomeCanvasItem *usage_current_bar; GnomeCanvasItem *usage_high_bar; GnomeCanvasItem *usage_leak_bar; guint status_update_timeout; gboolean follow_fork : 1; gboolean follow_exec : 1;};char *glade_file;MPServer *global_server;static ProcessWindow *process_window_new (void);static void process_window_destroy (ProcessWindow *pwin);static void process_window_reset (ProcessWindow *pwin);static GSList *skip_funcs = NULL;static GSList *skip_regexes = NULL;static gboolean default_follow_fork = FALSE;static gboolean default_follow_exec = FALSE;char *stack_command = NULL;GSList *process_windows = NULL;static GladeXML *pref_dialog_xml = NULL; /* We save this around, so we can prevent multiple property boxes from being opened at once *//************************************************************ * Status Page ************************************************************/static voidupdate_bars (ProcessWindow *pwin){ gint bytes_used; if (pwin->process) bytes_used = pwin->process->bytes_used; else bytes_used = 0; gnome_canvas_item_set (pwin->usage_current_bar, "x2", ((double)pwin->usage_canvas->allocation.width * (double)bytes_used / pwin->usage_max), NULL); gnome_canvas_item_set (pwin->usage_high_bar, "x2", ((double)pwin->usage_canvas->allocation.width * (double)pwin->usage_high / pwin->usage_max), NULL); gnome_canvas_item_set (pwin->usage_leak_bar, "x2", ((double)pwin->usage_canvas->allocation.width * (double)pwin->usage_leaked / pwin->usage_max), NULL); printf("======= max= %ld, use_high = %ld ============\n", pwin->usage_max, pwin->usage_high );}static gbooleanupdate_status (gpointer data){ char *tmp; ProcessWindow *pwin = (ProcessWindow *)data; tmp = g_strdup_printf ("%d", pwin->process->bytes_used); gtk_label_set_text (GTK_LABEL (pwin->total_bytes_label), tmp); g_free (tmp); tmp = g_strdup_printf ("%d", pwin->process->n_allocations); gtk_label_set_text (GTK_LABEL (pwin->n_allocations_label), tmp); g_free (tmp); if (pwin->process->n_allocations == 0) tmp = g_strdup("-"); else tmp = g_strdup_printf ("%.2f", (double)pwin->process->bytes_used / pwin->process->n_allocations); gtk_label_set_text (GTK_LABEL (pwin->bytes_per_label), tmp); g_free (tmp); if (pwin->process->bytes_used > pwin->usage_max) { while ((pwin->process->bytes_used > pwin->usage_max)) pwin->usage_max *= 2; tmp = g_strdup_printf ("%dk", pwin->usage_max / 1024); gtk_label_set_text (GTK_LABEL (pwin->usage_max_label), tmp); g_free (tmp); } pwin->usage_high = MAX (pwin->process->bytes_used, pwin->usage_high); update_bars (pwin); return TRUE;}static voidusage_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation, ProcessWindow *pwin){ gnome_canvas_set_scroll_region (GNOME_CANVAS (widget), 0, 0, allocation->width, allocation->height); gnome_canvas_item_set (pwin->usage_frame, "x2", (double)allocation->width - 1, "y2", (double)allocation->height - 1, NULL); gnome_canvas_item_set (pwin->usage_current_bar, "y2", (double)allocation->height - 1, NULL); gnome_canvas_item_set (pwin->usage_high_bar, "y2", (double)allocation->height - 1, NULL); gnome_canvas_item_set (pwin->usage_leak_bar, "y2", (double)allocation->height - 1, NULL);} /************************************************************ * GUI for profiles ************************************************************/static gintprofile_compare_name (GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2){ ProfileFunc *func1 = ((const GtkCListRow *)ptr1)->data; ProfileFunc *func2 = ((const GtkCListRow *)ptr2)->data; return strcmp (func1->symbol->name, func2->symbol->name);} static gintprofile_compare_self (GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2){ ProfileFunc *func1 = ((const GtkCListRow *)ptr1)->data; ProfileFunc *func2 = ((const GtkCListRow *)ptr2)->data; return func1->self < func2->self ? 1 : (func1->self > func2->self ? -1 : 0);} static gintprofile_compare_total (GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2){ ProfileFunc *func1 = ((const GtkCListRow *)ptr1)->data; ProfileFunc *func2 = ((const GtkCListRow *)ptr2)->data; return func1->total < func2->total ? 1 : (func1->total > func2->total ? -1 : 0);}static voidprofile_func_click_column (GtkWidget *clist, gint column){ static const GtkCListCompareFunc compare_funcs[] = { profile_compare_name, profile_compare_self, profile_compare_total }; g_return_if_fail (column >= 0 && column < 3); gtk_clist_set_compare_func (GTK_CLIST (clist), compare_funcs[column]); gtk_clist_sort (GTK_CLIST (clist));} static voidprofile_fill_ref_clist (GtkWidget *clist, GList *refs){ gint row; GList *tmp_list; gtk_clist_clear (GTK_CLIST (clist)); tmp_list = refs; while (tmp_list) { char *data[2]; char buf[32]; ProfileFuncRef *ref = tmp_list->data; data[0] = ref->function->symbol->name; g_snprintf(buf, 32, "%d", ref->bytes); data[1] = buf; row = gtk_clist_append (GTK_CLIST (clist), data); gtk_clist_set_row_data (GTK_CLIST (clist), row, ref); tmp_list = tmp_list->next; }}static voidprofile_func_select_row (GtkWidget *widget, gint row, gint column, GdkEvent *event, ProcessWindow *pwin){ ProfileFunc *function = gtk_clist_get_row_data (GTK_CLIST (widget), row); if (function == NULL) return; profile_fill_ref_clist (pwin->profile_child_clist, function->children); profile_fill_ref_clist (pwin->profile_caller_clist, function->inherited);}static gbooleanprofile_ref_button_press (GtkWidget *widget, GdkEventButton *event, ProcessWindow *pwin){ if (event->window == GTK_CLIST (widget)->clist_window && event->type == GDK_2BUTTON_PRESS) { int my_row, function_row; if (!gtk_clist_get_selection_info (GTK_CLIST (widget), event->x, event->y, &my_row, NULL)) return FALSE; if (my_row != -1) { ProfileFuncRef *ref; ref = gtk_clist_get_row_data (GTK_CLIST (widget), my_row); function_row = gtk_clist_find_row_from_data (GTK_CLIST (pwin->profile_func_clist), ref->function); if (function_row != -1) { gtk_clist_select_row (GTK_CLIST (pwin->profile_func_clist), function_row, 0); gtk_clist_moveto (GTK_CLIST (pwin->profile_func_clist), function_row, -1, 0.5, 0.0); } } g_signal_stop_emission_by_name (G_OBJECT (widget), "button_press_event"); return TRUE; } return FALSE;}static voidprofile_fill (ProcessWindow *pwin, GtkCList *clist){ int i, row; gtk_clist_clear (clist); for (i=0; i<pwin->profile->n_functions; i++) { ProfileFunc *function = pwin->profile->functions[i]; char *data[3]; char buf[32]; data[0] = function->symbol->name; g_snprintf(buf, 32, "%u", function->self); data[1] = g_strdup (buf); g_snprintf(buf, 32, "%u", function->total); data[2] = g_strdup (buf); row = gtk_clist_append (clist, data); g_free (data[1]); g_free (data[2]); gtk_clist_set_row_data (clist, row, function); } if (clist->rows > 0) profile_func_select_row (GTK_WIDGET (clist), 0, 0, NULL, pwin);}/************************************************************ * GUI for leak detection ************************************************************/static voidleak_block_select_row (GtkWidget *widget, gint row, gint column, GdkEvent *event, ProcessWindow *pwin){ Block *block = gtk_clist_get_row_data (GTK_CLIST (widget), row); StackElement *stack; if (block == NULL) return; gtk_clist_clear (GTK_CLIST (pwin->leak_stack_clist)); for (stack = block->stack; !STACK_ELEMENT_IS_ROOT (stack); stack = stack->parent) { char *data[3]; char buf[32]; const char *filename; char *functionname; unsigned int line; if (!process_find_line (pwin->process, stack->address, &filename, &functionname, &line)) { /* 0x3f == '?' -- suppress trigraph warnings */ functionname = g_strdup ("(\x3f\x3f\x3f)"); filename = "(\x3f\x3f\x3f)"; line = 0; } data[0] = functionname; g_snprintf(buf, 32, "%d", line); data[1] = buf; data[2] = (char *)filename; gtk_clist_append (GTK_CLIST (pwin->leak_stack_clist), data); free (data[0]); } }static voidleaks_fill (ProcessWindow *pwin, GtkCList *clist){ gint row; GSList *tmp_list; gtk_clist_clear (clist); tmp_list = pwin->leaks; while (tmp_list) { char *data[3]; char buf[32]; const char *filename; char *functionname = NULL; unsigned int line; Block *block = tmp_list->data; StackElement *stack; for (stack = block->stack; !STACK_ELEMENT_IS_ROOT (stack); stack = stack->parent) { if (process_find_line (pwin->process, stack->address, &filename, &functionname, &line)) { GSList *tmp_list; if (!functionname) continue; for (tmp_list = skip_funcs; tmp_list != NULL; tmp_list = tmp_list->next) { if (!strcmp (functionname, tmp_list->data)) { free (functionname); functionname = NULL; break; } } if (!functionname) continue; for (tmp_list = skip_regexes; tmp_list != NULL; tmp_list = tmp_list->next) { regex_t regex; regcomp (®ex, tmp_list->data, 0); if (!regexec (®ex, functionname, 0, NULL, 0)) { free (functionname); functionname = NULL; regfree (®ex); break; } regfree (®ex);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?