diff options
33 files changed, 43 insertions, 4315 deletions
@@ -1,3 +1,40 @@ +2000-09-29 Ramiro Estrugo <ramiro@eazel.com> + + * Makefile.am: + * configure.in: + * HACKING: + * tools/.cvsignore: + * tools/Makefile.am: + * tools/README: + * tools/leak-checker/.cvsignore: + * tools/leak-checker/Makefile.am: + * tools/leak-checker/nautilus-leak-checker-stubs.h: + * tools/leak-checker/nautilus-leak-checker.c: + * tools/leak-checker/nautilus-leak-checker.h: + * tools/leak-checker/nautilus-leak-hash-table.c: + * tools/leak-checker/nautilus-leak-hash-table.h: + * tools/leak-checker/nautilus-leak-symbol-lookup.c: + * tools/leak-checker/nautilus-leak-symbol-lookup.h: + * tools/profiler/Makefile: + * tools/profiler/funcsummary.C: + * tools/profiler/funcsummary.h: + * tools/profiler/machine-profile.S: + * tools/profiler/machine-profile.h: + * tools/profiler/machine-profileP.h: + * tools/profiler/nautilus-leak-symbol-lookup.C: + * tools/profiler/nautilus-leak-symbol-lookup.h: + * tools/profiler/profile.C: + * tools/profiler/profile.h: + * tools/profiler/profileP.h: + * tools/profiler/profiledata.C: + * tools/profiler/profiledata.h: + * tools/profiler/symbol-table.h: + * tools/profiler/test.cpp: + * tools/profiler/totaltime.C: + * tools/profiler/totaltime.h: + Moved the leak-checker and profiler tools to their own gnome cvs + module. + 2000-09-29 Robey Pointer <robey@eazel.com> * nautilus-installer/src/bootstrap-background.xpm: @@ -32,6 +32,9 @@ read other relevant documents in the docs directory too. 2: Using the leak checker ========================= +The leak checker is built as part of the eazel-tools gnome module. +Build that first before you continue. + Nautilus is set up to use the libleakcheck.so leak checking library. To use it, run Nautilus with LD_PRELOAD set to the path to the installed libleakcheck.so library. For example, if you are using a diff --git a/Makefile.am b/Makefile.am index 3549bbfe7..272198898 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,6 @@ SUBDIRS = \ po \ src \ test \ - tools \ $(NULL) EXTRA_DIST= \ diff --git a/configure.in b/configure.in index 08069e3cc..ba7c6be97 100644 --- a/configure.in +++ b/configure.in @@ -604,8 +604,6 @@ components/loser/sidebar/Makefile components/tree/Makefile helper-utilities/Makefile helper-utilities/authenticate/Makefile -tools/Makefile -tools/leak-checker/Makefile po/Makefile.in intl/Makefile test/Makefile diff --git a/tools/.cvsignore b/tools/.cvsignore deleted file mode 100644 index 282522db0..000000000 --- a/tools/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -Makefile.in diff --git a/tools/Makefile.am b/tools/Makefile.am deleted file mode 100644 index 24696f70d..000000000 --- a/tools/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -NULL= - -SUBDIRS = \ - leak-checker \ - $(NULL) diff --git a/tools/README b/tools/README new file mode 100644 index 000000000..addc4410b --- /dev/null +++ b/tools/README @@ -0,0 +1,3 @@ +The leak-checker and profiler have been moved to their own gnome cvs +module: eazel-tools. Please look there. + diff --git a/tools/leak-checker/.cvsignore b/tools/leak-checker/.cvsignore deleted file mode 100644 index 3dda72986..000000000 --- a/tools/leak-checker/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile.in -Makefile diff --git a/tools/leak-checker/Makefile.am b/tools/leak-checker/Makefile.am deleted file mode 100644 index 7ca280253..000000000 --- a/tools/leak-checker/Makefile.am +++ /dev/null @@ -1,38 +0,0 @@ -NULL= - -INCLUDES =\ - -I$(top_srcdir) \ - -I$(top_builddir) \ - -I$(top_builddir)/libnautilus \ - $(BONOBO_CFLAGS) \ - $(OAF_CFLAGS) \ - $(GCONF_CFLAGS) \ - $(GNOMEUI_CFLAGS) \ - $(VFS_CFLAGS) \ - $(XML_CFLAGS) \ - -DVERSION="\"$(VERSION)\"" \ - -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ - $(NULL) - -# for now just hardcode a plain old link line, someday someone can -#figure out what the magic password is to make libtool do this cleanly - -all: libleakcheck.so -CLEANFILES += libleakcheck.so - -libleakcheck.so: nautilus-leak-checker.c nautilus-leak-hash-table.c nautilus-leak-symbol-lookup.c - gcc $(srcdir)/nautilus-leak-checker.c $(srcdir)/nautilus-leak-hash-table.c \ - $(srcdir)/nautilus-leak-symbol-lookup.c \ - -Wall -o $@ -shared $(GLIB_CFLAGS) $(GLIB_LIBS) -lpthread -ldl -Wl,-Bstatic -lbfd -liberty -Wl,-Bdynamic - -# to include them in "make dist" -EXTRA_DIST = nautilus-leak-checker.c nautilus-leak-hash-table.c nautilus-leak-symbol-lookup.c \ - nautilus-leak-checker-stubs.h nautilus-leak-hash-table.h nautilus-leak-checker.h nautilus-leak-symbol-lookup.h - -leakcheck_DATA = libleakcheck.so -leakcheckdir= $(DESTDIR)$(libdir) - -leakchecktest: nautilus-leak-checker.c nautilus-leak-hash-table.c nautilus-leak-symbol-lookup.c - gcc $(srcdir)/nautilus-leak-checker.c $(srcdir)/nautilus-leak-hash-table.c \ - $(srcdir)/nautilus-leak-symbol-lookup.c \ - -Wall -o $@ -DLEAK_CHECK_TESTING $(GLIB_CFLAGS) $(GLIB_LIBS) -lpthread -ldl -Wl,-Bstatic -lbfd -liberty -Wl,-Bdynamic diff --git a/tools/leak-checker/nautilus-leak-checker-stubs.h b/tools/leak-checker/nautilus-leak-checker-stubs.h deleted file mode 100644 index 8f175dfda..000000000 --- a/tools/leak-checker/nautilus-leak-checker-stubs.h +++ /dev/null @@ -1,78 +0,0 @@ -/* nautilus-leak-checker-stubs.h - simple leak checking library - Virtual File System Library - - Copyright (C) 2000 Eazel - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Pavel Cisler <pavel@eazel.com> - based on MemProf by Owen Taylor, <otaylor@redhat.com> -*/ - -#ifndef LEAK_CHECKER_STUBS_H -#define LEAK_CHECKER_STUBS_H - - -extern void *(* real_malloc) (size_t size); -extern void *(* real_memalign) (size_t boundary, size_t size); -extern void *(* real_realloc) (void *ptr, size_t size); -extern void *(* real_calloc) (void *ptr, size_t size); -extern void (*real_free) (void *ptr); - - -void *__libc_malloc (size_t size); -void *__libc_memalign (size_t boundary, size_t size); -void *__libc_calloc (size_t count, size_t size); -void *__libc_realloc (void *ptr, size_t size); -void __libc_free (void *ptr); - -/* Records the context of an allocation. - * We could add pid, allocation time, etc. if needed. - */ -typedef struct { - /* pointer returned by malloc/realloc */ - void *block; - - /* allocated size */ - size_t size; - - /* NULL-terminated array of return addresses */ - void **stack_crawl; -} NautilusLeakAllocationRecord; - -void nautilus_leak_allocation_record_finalize - (NautilusLeakAllocationRecord *record); -void nautilus_leak_allocation_record_free (NautilusLeakAllocationRecord *record); -void nautilus_leak_allocation_record_init (NautilusLeakAllocationRecord *record, - void *block, - size_t initial_size, - void **stack_crawl, - int max_depth); -NautilusLeakAllocationRecord *nautilus_leak_allocation_record_copy - (const NautilusLeakAllocationRecord *record); - -int nautilus_leak_stack_crawl_compare (void **stack_crawl1, - void **stack_crawl2, - int levels); - -/* Hash table entry. */ -struct NautilusHashEntry { - int next; - NautilusLeakAllocationRecord data; -}; - - -#endif
\ No newline at end of file diff --git a/tools/leak-checker/nautilus-leak-checker.c b/tools/leak-checker/nautilus-leak-checker.c deleted file mode 100644 index 8cebf520e..000000000 --- a/tools/leak-checker/nautilus-leak-checker.c +++ /dev/null @@ -1,1077 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ - -/* nautilus-leak-checker.c - simple leak checking library - Virtual File System Library - - Copyright (C) 2000 Eazel - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Pavel Cisler <pavel@eazel.com> - based on MemProf by Owen Taylor, <otaylor@redhat.com> -*/ - -#include "nautilus-leak-checker.h" -/* included first, defines following switch*/ - -#if LEAK_CHECKER - -#include <malloc.h> -#include <dlfcn.h> -#include <malloc.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "nautilus-leak-checker-stubs.h" -#include "nautilus-leak-hash-table.h" -#include "nautilus-leak-symbol-lookup.h" - -/* this is the maximum number of stack crawl levels we can capture */ -enum { - TRACE_ARRAY_MAX = 512 -}; - -static volatile gboolean nautilus_leak_hooks_initialized; -static volatile gboolean nautilus_leak_initializing_hooks; -static volatile gboolean nautilus_leak_check_leaks; - -void *(* real_malloc) (size_t size); -void *(* real_memalign) (size_t boundary, size_t size); -void *(* real_realloc) (void *ptr, size_t size); -void *(* real_calloc) (void *ptr, size_t size); -void (* real_free) (void *ptr); -int (* real_start_main) (int (*main) (int, char **, char **), int argc, - char **argv, void (*init) (void), void (*fini) (void), - void (*rtld_fini) (void), void *stack_end); - -/* We clean up on exit, but not all libraries do so. - * For ones that don't, list tell-tale stack crawl function names. - */ -static const char * const known_leakers[] = { - "ConfigServer_remove_listener", /* gconf */ - "XSupportsLocale", - "__bindtextdomain", - "__pthread_initialize_manager", - "__textdomain", - "_gnome_config_get_bool_with_default", - "_nl_find_domain", - "bonobo_init", - "client_parse_func", /* gnome-libs */ - "client_save_yourself_callback", /* gnome-libs */ - "g_18n_get_language_list", - "g_data_initialize", - "g_data_set_internal", /* no easy way to make it not cache blocks */ - "g_dataset_id_set_data_full", /* no easy way to make it not cache blocks */ - "g_get_any_init", - "g_hash_node_new", - "g_log_set_handler", - "g_main_add_poll_unlocked", /* no easy way to make it not cache blocks */ - "g_quark_new", - "g_thread_init", - "gconf_postinit", - "gdk_atom_intern", - "gdk_pixbuf_load_module", - "gnome_add_gtk_arg_callback", - "gnome_client_init", - "gnome_i18n_get_language_list", - "gnome_init_cb", - "gnome_stock_pixmap", - "gnome_stock_pixmap_change", - "gnome_stock_pixmap_register", - "gnome_stock_pixmap_widget", - "gnome_vfs_add_module_to_hash_table", - "gnome_vfs_application_registry_init", - "gnome_vfs_backend_loadinit", - "gnome_vfs_i18n_get_language_list", - "gnome_vfs_init", - "gnomelib_init", - "gtk_init", - "gtk_item_factory_add_foreign", - "gtk_rc_get_style", - "gtk_rc_init", - "gtk_rc_parse", - "gtk_rc_style_init", - "gtk_type_class_init", - "gtk_type_init", - "gtk_type_register_enum", - "gtk_type_register_flags", - "gtk_type_unique", - "gtk_widget_queue_draw_data", /* no easy way to make it not cache blocks */ - "load_module", - "mbtowc", - "oaf_existing_set", - "oaf_init", - "pthread_initialize", - "register_client", /* gconf */ - "setlocale", - "stock_pixmaps", /* gnome-libs */ - "try_to_contact_server", /* gconf */ - "tzset_internal", -}; - -static const char *app_path; - -void -nautilus_leak_allocation_record_init (NautilusLeakAllocationRecord *record, - void *block, size_t initial_size, void **stack_crawl, int max_depth) -{ - int stack_depth, index; - - record->block = block; - record->size = initial_size; - - for (index = 0; index < max_depth; index++) { - if (stack_crawl[index] == NULL) - break; - } - - stack_depth = index; - - /* call real_malloc to avoid recursion and messing up results */ - record->stack_crawl = real_malloc ((stack_depth + 1) * sizeof(void *)); - memcpy (record->stack_crawl, stack_crawl, stack_depth * sizeof(void *)); - record->stack_crawl[stack_depth] = NULL; -} - -NautilusLeakAllocationRecord * -nautilus_leak_allocation_record_copy (const NautilusLeakAllocationRecord *record) -{ - int stack_depth, index; - NautilusLeakAllocationRecord *result; - - result = real_malloc (sizeof(*result)); - - result->block = record->block; - result->size = record->size; - - for (index = 0; ; index++) { - if (record->stack_crawl[index] == NULL) - break; - } - stack_depth = index; - result->stack_crawl = real_malloc ((stack_depth + 1) * sizeof(void *)); - memcpy (result->stack_crawl, record->stack_crawl, (stack_depth + 1) * sizeof(void *)); - - return result; -} - -void -nautilus_leak_allocation_record_finalize (NautilusLeakAllocationRecord *record) -{ - /* call real_free to avoid recursion and messing up results */ - real_free (record->stack_crawl); -} - -void -nautilus_leak_allocation_record_free (NautilusLeakAllocationRecord *record) -{ - /* call real_free to avoid recursion and messing up results */ - real_free (record->stack_crawl); - real_free (record); -} - -/* return a strcmp-like result to be used in sort funcitons */ -int -nautilus_leak_stack_crawl_compare (void **stack_crawl1, void **stack_crawl2, int levels) -{ - int index; - for (index = 0; index < levels; index++) { - if (stack_crawl1 [index] == NULL && stack_crawl2 [index] == NULL) { - return 0; - } - - if (stack_crawl1 [index] < stack_crawl2 [index]) { - return -1; - } else if (stack_crawl1 [index] > stack_crawl2 [index]) { - return 1; - } - } - - return 0; -} - -static void -nautilus_leak_initialize (void) -{ - /* Locate the original malloc calls. The dlsym calls - * will allocate memory when doing lookups. We use a special - * trick to deal with the fact that real_malloc is not set up - * yet while we are doing the first dlsym -- see malloc. - */ - real_malloc = dlsym (RTLD_NEXT, "__libc_malloc"); - real_realloc = dlsym (RTLD_NEXT, "__libc_realloc"); - real_free = dlsym (RTLD_NEXT, "__libc_free"); - real_memalign = dlsym (RTLD_NEXT, "__libc_memalign"); - real_calloc = dlsym (RTLD_NEXT, "__libc_calloc"); - real_start_main = dlsym (RTLD_NEXT, "__libc_start_main"); - - nautilus_leak_hooks_initialized = TRUE; - nautilus_leak_check_leaks = TRUE; -} - -typedef struct StackFrame StackFrame; - -struct StackFrame { - StackFrame *next_frame; - void *return_address; - /* first argument is here */ -}; - -static void -get_stack_trace (void **trace_array, int trace_array_max) -{ - int index; - const StackFrame *stack_frame; - - /* point to the stack frame pointer, two words before the - * address of the first argument - */ - stack_frame = (const StackFrame *)((void **)&trace_array - 2); - - - /* Record stack frames; skip first two in the malloc calls. */ - for (index = -2; index < trace_array_max; index++) { - if (index >= 0) { - /* Return address is the next pointer after - * stack frame. - */ - trace_array [index] = stack_frame->return_address; - } - stack_frame = stack_frame->next_frame; - if (stack_frame == NULL) { - break; - } - } - if (index < trace_array_max) { - trace_array [index] = NULL; - } -} - -/* Figure out if one of the malloc calls is reentering itself. - * There seems no cleaner way to handle this -- we want to override - * malloc calls at the __libc_* level. - * The malloc hooks recurse when initializing themselves. - * When this happens we need a reliable way to tell that a recursion is - * underway so as to not record the corresponding malloc call twice - */ -static gboolean -detect_reentry (void *parent_caller) -{ - int count; - const StackFrame *stack_frame; - - stack_frame = (const StackFrame *)((void **)&parent_caller - 2); - stack_frame = stack_frame->next_frame; - - for (count = 0; count < 7; count++) { - /* See if we return address on the stack - * that is near the parent_caller -- the start address - * of the calling function. - * We are using two arbitrary numbers here - 5 should be a "deep enough" - * check to detect the recursion, 0x40 bytes should be a large enough distance - * from the start of the malloc call to the point where the old malloc call is - * being called. - * FIXME bugzilla.eazel.com 2467: - * The value 0x40 works well only with certain function sizes, optimization levels, - * etc. need a more robust way of doing this. One way might be adding stuffing into the - * __libc_* calls that is never executed but makes the funcitons longer. We could - * then up the value without the danger of hitting the next function - */ - if (stack_frame->return_address >= parent_caller - && stack_frame->return_address < (void *)((char *)parent_caller + 0x40)) { - /* printf("detected reentry at level %d\n", count); */ - return TRUE; - } - stack_frame = stack_frame->next_frame; - if (stack_frame == NULL) { - break; - } - } - return FALSE; -} - -static pthread_mutex_t nautilus_leak_hash_table_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; -static NautilusLeakHashTable *nautilus_leak_hash_table; - -static void -nautilus_leak_record_malloc (void *ptr, size_t size) -{ - void *trace_array [TRACE_ARRAY_MAX]; - NautilusHashEntry *element; - - /* printf("new block %p, %d\n", ptr, size); */ - - if (!nautilus_leak_check_leaks) - return; - - get_stack_trace (trace_array, TRACE_ARRAY_MAX); - - pthread_mutex_lock (&nautilus_leak_hash_table_mutex); - - if (nautilus_leak_hash_table == NULL) { - nautilus_leak_hash_table = nautilus_leak_hash_table_new (10 * 1024); - } - if (nautilus_leak_hash_table_find (nautilus_leak_hash_table, (gulong)ptr) != NULL) { - printf("*** block %p appears to already be allocated " - "- someone must have sneaked a free past us\n", ptr); - nautilus_leak_hash_table_remove (nautilus_leak_hash_table, (gulong)ptr); - } - /* insert a new item into the hash table, using the block address as the key */ - element = nautilus_leak_hash_table_add (nautilus_leak_hash_table, (gulong)ptr); - - /* fill out the new allocated element */ - nautilus_leak_allocation_record_init (&element->data, ptr, size, trace_array, TRACE_ARRAY_MAX); - - pthread_mutex_unlock (&nautilus_leak_hash_table_mutex); -} - -static void -nautilus_leak_record_realloc (void *old_ptr, void *new_ptr, size_t size) -{ - void *trace_array [TRACE_ARRAY_MAX]; - NautilusHashEntry *element; - - /* printf("reallocing block %p, %d was %p\n", new_ptr, size, old_ptr); */ - - if (!nautilus_leak_check_leaks) - return; - - get_stack_trace (trace_array, TRACE_ARRAY_MAX); - - pthread_mutex_lock (&nautilus_leak_hash_table_mutex); - - /* must have hash table by now */ - g_assert (nautilus_leak_hash_table != NULL); - /* must have seen the block already */ - element = nautilus_leak_hash_table_find (nautilus_leak_hash_table, (gulong)old_ptr); - if (element == NULL) { - printf("*** we haven't seen block %p yet " - "- someone must have sneaked a malloc past us\n", old_ptr); - } else { - nautilus_leak_hash_table_remove (nautilus_leak_hash_table, (gulong)old_ptr); - } - - /* shouldn't have this block yet */ - if (nautilus_leak_hash_table_find (nautilus_leak_hash_table, (gulong)new_ptr) != NULL) { - printf("*** block %p appears to already be allocated " - "- someone must have sneaked a free past us\n", new_ptr); - nautilus_leak_hash_table_remove (nautilus_leak_hash_table, (gulong)new_ptr); - } - - /* insert a new item into the hash table, using the block address as the key */ - element = nautilus_leak_hash_table_add (nautilus_leak_hash_table, (gulong)new_ptr); - - /* Fill out the new allocated element. - * This way the last call to relloc will be the stack crawl that shows up in the - * final balance. - */ - nautilus_leak_allocation_record_init (&element->data, new_ptr, size, trace_array, - TRACE_ARRAY_MAX); - - pthread_mutex_unlock (&nautilus_leak_hash_table_mutex); -} - -static void -nautilus_leak_record_free (void *ptr) -{ - NautilusHashEntry *element; - /* printf("freeing block %p\n", ptr); */ - if (!nautilus_leak_check_leaks) - return; - - pthread_mutex_lock (&nautilus_leak_hash_table_mutex); - - /* must have hash table by now */ - g_assert (nautilus_leak_hash_table != NULL); - /* must have seen the block already */ - element = nautilus_leak_hash_table_find (nautilus_leak_hash_table, (gulong)ptr); - if (element == NULL) { - printf("*** we haven't seen block %p yet " - "- someone must have sneaked a malloc past us\n", ptr); - } else { - nautilus_leak_hash_table_remove (nautilus_leak_hash_table, (gulong)ptr); - } - pthread_mutex_unlock (&nautilus_leak_hash_table_mutex); - -} - -static void -nautilus_leak_initialize_if_needed (void) -{ - if (nautilus_leak_hooks_initialized) - return; - - if (nautilus_leak_initializing_hooks) - /* guard against reentrancy */ - return; - - nautilus_leak_initializing_hooks = TRUE; - nautilus_leak_initialize (); - nautilus_leak_initializing_hooks = FALSE; -} - -/* we are overlaying the original __libc_malloc */ -enum { - STARTUP_FALLBACK_MEMORY_SIZE = 1024 -}; - -static int startup_fallback_memory_index = 0; -static char startup_fallback_memory [STARTUP_FALLBACK_MEMORY_SIZE]; - -/* If our malloc hook is not installed yet - for instance when we are being - * called from the initialize_if_needed routine. We have to fall back on - * returning a chunk of static memory to carry us through the initialization. - */ -static void * -allocate_temporary_fallback_memory (ssize_t size) -{ - void *result; - - /* align to natural word boundary */ - size = (size + sizeof(void *) - 1 ) & ~(sizeof(void *) - 1); - if (size + startup_fallback_memory_index - > STARTUP_FALLBACK_MEMORY_SIZE) { - g_warning ("trying to allocate to much space during startup"); - return NULL; - } - result = &startup_fallback_memory [startup_fallback_memory_index]; - startup_fallback_memory_index += size; - - return result; -} - -void * -__libc_malloc (size_t size) -{ - void *result; - - nautilus_leak_initialize_if_needed (); - - if (real_malloc == NULL) { - return allocate_temporary_fallback_memory (size); - } - - result = (*real_malloc) (size); - - if (result != NULL) { - if (detect_reentry(&__libc_malloc) - || detect_reentry(&__libc_realloc) - || detect_reentry(&__libc_memalign)) { - /* printf("avoiding reentry in __libc_malloc, block %p\n", result); */ - } else { - nautilus_leak_record_malloc (result, size); - } - } - - return result; -} - -void * -__libc_memalign (size_t boundary, size_t size) -{ - void *result; - - nautilus_leak_initialize_if_needed (); - result = (*real_memalign) (boundary, size); - - if (result != NULL) { - if (detect_reentry(&__libc_memalign)) { - /* printf("avoiding reentry in __libc_memalign, block %p\n", result); */ - } else { - nautilus_leak_record_malloc (result, size); - } - } - - return result; -} - -/* We are implementing __libc_calloc by calling __libc_malloc and memset - * instead of calling real_calloc for a reason. dlsym calls - * calloc and this way we prevent recursion during initialization. - * If we didn't do this, we would have to teach __libc_calloc to use - * fallback startup memory like __libc_malloc does. - */ -void * -__libc_calloc (size_t count, size_t size) -{ - size_t total; - void *result; - - total = count * size; - nautilus_leak_initialize_if_needed (); - result = __libc_malloc (total); - - if (result != NULL) { - memset (result, 0, total); - } - - return result; -} - -void * -__libc_realloc (void *ptr, size_t size) -{ - void *result; - nautilus_leak_initialize_if_needed (); - result = (*real_realloc) (ptr, size); - - if (detect_reentry(&__libc_realloc)) { - /* printf("avoiding reentry in __libc_realloc, block %p, old block %p\n", - result, ptr); */ - } else { - if (result != NULL && ptr == NULL) { - /* we are allocating a new block */ - nautilus_leak_record_malloc (result, size); - } else { - nautilus_leak_record_realloc (ptr, result, size); - } - } - return result; -} - -void -__libc_free (void *ptr) -{ - nautilus_leak_initialize_if_needed (); - - if (ptr > (void *)&startup_fallback_memory[0] - && ptr < (void *)&startup_fallback_memory[STARTUP_FALLBACK_MEMORY_SIZE]) { - /* this is a temporary startup fallback block, don't do anything - * with it - */ - return; - } - if (ptr != NULL) { - if (detect_reentry(&__libc_realloc)) { - /* printf("avoiding reentry in __libc_free, block %p\n", ptr); */ - } else { - nautilus_leak_record_free (ptr); - } - } - - (real_free) (ptr); -} - -static void -print_leaks_at_exit (void) -{ - /* If leak checking, dump all the outstanding allocations just before exiting. */ - nautilus_leak_print_leaks (8, 15, 100, TRUE); -} - -int -__libc_start_main (int (*main) (int, char **, char **), int argc, - char **argv, void (*init) (void), void (*fini) (void), - void (*rtld_fini) (void), void *stack_end) -{ - g_atexit (print_leaks_at_exit); - - nautilus_leak_initialize_if_needed (); - - nautilus_leak_checker_init (argv[0]); - - return real_start_main (main, argc, argv, init, fini, rtld_fini, stack_end); -} - -/* We try to keep a lot of code in between __libc_free and malloc to make - * the reentry detection that depends on call address proximity work. - */ - -typedef struct { - int count; - unsigned long size; -} LeakTotals; - -typedef struct { - int max_count; - int counter; - int stack_print_depth; - int stack_match_depth; -} PrintOneLeakParams; - -/* we don't care if printf, etc. allocates (as long as it doesn't leak) - * because by now we have a snapshot of the leaks at the time of - * calling nautilus_leak_print_leaks - */ - -static gboolean -total_one_leak (NautilusLeakTableEntry *entry, gpointer callback_data) -{ - LeakTotals *totals; - - totals = (LeakTotals *) callback_data; - - totals->count += entry->count; - totals->size += entry->total_size; - return TRUE; -} - -static GHashTable * -create_bad_names_hash_table (void) -{ - GHashTable *table; - int i; - - table = g_hash_table_new (g_str_hash, - g_str_equal); - for (i = 0; i < (sizeof (known_leakers) / sizeof (known_leakers[0])); i++) { - g_hash_table_insert (table, - (char *) known_leakers[i], - (char *) known_leakers[i]); - } - return table; -} - -static gboolean -is_stack_crawl_good (const NautilusLeakAllocationRecord *record, gpointer callback_data) -{ - int i; - char *name; - GHashTable *bad_names; - - bad_names = (GHashTable *) callback_data; - for (i = 0; record->stack_crawl[i] != NULL; i++) { - name = nautilus_leak_get_function_name (app_path, record->stack_crawl[i]); - if (g_hash_table_lookup (bad_names, name) != NULL) { - g_free (name); - return FALSE; - } - g_free (name); - } - return TRUE; -} - -static gboolean -print_one_leak (NautilusLeakTableEntry *entry, void *context) -{ - int index; - PrintOneLeakParams *params = (PrintOneLeakParams *)context; - - printf("----------------- total_size %ld count %d -------------------\n", - (long)entry->total_size, entry->count); - - for (index = 0; index < params->stack_print_depth; index++) { - /* only print stack_grouping worth of stack crawl - - * beyond that different blocks may have different addresses - * and we would be printing a lie - */ - if (entry->sample_allocation->stack_crawl[index] == NULL) - break; - printf(" %c ", (entry->count > 1 && index >= params->stack_match_depth) ? '?' : ' '); - - nautilus_leak_print_symbol_address (app_path, - entry->sample_allocation->stack_crawl[index]); - } - - /* only print max_counter groups */ - return params->counter++ < params->max_count; -} - -void -nautilus_leak_print_leaks (int stack_grouping_depth, int stack_print_depth, - int max_count, gboolean sort_by_count) -{ - NautilusLeakHashTable *hash_table; - NautilusLeakTable *leak_table; - GHashTable *bad_names; - LeakTotals leak_totals; - PrintOneLeakParams each_context; - - pthread_mutex_lock (&nautilus_leak_hash_table_mutex); - /* must have hash table by now */ - g_assert (nautilus_leak_hash_table != NULL); - hash_table = nautilus_leak_hash_table; - nautilus_leak_hash_table = NULL; - nautilus_leak_check_leaks = FALSE; - pthread_mutex_unlock (&nautilus_leak_hash_table_mutex); - - /* Filter out stack crawls that we want to ignore. */ - bad_names = create_bad_names_hash_table (); - nautilus_leak_hash_table_filter (hash_table, - is_stack_crawl_good, - bad_names); - g_hash_table_destroy (bad_names); - - /* Build a leak table by grouping blocks with the same - * stack crawls (<stack_grouping_depth> levels considered) - * from the allocated block hash table. - */ - leak_table = nautilus_leak_table_new (hash_table, stack_grouping_depth); - nautilus_leak_hash_table_free (hash_table); - - /* sort the leak table */ - if (sort_by_count) { - nautilus_leak_table_sort_by_count (leak_table); - } else { - nautilus_leak_table_sort_by_size (leak_table); - } - - /* we have a sorted table of all the leakers, we can print it out. */ - - leak_totals.count = 0; - leak_totals.size = 0; - nautilus_leak_table_each_item (leak_table, total_one_leak, &leak_totals); - - printf ("The leak checker found %d outstanding allocations for %lu bytes total at exit time.\n", - leak_totals.count, leak_totals.size); - printf ("Here is a report with stack trace match depth %d:\n", stack_grouping_depth); - - each_context.counter = 0; - each_context.max_count = max_count; - each_context.stack_print_depth = stack_print_depth; - each_context.stack_match_depth = stack_grouping_depth; - nautilus_leak_table_each_item (leak_table, print_one_leak, &each_context); - - /* we are done with it, free the leak table */ - nautilus_leak_table_free (leak_table); - - /* we are done with it, clean up cached up data used by the symbol lookup */ - nautilus_leak_print_symbol_cleanup (); -} - -void -nautilus_leak_checker_init (const char *path) -{ - /* we should get rid of this and find another way to find our - * binary's name - */ - printf ("Setting up the leak checker for %s\n", path); - app_path = path; -} - -void * -malloc (size_t size) -{ - return __libc_malloc (size); -} - -void * -realloc (void *ptr, size_t size) -{ - return __libc_realloc (ptr, size); -} - -void * -memalign (size_t boundary, size_t size) -{ - return __libc_memalign (boundary, size); -} - -void * -calloc (size_t nmemb, size_t size) -{ - return __libc_calloc (nmemb, size); -} - -void -free (void *ptr) -{ - __libc_free (ptr); -} - -/* Version that frees right away instead of keeping a pool. */ -GList * -g_list_alloc (void) -{ - return g_new0 (GList, 1); -} - -/* Version that frees right away instead of keeping a pool. */ -void -g_list_free (GList *list) -{ - GList *node, *next; - - node = list; - while (node != NULL) { - next = node->next; - g_free (node); - node = next; - } -} - -/* Version that uses normal allocation, not mem. chunks. */ -void -g_list_free_1 (GList *list) -{ - g_free (list); -} - -/* Version that frees right away instead of keeping a pool. */ -GSList * -g_slist_alloc (void) -{ - return g_new0 (GSList, 1); -} - -/* Version that frees right away instead of keeping a pool. */ -void -g_slist_free (GSList *list) -{ - GSList *node, *next; - - node = list; - while (node != NULL) { - next = node->next; - g_free (node); - node = next; - } -} - -/* Version that uses normal allocation, not mem. chunks. */ -void -g_slist_free_1 (GSList *list) -{ - g_free (list); -} - -/* Version that frees right away instead of keeping a pool. */ -GNode * -g_node_new (gpointer data) -{ - GNode *node; - - node = g_new0 (GNode, 1); - node->data = data; - return node; -} - -/* Version that frees right away instead of keeping a pool. */ -static void -g_nodes_free (GNode *root) -{ - GNode *node, *next; - - node = root; - while (node != NULL) { - next = node->next; - g_nodes_free (node->children); - g_free (node); - node = next; - } -} - -/* Version that frees right away instead of keeping a pool. */ -void -g_node_destroy (GNode *root) -{ - g_return_if_fail (root != NULL); - - if (!G_NODE_IS_ROOT (root)) { - g_node_unlink (root); - } - - g_nodes_free (root); -} - -/* Header on each chunk-allocated block. */ -typedef struct BlockHeader BlockHeader; -struct BlockHeader { - BlockHeader *next; - BlockHeader *prev; -}; - -/* Our version of GMemChunk. */ -struct _GMemChunk { - gint atom_size; - BlockHeader head; -}; - -/* Version that uses malloc and doesn't bother with chunking. */ -GMemChunk * -g_mem_chunk_new (gchar *name, - gint atom_size, - gulong area_size, - gint type) -{ - GMemChunk *mem_chunk; - - mem_chunk = g_new0 (GMemChunk, 1); - mem_chunk->atom_size = atom_size; - mem_chunk->head.next = &mem_chunk->head; - mem_chunk->head.prev = &mem_chunk->head; - return mem_chunk; -} - -/* Version that uses malloc and doesn't bother with chunking. */ -void -g_mem_chunk_destroy (GMemChunk *mem_chunk) -{ - g_mem_chunk_reset (mem_chunk); - g_free (mem_chunk); -} - -/* Version that uses malloc and doesn't bother with chunking. */ -gpointer -g_mem_chunk_alloc (GMemChunk *mem_chunk) -{ - BlockHeader *header, *next; - - header = g_malloc (sizeof (BlockHeader) + mem_chunk->atom_size); - next = mem_chunk->head.next; - header->next = next; - header->prev = &mem_chunk->head; - mem_chunk->head.next = header; - next->prev = header; - return header + 1; -} - -/* Version that uses malloc and doesn't bother with chunking. */ -gpointer -g_mem_chunk_alloc0 (GMemChunk *mem_chunk) -{ - gpointer block; - - block = g_mem_chunk_alloc (mem_chunk); - memset (block, 0, mem_chunk->atom_size); - return block; -} - -/* Version that uses malloc and doesn't bother with chunking. */ -void -g_mem_chunk_free (GMemChunk *mem_chunk, - gpointer mem) -{ - BlockHeader *header; - - header = ((BlockHeader *) mem) - 1; - header->next->prev = header->prev; - header->prev->next = header->next; - g_free (header); -} - -/* Version that uses malloc and doesn't bother with chunking. */ -void -g_mem_chunk_clean (GMemChunk *mem_chunk) -{ -} - -/* Version that uses malloc and doesn't bother with chunking. */ -void -g_mem_chunk_reset (GMemChunk *mem_chunk) -{ - while (mem_chunk->head.next != &mem_chunk->head) { - g_mem_chunk_free (mem_chunk, mem_chunk->head.next + 1); - } -} - -/* Version that uses malloc and doesn't bother with chunking. */ -void -g_mem_chunk_print (GMemChunk *mem_chunk) -{ -} - -#endif /* LEAK_CHECKER */ - -#ifdef LEAK_CHECK_TESTING -/* normally disabled */ - -static void -allocate_lots (int count) -{ - GList *list; - GList *p; - - list = NULL; - for (; count > 0; count--) { - list = g_list_prepend (list, g_malloc (rand() % 256)); - list = g_list_prepend (list, NULL); - } - for (p = list; p != NULL; p = p->next) { - g_free (p->data); - p->data = NULL; - } - g_list_free (list); -} - - -static void -leak_mem2 (void) -{ - int i; - for (i = 0; i < 40; i++) { - g_strdup("bla"); - } - allocate_lots (1280); -} - -static void -leak_mem (void) -{ - int i; - for (i = 0; i < 1010; i++) { - malloc(13); - } - leak_mem2(); - allocate_lots (200); -} - - -int -main (int argc, char **argv) -{ - void *non_leak; - void *leak; - int i; - - non_leak = g_malloc(100); - leak = g_malloc(200); - g_assert(non_leak != NULL); - non_leak = g_realloc(non_leak, 1000); - g_assert(non_leak != NULL); - non_leak = g_realloc(non_leak, 10000); - leak = g_malloc(200); - non_leak = g_realloc(non_leak, 100000); - leak = g_malloc(200); - g_assert(non_leak != NULL); - g_free(non_leak); - - non_leak = calloc(1, 100); - g_assert(non_leak != NULL); - g_free(non_leak); - leak = g_malloc(200); - - non_leak = memalign(16, 100); - g_assert(non_leak != NULL); - g_free(non_leak); - leak = g_malloc(200); - leak = memalign(16, 100); - leak = memalign(16, 100); - leak = memalign(16, 100); - leak = memalign(16, 100); - leak = memalign(16, 100); - leak = memalign(16, 100); - - for (i = 0; i < 13; i++) { - leak = malloc(13); - } - - leak_mem(); - leak_mem2(); - - allocate_lots (1); - for (i = 0; i < 100; i++) { - allocate_lots(rand() % 40); - } - printf("done\n"); - nautilus_leak_print_leaks (6, 12, 100, TRUE); - - return 0; -} - - -#endif diff --git a/tools/leak-checker/nautilus-leak-checker.h b/tools/leak-checker/nautilus-leak-checker.h deleted file mode 100644 index b58a633dd..000000000 --- a/tools/leak-checker/nautilus-leak-checker.h +++ /dev/null @@ -1,54 +0,0 @@ -/* nautilus-leak-checker.h - simple leak checking library - Virtual File System Library - - Copyright (C) 2000 Eazel - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Pavel Cisler <pavel@eazel.com> - based on MemProf by Owen Taylor, <otaylor@redhat.com> -*/ - -#ifndef LEAK_CHECKER_H -#define LEAK_CHECKER_H - -#define LEAK_CHECKER 1 - -#if LEAK_CHECKER - -#define __USE_GNU -#define _GNU_SOURCE -/* need this for dlsym */ -#include <pthread.h> -#include <glib.h> - -/* This is a leakchecker simpler than MemProf - it tracks all the outstanding - * allocations and allows you print a total when your app quits. It doesn't actually - * try to identify leaks like MemProf does. The entire leakchecker machinery runs - * in the same process as the target app and shares the same heap for it's data - * structures. - */ - -extern void nautilus_leak_checker_init (const char *app_path); - -extern void nautilus_leak_print_leaks (int stack_grouping_depth, - int stack_print_depth, - int max_count, - gboolean sort_by_count); - -#endif - -#endif diff --git a/tools/leak-checker/nautilus-leak-hash-table.c b/tools/leak-checker/nautilus-leak-hash-table.c deleted file mode 100644 index c2cba26dd..000000000 --- a/tools/leak-checker/nautilus-leak-hash-table.c +++ /dev/null @@ -1,533 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ - -/* nautilus-leak-hash-table.c - hash table for a leak checking library - Virtual File System Library - - Copyright (C) 2000 Eazel - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Pavel Cisler <pavel@eazel.com> -*/ - -#include "nautilus-leak-checker.h" -/* included first, defines following switch*/ -#if LEAK_CHECKER - -#include <glib.h> -#include <stdlib.h> -#include <string.h> - -#include "nautilus-leak-checker-stubs.h" -#include "nautilus-leak-hash-table.h" - -/* We have our own hash table here mainly to allow avoiding calls to - * malloc and realloc that would cause reentry - */ - -static void -nautilus_leak_hash_element_finalize (NautilusHashEntry *element) -{ - nautilus_leak_allocation_record_finalize (&element->data); - memset (element, 0, sizeof(NautilusHashEntry)); -} - -static unsigned long -nautilus_leak_hash_element_hash (NautilusHashEntry *element) -{ - return (unsigned long)element->data.block; -} - -static gboolean -nautilus_leak_hash_element_match (NautilusHashEntry *element, unsigned long key) -{ - return (unsigned long)element->data.block == key; -} - -/* NautilusHashEntries are allocated inside a NautilusHashEntryVector. - * NautilusHashEntryVector keeps a linked list of deleted entries. - */ -typedef struct { - NautilusHashEntry *data; - size_t size; - int next_free; - int next_deleted; -} NautilusHashEntryVector; - -static void -nautilus_leak_hash_element_vector_inititalize (NautilusHashEntryVector *vector, size_t initial_size) -{ - int index; - - vector->data = (NautilusHashEntry *)real_malloc(initial_size * sizeof(NautilusHashEntry)); - if (vector->data == NULL) { - g_warning ("leak checker out of memory"); - abort(); - } - memset (vector->data, 0, initial_size * sizeof(NautilusHashEntry)); - for (index = initial_size - 1; index >= 0; index --) { - vector->data[index].next = -1; - } - - vector->size = initial_size; - vector->next_free = 0; - vector->next_deleted = -1; -} - -static void -nautilus_leak_hash_element_vector_finalize (NautilusHashEntryVector *vector) -{ - int index; - for (index = 0; index < vector->size; index++) { - nautilus_leak_hash_element_finalize (&vector->data[index]); - } - real_free (vector->data); -} - -static NautilusHashEntry * -nautilus_leak_hash_element_vector_at (NautilusHashEntryVector *vector, int index) -{ - return &vector->data[index]; -} - -enum { - HASH_ELEMENT_VECTOR_GROW_CHUNK = 1024 -}; - -static int -nautilus_leak_hash_element_vector_add (NautilusHashEntryVector *vector) -{ - int index; - NautilusHashEntry *new_element; - size_t new_size; - NautilusHashEntry *new_data; - - if (vector->next_deleted >= 0) { - /* Reuse a previously deleted item. */ - index = vector->next_deleted; - vector->next_deleted = nautilus_leak_hash_element_vector_at (vector, index)->next; - } else if (vector->next_free >= vector->size - 1) { - /* We need grow the vector because it cannot fit more entries. */ - new_size = vector->size + HASH_ELEMENT_VECTOR_GROW_CHUNK; - new_data = (NautilusHashEntry *)real_malloc(new_size * sizeof(NautilusHashEntry)); - if (new_data == NULL) { - g_warning ("leak checker out of memory"); - abort(); - } - /* FIXME bugzilla.eazel.com 2469: only clean the unused part */ - memset (new_data, 0, new_size * sizeof(NautilusHashEntry)); - - /* copy all the existing items over*/ - memcpy (new_data, vector->data, vector->size * sizeof(NautilusHashEntry)); - /* delete the old array */ - real_free (vector->data); - vector->data = new_data; - vector->size = new_size; - index = vector->next_free; - ++vector->next_free; - } else { - /* Just take the next free item. */ - index = vector->next_free; - ++vector->next_free; - } - - /* Initialize the new element to an empty state. */ - new_element = nautilus_leak_hash_element_vector_at (vector, index); - memset (new_element, 0, sizeof(NautilusHashEntry)); - new_element->next = -1; - - return index; -} - -static void -nautilus_leak_hash_element_vector_remove (NautilusHashEntryVector *vector, int index) -{ - /* free the data */ - nautilus_leak_hash_element_finalize (&vector->data[index]); - - /* insert item as first into deleted item list */ - nautilus_leak_hash_element_vector_at (vector, index)->next = vector->next_deleted; - vector->next_deleted = index; -} - -struct NautilusLeakHashTable { - size_t array_size; - int *hash_array; - NautilusHashEntryVector element_vector; -}; - -/* These primes are close to 2^n numbers for optimal hashing performance - * and near-2^n size. - */ -long nautilus_leak_hash_table_primes [] = { - 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, - 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859, - 134217689, 268435399, 536870909, 1073741789, 2147483647, 0 -}; - - -static size_t -nautilus_leak_hash_table_optimal_size (size_t size) -{ - int index; - for (index = 0; ; index++) { - if (!nautilus_leak_hash_table_primes [index] || nautilus_leak_hash_table_primes [index] >= size) { - return nautilus_leak_hash_table_primes [index]; - } - } - - return 0; -} - -static void -nautilus_leak_hash_table_initialize (NautilusLeakHashTable *table, size_t initial_size) -{ - /* calculate the size of the bucket array */ - table->array_size = nautilus_leak_hash_table_optimal_size (initial_size); - - /* allocate the element array */ - nautilus_leak_hash_element_vector_inititalize (&table->element_vector, table->array_size * 5); - - /* allocate the bucket array */ - table->hash_array = (int *)real_malloc (table->array_size * sizeof(int)); - - /* initialize the to empty state */ - memset (table->hash_array, -1, table->array_size * sizeof(int)); -} - -static void -nautilus_leak_hash_table_finalize (NautilusLeakHashTable *table) -{ - nautilus_leak_hash_element_vector_finalize (&table->element_vector); - real_free (table->hash_array); -} - -NautilusLeakHashTable * -nautilus_leak_hash_table_new (size_t initial_size) -{ - NautilusLeakHashTable *new_table; - new_table = real_malloc (sizeof(NautilusLeakHashTable)); - nautilus_leak_hash_table_initialize (new_table, initial_size); - - return new_table; -} - -void -nautilus_leak_hash_table_free (NautilusLeakHashTable *hash_table) -{ - nautilus_leak_hash_table_finalize (hash_table); - real_free (hash_table); -} - -static unsigned long -nautilus_leak_hash_table_hash (NautilusLeakHashTable *table, unsigned long seed) -{ - return (seed >> 2) % table->array_size; -} - -NautilusHashEntry * -nautilus_leak_hash_table_find (NautilusLeakHashTable *table, unsigned long key) -{ - int index; - NautilusHashEntry *result; - - for (index = table->hash_array [nautilus_leak_hash_table_hash (table, key)]; index >= 0;) { - result = nautilus_leak_hash_element_vector_at (&table->element_vector, index); - if (nautilus_leak_hash_element_match (result, key)) { - return result; - } - index = result->next; - } - - return NULL; -} - -NautilusHashEntry * -nautilus_leak_hash_table_add (NautilusLeakHashTable *table, unsigned long key) -{ - int new_index; - NautilusHashEntry *result; - unsigned long hash; - - /* calculate the index of the bucket */ - hash = nautilus_leak_hash_table_hash (table, key); - - /* allocate space for new item in element vector */ - new_index = nautilus_leak_hash_element_vector_add (&table->element_vector); - result = nautilus_leak_hash_element_vector_at (&table->element_vector, new_index); - - /* insert new item first in the list for bucket <hash> */ - result->next = table->hash_array[hash]; - table->hash_array[hash] = new_index; - - return result; -} - -static void -nautilus_leak_hash_table_remove_element (NautilusLeakHashTable *table, NautilusHashEntry *element) -{ - unsigned long hash; - int next; - int index; - NautilusHashEntry *tmp_element; - - /* find the bucket */ - hash = nautilus_leak_hash_table_hash (table, nautilus_leak_hash_element_hash (element)); - next = table->hash_array[hash]; - - g_assert (next >= 0); - - /* try to match bucket list head */ - if (nautilus_leak_hash_element_vector_at (&table->element_vector, next) == element) { - table->hash_array[hash] = element->next; - nautilus_leak_hash_element_vector_remove (&table->element_vector, next); - return; - } - - for (index = next; index >= 0; ) { - /* look for an existing match in table */ - next = nautilus_leak_hash_element_vector_at (&table->element_vector, index)->next; - if (next < 0) { - g_assert (!"should not be here"); - return; - } - - tmp_element = nautilus_leak_hash_element_vector_at (&table->element_vector, index); - if (nautilus_leak_hash_element_vector_at (&table->element_vector, next) == element) { - nautilus_leak_hash_element_vector_at (&table->element_vector, index)->next = element->next; - nautilus_leak_hash_element_vector_remove (&table->element_vector, next); - return; - } - index = next; - } -} - -gboolean -nautilus_leak_hash_table_remove (NautilusLeakHashTable *table, unsigned long key) -{ - NautilusHashEntry *element; - - element = nautilus_leak_hash_table_find (table, key); - if (element != NULL) { - /* FIXME bugzilla.eazel.com 2470: - * this could be faster if we just found the element - * here and deleted it. - */ - nautilus_leak_hash_table_remove_element (table, element); - - return TRUE; - } - return FALSE; -} - -void -nautilus_leak_hash_table_filter (NautilusLeakHashTable *table, - NautilusLeakHashTableFilterFunction function, - gpointer callback_data) -{ - NautilusHashEntry *entry; - int i; - - for (i = 0; i < table->element_vector.size; i++) { - /* traverse the hash table element vector */ - entry = nautilus_leak_hash_element_vector_at (&table->element_vector, i); - if (entry->data.stack_crawl != NULL) { - if (!(* function) (&entry->data, callback_data)) { - entry->data.stack_crawl = NULL; - } - } - } -} - -struct NautilusLeakTable { - size_t size; - NautilusLeakTableEntry *data; -}; - -static NautilusLeakTableEntry * -nautilus_leak_table_new_entry_at (NautilusLeakTable *table, int index) -{ - /* Allocate a new slot. Avoid using real_realloc here because - * it ends up calling our version of __libc_malloc and messes up - * the leak table - */ - NautilusLeakTableEntry *new_table = (NautilusLeakTableEntry *) real_malloc - ((table->size + 1) * sizeof (NautilusLeakTableEntry)); - - if (new_table == NULL) { - g_warning ("Ran out of memory while allocating leak checker structures"); - abort (); - } - - /* finish what realloc would have done if we could call it */ - memcpy (new_table, table->data, (table->size) * sizeof (NautilusLeakTableEntry)); - real_free (table->data); - table->data = new_table; - - /* move the items over by one to make room for new item */ - if (index < table->size) { - memmove (&table->data[index + 1], - &table->data[index], - (table->size - index) * sizeof (NautilusLeakTableEntry)); - } - - table->size++; - - return &table->data[index]; -} - -static void -nautilus_leak_table_add_entry (NautilusLeakTable *table, NautilusHashEntry *entry, int stack_grouping_depth) -{ - int r, l; - int resulting_index; - int compare_result; - - /* do a binary lookup of the item */ - r = table->size - 1; - resulting_index = 0; - compare_result = 0; - - for (l = 0; l <= r; ) { - resulting_index = (l + r) / 2; - - compare_result = nautilus_leak_stack_crawl_compare ( - table->data[resulting_index].sample_allocation->stack_crawl, - entry->data.stack_crawl, - stack_grouping_depth); - - if (compare_result > 0) { - r = resulting_index - 1; - } else if (compare_result < 0) { - l = resulting_index + 1; - } else { - break; - } - } - - if (compare_result < 0) { - resulting_index++; - } - - if (compare_result == 0 && resulting_index < table->size) { - /* we already have a match, just bump up the count and size */ - table->data[resulting_index].count++; - table->data[resulting_index].total_size += entry->data.size; - return; - } - - nautilus_leak_table_new_entry_at (table, resulting_index); - table->data[resulting_index].count = 1; - table->data[resulting_index].total_size = entry->data.size; - table->data[resulting_index].sample_allocation = nautilus_leak_allocation_record_copy (&entry->data); -} - -NautilusLeakTable * -nautilus_leak_table_new (NautilusLeakHashTable *hash_table, int stack_grouping_depth) -{ - NautilusLeakTable *result; - NautilusHashEntry *nautilus_leak_hash_table_entry; - int index; - - result = real_malloc (sizeof(NautilusLeakTable)); - result->size = 0; - result->data = NULL; - - for (index = 0; index < hash_table->element_vector.size; index++) { - /* traverse the hash table element vector */ - nautilus_leak_hash_table_entry = nautilus_leak_hash_element_vector_at (&hash_table->element_vector, index); - if (nautilus_leak_hash_table_entry->data.stack_crawl != NULL) { - nautilus_leak_table_add_entry (result, nautilus_leak_hash_table_entry, stack_grouping_depth); - } - } - - return result; -} - -void -nautilus_leak_table_free (NautilusLeakTable *leak_table) -{ - int index; - if (leak_table != NULL) { - for (index = 0; index < leak_table->size; index++) { - nautilus_leak_allocation_record_free(leak_table->data[index].sample_allocation); - } - real_free (leak_table->data); - } - - real_free (leak_table); -} - -static int -sort_by_count (const void *entry1, const void *entry2) -{ - int result; - - result = ((NautilusLeakTableEntry *)entry2)->count - - ((NautilusLeakTableEntry *)entry1)->count; - - if (result == 0) { - /* match, secondary sort order by size */ - return ((NautilusLeakTableEntry *)entry2)->total_size - - ((NautilusLeakTableEntry *)entry1)->total_size; - } - return result; -} - -void -nautilus_leak_table_sort_by_count (NautilusLeakTable *leak_table) -{ - qsort (leak_table->data, leak_table->size, - sizeof(NautilusLeakTableEntry), sort_by_count); -} - -static int -sort_by_size (const void *entry1, const void *entry2) -{ - int result; - - result = ((NautilusLeakTableEntry *)entry2)->total_size - - ((NautilusLeakTableEntry *)entry1)->total_size; - - if (result == 0) { - /* match, secondary sort order by count */ - return ((NautilusLeakTableEntry *)entry2)->count - - ((NautilusLeakTableEntry *)entry1)->count; - } - return result; -} - -void -nautilus_leak_table_sort_by_size (NautilusLeakTable *leak_table) -{ - qsort (leak_table->data, leak_table->size, - sizeof (NautilusLeakTableEntry), sort_by_size); -} - -void -nautilus_leak_table_each_item (NautilusLeakTable *leak_table, NautilusEachLeakTableFunction function, - void *context) -{ - int index; - for (index = 0; index < leak_table->size; index++) { - if (!function (&leak_table->data[index], context)) { - /* break early */ - return; - } - } -} - -#endif diff --git a/tools/leak-checker/nautilus-leak-hash-table.h b/tools/leak-checker/nautilus-leak-hash-table.h deleted file mode 100644 index 2de2aeb58..000000000 --- a/tools/leak-checker/nautilus-leak-hash-table.h +++ /dev/null @@ -1,63 +0,0 @@ -/* nautilus-leak-hash-table.h - hash table for a leak checking library - Virtual File System Library - - Copyright (C) 2000 Eazel - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Pavel Cisler <pavel@eazel.com> -*/ - -#ifndef NAUTILUS_LEAK_HASH_TABLE_H -#define NAUTILUS_LEAK_HASH_TABLE_H - -typedef struct NautilusLeakHashTable NautilusLeakHashTable; -typedef struct NautilusHashEntry NautilusHashEntry; - -typedef gboolean (* NautilusLeakHashTableFilterFunction) (const NautilusLeakAllocationRecord *record, gpointer callback_data); - -NautilusLeakHashTable *nautilus_leak_hash_table_new (size_t initial_size); -void nautilus_leak_hash_table_free (NautilusLeakHashTable *hash_table); -gboolean nautilus_leak_hash_table_remove (NautilusLeakHashTable *table, - unsigned long key); -NautilusHashEntry * nautilus_leak_hash_table_add (NautilusLeakHashTable *table, - unsigned long key); -NautilusHashEntry * nautilus_leak_hash_table_find (NautilusLeakHashTable *table, - unsigned long key); -void nautilus_leak_hash_table_filter (NautilusLeakHashTable *table, - NautilusLeakHashTableFilterFunction function, - gpointer callback_data); - - -typedef struct { - int count; - size_t total_size; - NautilusLeakAllocationRecord *sample_allocation; -} NautilusLeakTableEntry; - -typedef struct NautilusLeakTable NautilusLeakTable; -typedef gboolean (* NautilusEachLeakTableFunction) (NautilusLeakTableEntry *entry, void *context); - -NautilusLeakTable *nautilus_leak_table_new (NautilusLeakHashTable *hash_table, - int stack_grouping_depth); -void nautilus_leak_table_free (NautilusLeakTable *leak_table); -void nautilus_leak_table_sort_by_count (NautilusLeakTable *leak_table); -void nautilus_leak_table_sort_by_size (NautilusLeakTable *leak_table); -void nautilus_leak_table_each_item (NautilusLeakTable *leak_table, - NautilusEachLeakTableFunction function, - void *context); - -#endif /* NAUTILUS_LEAK_HASH_TABLE_H */ diff --git a/tools/leak-checker/nautilus-leak-symbol-lookup.c b/tools/leak-checker/nautilus-leak-symbol-lookup.c deleted file mode 100644 index 5f73f91bc..000000000 --- a/tools/leak-checker/nautilus-leak-symbol-lookup.c +++ /dev/null @@ -1,294 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ - -/* nautilus-leak-symbol-lookup.c - symbol lookup for a leak checking library - Virtual File System Library - - Copyright (C) 2000 Eazel - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Pavel Cisler <pavel@eazel.com> - based on MemProf by Owen Taylor, <otaylor@redhat.com> -*/ - -#define _GNU_SOURCE - /* need this for dladdr */ - -#include "nautilus-leak-symbol-lookup.h" - -#include <bfd.h> -#include <dlfcn.h> -#include <glib.h> -#include <stdio.h> -#include <malloc.h> -#include <unistd.h> -#include <sys/stat.h> - - -static GList *symbol_table_list; - -typedef struct { - char *path; - bfd *abfd; - asymbol **symbol_table; - asection *text_section; - unsigned long start; - unsigned long end; -} NautilusLeakSymbolLookupMap; - -static gboolean -nautilus_leak_find_symbol_in_map (const NautilusLeakSymbolLookupMap *map, - unsigned long address, char **function_name, char **source_file_name, - unsigned int *line) -{ - const char *file; - const char *function; - - address -= map->start; - address -= map->text_section->vma; - - if (address < 0 || address > map->text_section->_cooked_size) { - /* not a valid address range for this binary */ - return FALSE; - } - - if (!bfd_find_nearest_line (map->abfd, map->text_section, map->symbol_table, - address, - &file, &function, line)) { - printf ("error looking up address in binary %s\n", map->path); - return FALSE; - } - if (file == NULL || function == NULL) { - return FALSE; - } - - *function_name = g_strdup (function); - *source_file_name = g_strdup (file); - - return TRUE; -} - -static void -nautilus_leak_symbol_map_get_offsets (NautilusLeakSymbolLookupMap *map) -{ - gchar buffer[1024]; - FILE *in; - gchar perms[26]; - gchar file[256]; - unsigned long start, end; - guint major, minor; - ino_t inode; - struct stat library_stat; - struct stat entry_stat; - int count; - - /* find the library we are looking for in the proc directories - * to find out at which addresses it is mapped - */ - snprintf (buffer, 1023, "/proc/%d/maps", getpid()); - in = fopen (buffer, "r"); - - if (stat (map->path, &library_stat) != 0) { - /* we will use st_ino and st_dev to do a file match */ - return; - } - - while (fgets(buffer, 1023, in)) { - gulong tmp; - - count = sscanf (buffer, "%lx-%lx %15s %*x %u:%u %lu %255s", - &start, &end, perms, &major, &minor, &tmp, file); - inode = tmp; - - if (count >= 6 && strcmp (perms, "r-xp") == 0) { - if (stat (file, &entry_stat) != 0) { - break; - } - /* check if this is the library we are loading */ - if (library_stat.st_ino == entry_stat.st_ino - && library_stat.st_dev == entry_stat.st_dev) { - map->start = start; - map->end = end; - - break; - } - } - } - fclose (in); -} - -static NautilusLeakSymbolLookupMap * -nautilus_leak_symbol_map_load (const char *binary_path, gboolean executable) -{ - NautilusLeakSymbolLookupMap *map; - char *target = NULL; - size_t storage_needed; - int number_of_symbols; - - map = g_new0 (NautilusLeakSymbolLookupMap, 1); - - map->abfd = bfd_openr (binary_path, target); - - if (map->abfd == NULL) { - fprintf (stderr, "%s: ", binary_path); - bfd_perror (binary_path); - return NULL; - } - - if (!bfd_check_format (map->abfd, bfd_object)) { - fprintf (stderr, "%s is not an object file\n", binary_path); - bfd_close (map->abfd); - return NULL; - } - - /* Use the ".text" section. */ - map->text_section = bfd_get_section_by_name (map->abfd, ".text"); - - /* Read the symbol table. */ - storage_needed = bfd_get_symtab_upper_bound (map->abfd); - if (storage_needed == 0) { - fprintf (stderr, "no symbols\n"); - bfd_close (map->abfd); - return NULL; - } - map->symbol_table = (asymbol **)g_malloc (storage_needed); - if (map->symbol_table == NULL) { - fprintf (stderr, "no memory allocating symbol table\n"); - bfd_close (map->abfd); - return NULL; - } - number_of_symbols = bfd_canonicalize_symtab (map->abfd, map->symbol_table); - map->path = g_strdup (binary_path); - - if (!executable) { - nautilus_leak_symbol_map_get_offsets (map); - } - symbol_table_list = g_list_append (symbol_table_list, map); - - return map; -} - -static NautilusLeakSymbolLookupMap * -nautilus_leak_symbol_map_load_if_needed (const char *binary_path, gboolean executable) -{ - GList *p; - NautilusLeakSymbolLookupMap *map; - - for (p = symbol_table_list; p != NULL; p = p->next) { - map = p->data; - if (strcmp (map->path, binary_path) == 0) - /* no need to load the symbols, already got the map */ - return map; - } - return nautilus_leak_symbol_map_load (binary_path, executable); -} - -void -nautilus_leak_print_symbol_cleanup (void) -{ - /* free the cached symbol tables */ - GList *p; - NautilusLeakSymbolLookupMap *map; - - for (p = symbol_table_list; p != NULL; p = p->next) { - map = p->data; - bfd_close (map->abfd); - g_free (map->symbol_table); - g_free (map->path); - - g_free (map); - } - - g_list_free (symbol_table_list); - symbol_table_list = NULL; -} - -static gboolean -nautilus_leak_find_symbol_address (void *address, char **function_name, char **source_file_name, - int *line) -{ - GList *p; - NautilusLeakSymbolLookupMap *map; - Dl_info info; - - if (dladdr (address, &info) != 0) { - /* We know the function name and the binary it lives in, now try to find - * the function and the offset. - */ - map = nautilus_leak_symbol_map_load_if_needed (info.dli_fname, false); - if (map != NULL - && nautilus_leak_find_symbol_in_map (map, (long)address, - function_name, source_file_name, line)) { - return TRUE; - } - /* just return the function name and the library binary path */ - *function_name = g_strdup (info.dli_sname); - *source_file_name = g_strdup (info.dli_fname); - *line = -1; - return TRUE; - } else { - /* Usually dladdr will succeed, it seems to only fail for - * address lookups for functions in the main binary. - */ - for (p = symbol_table_list; p != NULL; p = p->next) { - map = p->data; - if (nautilus_leak_find_symbol_in_map (map, (long)address, function_name, - source_file_name, (unsigned int *)line)) - return TRUE; - } - } - - return FALSE; -} - -void -nautilus_leak_print_symbol_address (const char *app_path, void *address) -{ - char *function_name; - char *source_file_name; - int line; - - nautilus_leak_symbol_map_load_if_needed (app_path, true); - - if (nautilus_leak_find_symbol_address (address, &function_name, &source_file_name, &line)) { - if (line >= 0) { - printf("%10p %-30s %s:%d\n", address, function_name, source_file_name, line); - } else { - printf("%10p %-30s in library %s\n", address, function_name, source_file_name); - } - g_free (function_name); - g_free (source_file_name); - } else { - printf("%p (unknown function)\n", address); - } -} - -char * -nautilus_leak_get_function_name (const char *app_path, void *address) -{ - char *function_name; - char *source_file_name; - int line; - - nautilus_leak_symbol_map_load_if_needed (app_path, true); - - if (nautilus_leak_find_symbol_address (address, &function_name, &source_file_name, &line)) { - g_free (source_file_name); - return function_name; - } else { - return NULL; - } -} diff --git a/tools/leak-checker/nautilus-leak-symbol-lookup.h b/tools/leak-checker/nautilus-leak-symbol-lookup.h deleted file mode 100644 index 05afe9941..000000000 --- a/tools/leak-checker/nautilus-leak-symbol-lookup.h +++ /dev/null @@ -1,34 +0,0 @@ -/* nautilus-leak-symbol-lookup.h - symbol lookup for a leak checking library - Virtual File System Library - - Copyright (C) 2000 Eazel - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Pavel Cisler <pavel@eazel.com> - based on MemProf by Owen Taylor, <otaylor@redhat.com> -*/ - -#ifndef NAUTILUS_LEAK_SYMBOL_LOOKUP_H -#define NAUTILUS_LEAK_SYMBOL_LOOKUP_H - -void nautilus_leak_print_symbol_address (const char *app_path, - void *address); -char *nautilus_leak_get_function_name (const char *app_path, - void *address); -void nautilus_leak_print_symbol_cleanup (void); - -#endif /* NAUTILUS_LEAK_SYMBOL_LOOKUP_H */ diff --git a/tools/profiler/Makefile b/tools/profiler/Makefile deleted file mode 100644 index f5935a601..000000000 --- a/tools/profiler/Makefile +++ /dev/null @@ -1,14 +0,0 @@ - -# temporary hardcoded makefile to get things going - -SOURCES := profile.C profiledata.C totaltime.C machine-profile.S funcsummary.C nautilus-leak-symbol-lookup.C -HEADERS := profile.h profiledata.h totaltime.h symbol-table.h funcsummary.h nautilus-leak-symbol-lookup.h profileP.h machine-profileP.h machine-profile.h - -LIBS := -lpthread -lglib -ldl -Wl,-Bstatic -lbfd -liberty -Wl,-Bdynamic - -libprofiler.so: $(SOURCES) $(HEADERS) - g++ -g -W -Wall -I/gnome/include -I/gnome/include/glib-1.2 -I/gnome/lib/glib/include -L/gnome/lib $(SOURCES) $(LIBS) -shared -o libprofiler.so - -test: test.cpp - g++ -DTEST_LIB -g -O0 -finstrument-functions test.cpp -shared -o libtest.so - g++ -g -O0 -finstrument-functions test.cpp -L. -ltest -lprofiler -lpthread -o test
\ No newline at end of file diff --git a/tools/profiler/funcsummary.C b/tools/profiler/funcsummary.C deleted file mode 100644 index 778fffe08..000000000 --- a/tools/profiler/funcsummary.C +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "funcsummary.h" - -#include <vector> -#include <algorithm> -#include <utility> -#include <iomanip> -#include <cstdio> - -using namespace std; - -inline bool -FuncSummary::sort_func_percent(const FuncData &left, const FuncData &right) -{ - return right.func_pct < left.func_pct; -} - -inline bool -FuncSummary::sort_func_calls(const FuncData &left, const FuncData &right) -{ - return right.count < left.count; -} - -inline bool -FuncSummary::sort_func_children_percent(const FuncData &left, const FuncData &right) -{ - return right.func_children_pct < left.func_children_pct; -} - -FuncSummary::FuncSummary(const ProfileData &data, const SymbolTable &_syms, - sort_order _order, profctr_t total_time) - : syms(_syms), order(_order) -{ - time_factor = data.frequency() / 1000; - - MyArcVisitor visitor(*this); - data.VisitArcs(&visitor); - - for (function_map_t::iterator i = function_map.begin(); - i != function_map.end(); ++i) { - i->second.func_pct = (double)i->second.func_time / total_time * 100; - i->second.func_children_pct = (double)i->second.func_children_time / total_time * 100; - } -} - -FuncSummary::~FuncSummary() -{ -} - -const char FuncSummary::header[] = - "Function Name calls func% func(ms) f+c% f+c(ms)\n"; -//wait_reply 19078 51.731 4074 51.737 4074 - - -void -FuncSummary::Output(ostream &os) -{ - typedef std::vector<FuncData> function_list_t; - function_list_t func_list; - - func_list.reserve(function_map.size()); - - for (function_map_t::const_iterator i = function_map.begin(); - i != function_map.end(); ++i) - func_list.push_back(i->second); - - switch (order) { - case sort_func: - sort(func_list.begin(), func_list.end(), sort_func_percent); - break; - - case sort_child: - sort(func_list.begin(), func_list.end(), sort_func_children_percent); - break; - - case sort_calls: - sort(func_list.begin(), func_list.end(), sort_func_calls); - break; - } - - os << header; - - for (function_list_t::const_iterator i = func_list.begin(); - i != func_list.end(); ++i) { - char buf[256]; - - if (i->func_pct == 0 || i->count == 0) - continue; - - snprintf(buf, sizeof(buf)/sizeof(buf[0]), - "%-47s %9ld %#7.3f %9lld %7.3f %9lld\n", i->name.c_str(), - (long)i->count, i->func_pct, i->func_time / time_factor, - i->func_children_pct, i->func_children_time / time_factor); - - os << buf; - } -} - -FuncSummary::FuncData &FuncSummary::get_func(codeptr_t func) -{ - string name; - syms.LookupExact(func, name); - - function_map_t::iterator i = function_map.find(name); - if (i != function_map.end()) - return i->second; - - FuncData f; - f.name = name; - f.func_time = 0; - f.func_children_time = 0; - f.func_pct = 0; - f.func_children_pct = 0; - f.count = 0; - - return function_map.insert(make_pair(name, f)).first->second; -} - -void FuncSummary::MyArcVisitor::visit(const ProfileData::ArcData &a) -{ - FuncData &from = outer.get_func(a.fromfunc); - FuncData &to = outer.get_func(a.tofunc); - - to.count += a.count; - - to.func_time += a.time; - to.func_children_time += a.time; - - if (from.func_time > 0) - from.func_time -= a.time; -} - - -FuncSummary::MyArcVisitor::~MyArcVisitor() -{ -} diff --git a/tools/profiler/funcsummary.h b/tools/profiler/funcsummary.h deleted file mode 100644 index da6ccb4f2..000000000 --- a/tools/profiler/funcsummary.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef FUNCSUMMARY_H_INCLUDED -#define FUNCSUMMARY_H_INCLUDED - -#include <iostream> -#include <string> -#include <map> - -#include "profiledata.h" -#include "symbol-table.h" - -class FuncSummary -{ -public: - enum sort_order { - sort_func, - sort_child, - sort_calls - }; - - FuncSummary(const ProfileData &data, const SymbolTable &syms, - sort_order order, profctr_t total_time); - ~FuncSummary(); - - void Output(std::ostream &os); - -private: - struct FuncData { - string name; - profctr_t func_time, func_children_time; - double func_pct, func_children_pct; - size_t count; - }; - - typedef std::map<std::string, FuncData> function_map_t; - - const SymbolTable &syms; - function_map_t function_map; - - FuncData &get_func(codeptr_t); - - struct MyArcVisitor; - friend struct MyArcVisitor; - struct MyArcVisitor : ProfileData::ArcVisitor { - explicit MyArcVisitor(FuncSummary &_outer) : outer(_outer) { } - virtual ~MyArcVisitor(); - virtual void visit(const ProfileData::ArcData &a); - - private: - FuncSummary &outer; - }; - - profctr_t time_factor; - - static const char header[]; - - sort_order order; - - static inline bool sort_func_percent(const FuncData &left, - const FuncData &right); - static inline bool sort_func_calls(const FuncData &left, - const FuncData &right); - static inline bool sort_func_children_percent(const FuncData &left, - const FuncData &right); - - // unimplemented - FuncSummary(const FuncSummary &); - void operator = (const FuncSummary &); -}; - -#endif diff --git a/tools/profiler/machine-profile.S b/tools/profiler/machine-profile.S deleted file mode 100644 index 9f2b044cb..000000000 --- a/tools/profiler/machine-profile.S +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (C) 2000 Corel Corporation */ - .globl __menter - .globl __mexit - -.text - .align 4 - .type __menter,@function -__menter: - pushl %eax - pushl %ecx - pushl %edx - - pushl 16(%esp) - - call __menter_internal - - popl %edx - popl %ecx - popl %eax - - ret -1: - .size __menter, 1b-__menter - - .align 4 - .type __mexit,@function -__mexit: - pushl %eax - pushl %ecx - pushl %edx - - call __mexit_internal - - popl %edx - popl %ecx - popl %eax - ret -1: - .size __mexit, 1b-__mexit - -/* gcc-2.95.2 outputs calls to these functions */ - .globl __cyg_profile_func_enter - .set __cyg_profile_func_enter, __menter - - .globl __cyg_profile_func_exit - .set __cyg_profile_func_exit, __mexit diff --git a/tools/profiler/machine-profile.h b/tools/profiler/machine-profile.h deleted file mode 100644 index 6556c1cdf..000000000 --- a/tools/profiler/machine-profile.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Public, machine-dependent definitions */ - -#ifndef MACHINE_PROFILE_H_INCLUDED -#define MACHINE_PROFILE_H_INCLUDED - -#include <stdint.h> - -/* An integer large enough to hold a data or function pointer. */ -typedef uintptr_t codeptr_t; - -/* An arithmetic used to represent both absolute times - * and (non-negative) deltas. */ -typedef unsigned long long profctr_t; - -#endif diff --git a/tools/profiler/machine-profileP.h b/tools/profiler/machine-profileP.h deleted file mode 100644 index d6ea397d8..000000000 --- a/tools/profiler/machine-profileP.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef MACHINE_PROFILE_PRIVATE_H_INCLUDED -#define MACHINE_PROFILE_PRIVATE_H_INCLUDED - -#include "machine-profile.h" - -extern "C" { - void __attribute((__stdcall__)) __menter_internal (codeptr_t func); - void __attribute((__stdcall__)) __mexit_internal (void); -} -/* Note that we don't issue a serialising instruction (e.g. cpuid) - * before reading the counter. Since we are profiling entire functions, - * it doesn't matter. - * Don't use this to determine how many cycles a single instruction takes. - */ -#define get_timestamp(t) \ - do \ - { \ - __asm__ __volatile__("pushl %%ebx\n" \ - "cpuid\n" \ - "popl %%ebx\n" \ - "rdtsc" \ - : "=A" (t) : : "cx"); \ - } while (0) - -#define update_arc_time(arc_time, delta) \ - do { (arc_time) += (delta); } while (0) - -static inline size_t atomic_inc(volatile size_t *x) -{ - size_t result; - __asm__("lock; xaddl %1, %0" - : "=m" (*x), "=rm" (result) - : "1" (1)); - - return result; -} - -static inline int compare_and_swap(void **dest, void *old, void *_new) -{ - char ret; - unsigned long readval; - - __asm__("lock; cmpxchgl %3, %1; sete %0" - : "=q" (ret), "=m" (*dest), "=a" (readval) - : "r" (_new), "m" (*dest), "a" (old)); - - return ret; -} - -#endif diff --git a/tools/profiler/nautilus-leak-symbol-lookup.C b/tools/profiler/nautilus-leak-symbol-lookup.C deleted file mode 100644 index 02120bae9..000000000 --- a/tools/profiler/nautilus-leak-symbol-lookup.C +++ /dev/null @@ -1,301 +0,0 @@ -/* nautilus-leak-symbol-lookup.C - symbol lookup for a leak checking and profiling - library - - Copyright (C) 2000 Eazel - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Pavel Cisler <pavel@eazel.com> -*/ - -/* Copied from the leakchecker with a few minor tweaks. - * FIXME: need to consolidate this with the leakchecker version and - * only have one copy for both - */ -#define _GNU_SOURCE - /* need this for dladdr */ - -#include "nautilus-leak-symbol-lookup.h" - -#include <bfd.h> -#include <dlfcn.h> -#include <glib.h> -#include <stdio.h> -#include <malloc.h> -#include <unistd.h> -#include <sys/stat.h> - - -static GList *symbol_table_list; - -typedef struct { - char *path; - bfd *abfd; - asymbol **symbol_table; - asection *text_section; - unsigned long start; - unsigned long end; -} NautilusLeakSymbolLookupMap; - -static gboolean -nautilus_leak_find_symbol_in_map (const NautilusLeakSymbolLookupMap *map, - unsigned long address, char **function_name, char **source_file_name, - unsigned int *line) -{ - const char *file; - const char *function; - - address -= map->start; - address -= map->text_section->vma; - - if (address > map->text_section->_cooked_size) { - /* not a valid address range for this binary */ - return FALSE; - } - - if (!bfd_find_nearest_line (map->abfd, map->text_section, map->symbol_table, - address, - &file, &function, line)) { - printf ("error looking up address in binary %s\n", map->path); - return FALSE; - } - if (file == NULL || function == NULL) { - return FALSE; - } - - *function_name = g_strdup (function); - *source_file_name = g_strdup (file); - - return TRUE; -} - -static void -nautilus_leak_symbol_map_get_offsets (NautilusLeakSymbolLookupMap *map) -{ - gchar buffer[1024]; - FILE *in; - gchar perms[26]; - gchar file[256]; - unsigned long start, end; - guint major, minor; - ino_t inode; - struct stat library_stat; - struct stat entry_stat; - int count; - - /* find the library we are looking for in the proc directories - * to find out at which addresses it is mapped - */ - snprintf (buffer, 1023, "/proc/%d/maps", getpid()); - in = fopen (buffer, "r"); - - if (stat (map->path, &library_stat) != 0) { - /* we will use st_ino and st_dev to do a file match */ - return; - } - - while (fgets(buffer, 1023, in)) { - gulong tmp; - - count = sscanf (buffer, "%lx-%lx %15s %*x %u:%u %lu %255s", - &start, &end, perms, &major, &minor, &tmp, file); - inode = tmp; - - if (count >= 6 && strcmp (perms, "r-xp") == 0) { - if (stat (file, &entry_stat) != 0) { - break; - } - /* check if this is the library we are loading */ - if (library_stat.st_ino == entry_stat.st_ino - && library_stat.st_dev == entry_stat.st_dev) { - map->start = start; - map->end = end; - - break; - } - } - } - fclose (in); -} - -static NautilusLeakSymbolLookupMap * -nautilus_leak_symbol_map_load (const char *binary_path, gboolean executable) -{ - NautilusLeakSymbolLookupMap *map; - char *target = NULL; - size_t storage_needed; - int number_of_symbols; - - map = g_new0 (NautilusLeakSymbolLookupMap, 1); - - map->abfd = bfd_openr (binary_path, target); - - if (map->abfd == NULL) { - fprintf (stderr, "%s: ", binary_path); - bfd_perror (binary_path); - return NULL; - } - - if (!bfd_check_format (map->abfd, bfd_object)) { - fprintf (stderr, "%s is not an object file\n", binary_path); - bfd_close (map->abfd); - return NULL; - } - - /* Use the ".text" section. */ - map->text_section = bfd_get_section_by_name (map->abfd, ".text"); - - /* Read the symbol table. */ - storage_needed = bfd_get_symtab_upper_bound (map->abfd); - if (storage_needed == 0) { - fprintf (stderr, "no symbols\n"); - bfd_close (map->abfd); - return NULL; - } - map->symbol_table = (asymbol **)g_malloc (storage_needed); - if (map->symbol_table == NULL) { - fprintf (stderr, "no memory allocating symbol table\n"); - bfd_close (map->abfd); - return NULL; - } - number_of_symbols = bfd_canonicalize_symtab (map->abfd, map->symbol_table); - map->path = g_strdup (binary_path); - - if (!executable) { - nautilus_leak_symbol_map_get_offsets (map); - } - symbol_table_list = g_list_append (symbol_table_list, map); - - return map; -} - -static NautilusLeakSymbolLookupMap * -nautilus_leak_symbol_map_load_if_needed (const char *binary_path, gboolean executable) -{ - GList *p; - NautilusLeakSymbolLookupMap *map; - - for (p = symbol_table_list; p != NULL; p = p->next) { - map = (NautilusLeakSymbolLookupMap *)p->data; - if (strcmp (map->path, binary_path) == 0) - /* no need to load the symbols, already got the map */ - return map; - } - return nautilus_leak_symbol_map_load (binary_path, executable); -} - -void -nautilus_leak_print_symbol_cleanup (void) -{ - /* free the cached symbol tables */ - GList *p; - NautilusLeakSymbolLookupMap *map; - - for (p = symbol_table_list; p != NULL; p = p->next) { - map = (NautilusLeakSymbolLookupMap *)p->data; - bfd_close (map->abfd); - g_free (map->symbol_table); - g_free (map->path); - - g_free (map); - } - - g_list_free (symbol_table_list); - symbol_table_list = NULL; -} - -static gboolean -nautilus_leak_find_symbol_address (void *address, char **function_name, char **source_file_name, - int *line) -{ - GList *p; - NautilusLeakSymbolLookupMap *map; - Dl_info info; - - if (dladdr (address, &info) != 0) { - /* We know the function name and the binary it lives in, now try to find - * the function and the offset. - */ - map = nautilus_leak_symbol_map_load_if_needed (info.dli_fname, false); - - /* temporarily force a dladdr-only lookup. - * should make the bfd symbol lookup work. - */ - if (map != NULL - && nautilus_leak_find_symbol_in_map (map, (long)address, - function_name, source_file_name, (unsigned int *)line)) { - return TRUE; - } - /* just return the function name and the library binary path */ - *function_name = g_strdup (info.dli_sname); - *source_file_name = g_strdup (info.dli_fname); - *line = -1; - return TRUE; - } else { - /* Usually dladdr will succeed, it seems to only fail for - * address lookups for functions in the main binary. - */ - for (p = symbol_table_list; p != NULL; p = p->next) { - map = (NautilusLeakSymbolLookupMap *)p->data; - if (nautilus_leak_find_symbol_in_map (map, (long)address, function_name, - source_file_name, (unsigned int *)line)) - return TRUE; - } - } - - return FALSE; -} - -void -get_function_at_address (const char *app_path, void *address, string &result) -{ - char *function_name; - char *source_file_name; - int line; - - nautilus_leak_symbol_map_load_if_needed (app_path, true); - - if (nautilus_leak_find_symbol_address (address, &function_name, &source_file_name, &line)) { - result = function_name; - - g_free (function_name); - g_free (source_file_name); - } else { - result = "unknown function"; - } -} - -void -nautilus_leak_print_symbol_address (const char *app_path, void *address) -{ - char *function_name; - char *source_file_name; - int line; - - nautilus_leak_symbol_map_load_if_needed (app_path, true); - - if (nautilus_leak_find_symbol_address (address, &function_name, &source_file_name, &line)) { - if (line >= 0) { - printf("%10p %-30s %s:%d\n", address, function_name, source_file_name, line); - } else { - printf("%10p %-30s in library %s\n", address, function_name, source_file_name); - } - g_free (function_name); - g_free (source_file_name); - } else { - printf("%p (unknown function)\n", address); - } -} diff --git a/tools/profiler/nautilus-leak-symbol-lookup.h b/tools/profiler/nautilus-leak-symbol-lookup.h deleted file mode 100644 index 698adf868..000000000 --- a/tools/profiler/nautilus-leak-symbol-lookup.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef NAUTILUS_LEAK_SYMBOL_LOOKUP__ -#define NAUTILUS_LEAK_SYMBOL_LOOKUP__ - -#include <string> - -void nautilus_leak_print_symbol_address (const char *app_path, void *address); -void get_function_at_address (const char *app_path, void *address, string &result); - -#endif diff --git a/tools/profiler/profile.C b/tools/profiler/profile.C deleted file mode 100644 index a54162be9..000000000 --- a/tools/profiler/profile.C +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * Copyright (C) 2000 Eazel - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * adapted for shared library support: - * Pavel Cisler <pavel@eazel.com> - */ - -#define _XOPEN_SOURCE 500 /* for pwrite */ - -/* Define to whatever is needed to declare a stdcall function. */ -#define STDCALL __attribute__((__stdcall__)) - -/* Define to whatever prefix is used on pthread calls. */ -#define PTHREAD_PREFIX pthread_ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <signal.h> -#include <limits.h> -#include <errno.h> - -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/sendfile.h> -#include <fcntl.h> -#include <unistd.h> -#include <pthread.h> - -#include "profileP.h" -#include "machine-profileP.h" -#include "profiledata.h" -#include "totaltime.h" -#include "funcsummary.h" -#include "symbol-table.h" - -/************************************************************************/ - -static enum mstatus status = mstatus_on; - -static size_t maplen; - -static profile_header *header; - -static arc *arc_table; - -static pthread_key_t prof_key; - -static int dev_zero_fd; - -static thread_prof *threads; - -static int profile_map_fd; - -static size_t thread_maplen; - -static const char CPROF_STACK_SIZE[] = "CPROF_STACK_SIZE"; -static const char CPROF_ARC_TABLE_SIZE[] = "CPROF_ARC_TABLE_SIZE"; -static const char CPROF_DUMP_PREFIX[] = "CPROF_DUMP_PREFIX"; - -static size_t stack_size; -static size_t arc_table_size; -static char *dump_prefix; - -/************************************************************************/ - -static void profile_exit(); -static inline arc *allocate_arc(volatile thread_prof *thread, codeptr_t to); - -/* Temporarily installed during determine_frequency(): - * sigsuspend() does not wake up for SIG_IGN signals. */ -static void -alarm_handler(int) -{ -} - - -/* Determine (and return) the number of profctr_t ticks per second. */ -static profctr_t -determine_frequency() -{ - itimerval delay, oldtimer; - timeval tbefore, tafter; - profctr_t before, after, delta; - double elapsed; - void (*old_alarm_handler)(int); - sigset_t sigs; - - /* We steal the SIGALRM handler as well as ITIMER_REAL. This is very - * rude, but unavoidable. */ - - old_alarm_handler = signal(SIGALRM, alarm_handler); - - sigfillset(&sigs); - sigdelset(&sigs, SIGALRM); - sigdelset(&sigs, SIGKILL); /* we aren't allowed to block these */ - sigdelset(&sigs, SIGSTOP); - - /* Set this to whatever you want: we use gettimeofday to determine - * how much time has actually elapsed. */ - delay.it_interval.tv_sec = 0; - delay.it_interval.tv_usec = 0; - delay.it_value.tv_sec = 0; - delay.it_value.tv_usec = 1000000; - - setitimer(ITIMER_REAL, &delay, &oldtimer); - - get_timestamp(before); - gettimeofday(&tbefore, NULL); - - sigsuspend(&sigs); - - get_timestamp(after); - gettimeofday(&tafter, NULL); - - /* In seconds */ - elapsed = tafter.tv_sec - tbefore.tv_sec - + (tafter.tv_usec - tbefore.tv_usec) / 1000000.0; - - delta = after - before; - - signal(SIGALRM, old_alarm_handler); - setitimer(ITIMER_REAL, &oldtimer, &delay); - - return (profctr_t)(delta / elapsed); -} - -static unsigned long -getenv_ul(const char *name, unsigned long defult) -{ - char *value, *endptr; - unsigned long ret; - - value = getenv(name); - if (value == NULL || value[0] == '\0') - return defult; - - ret = strtoul(value, &endptr, 10); - if (*endptr != '\0' || (ret == ULONG_MAX && errno == ERANGE)) - return defult; - - return ret; -} - -static char * -getenv_str(const char *name, const char *defult, int empty_ok) -{ - const char *value = getenv(name); - if (!value || (value[0] == '\0' && !empty_ok)) - value = defult; - - return strdup(value); -} - -static void -load_environment() -{ - stack_size = getenv_ul(CPROF_STACK_SIZE, STACK_SIZE); - arc_table_size = getenv_ul(CPROF_ARC_TABLE_SIZE, ARC_TABLE_SIZE); - dump_prefix = getenv_str(CPROF_DUMP_PREFIX, "cmon.out", 0); -} - -static void -prof_init() -{ - load_environment(); - - maplen = getpagesize() + arc_table_size * sizeof(arc); - thread_maplen = stack_size * sizeof(stack_entry); - - if (pthread_key_create(&prof_key, NULL) != 0) - abort (); - - if (atexit(profile_exit) == -1) - abort (); - - threads = NULL; - - dev_zero_fd = open("/dev/zero", O_RDWR); - if (dev_zero_fd == -1) - abort (); - - profile_map_fd = open(dump_prefix, O_RDWR | O_CREAT | O_NOCTTY | O_TRUNC, 0664); - - if (profile_map_fd == -1) - abort (); - - ftruncate(profile_map_fd, maplen); - - header = (profile_header *)mmap(NULL, maplen, PROT_READ | PROT_WRITE, MAP_SHARED, - profile_map_fd, 0); - if (header == (profile_header *)-1) - abort (); - - arc_table = (arc *)((char *)header + getpagesize()); - - header->magic = CPROF_MAGIC; - gettimeofday(&header->start_time, NULL); - header->frequency = determine_frequency(); - header->num_arcs = arc_table_size; - header->stack_size = stack_size; - header->arc_table_addr = (uintptr_t)arc_table; - header->valid_arcs = 0; - header->num_threads = 0; - - mmap(arc_table + arc_table_size, getpagesize(), PROT_NONE, - MAP_FIXED | MAP_PRIVATE, dev_zero_fd, 0); - -} - -static void -prof_init_if_needed() -{ - static pthread_once_t once_control = PTHREAD_ONCE_INIT; - pthread_once(&once_control, prof_init); -} - - -static thread_prof * -new_thread_profile() -{ - prof_init_if_needed(); - - size_t thread_num = atomic_inc(&header->num_threads); - off_t mapoff = maplen + thread_num * thread_maplen; - - /* We have to extend the file so that it is large enough to hold - * our additional mapping. Normally we'd use ftruncate, but that - * causes concurrency problems: we might accidently shorten the file. */ - char c = 0; - pwrite(profile_map_fd, &c, 1, mapoff + thread_maplen - 1); - - thread_prof *thread = (thread_prof *)mmap(NULL, - stack_size * sizeof(stack_entry), - PROT_READ | PROT_WRITE, MAP_SHARED, profile_map_fd, mapoff); - - if (thread == (thread_prof *)-1) - abort(); - - /* watch the alignment of stacktop. It's ok in 32-bit systems. */ - thread->stacktop - = (stack_entry *)((char *)thread + sizeof(thread_prof)); - - thread->root_arc = allocate_arc(thread, (codeptr_t)NULL); - - thread->root_arc->next = NULL; - thread->root_arc->func_and_children = 0; - thread->root_arc->count = 0; - thread->root_arc->chain = NULL; - - /* Now we have to push a toplevel stack entry, since the rest of - * menter will look at stacktop->current_arc */ - thread->stacktop->current_arc = thread->root_arc; - get_timestamp(thread->stacktop->entry_timestamp); - - thread->pid = getpid(); - - pthread_setspecific(prof_key, thread); - - /* Put us on the linked list of threads. */ - for (;;) { - thread_prof *threads_head = threads; - thread->next = threads_head; - if (compare_and_swap((void **)&threads, threads_head, thread)) - break; - } - - return thread; -} - -static inline arc * -allocate_arc(volatile thread_prof *, codeptr_t to) -{ - arc *result = arc_table + atomic_inc(&header->valid_arcs); - - result->to = to; - - assert(result->func_and_children == 0); - assert(result->count == 0); - assert(result->chain == NULL); - - return result; -} - -static inline arc * -find_arc(volatile thread_prof *thread, arc *from, codeptr_t to) -{ - for (arc *chain = from->chain; chain != NULL; chain = chain->next) - if (chain->to == (codeptr_t)to) - return chain; - - - /* So allocate a new arc, and put it on the head of the chain. */ - arc *newarc = allocate_arc(thread, to); - newarc->next = from->chain; - from->chain = newarc; - - return newarc; -} - -static inline thread_prof * -get_thread_profile() -{ - thread_prof *thread = (thread_prof *)pthread_getspecific(prof_key); - - if (!thread) - thread = new_thread_profile(); - return thread; -} - -static codeptr_t -resolve_shared_library_address (codeptr_t address) -{ - // Detect if we have an actual routine address or an address of a GOT. - // If the latter is the case, follow the address to our routine. - // This only works after the library has been loaded and relocated. - const unsigned char *byte_stream = (const unsigned char *)address; - if (byte_stream[0] == 0xff && byte_stream[1] == 0x25) { - // jmp * - get the real routine address at the - // jump destination - const codeptr_t *indirect_location = *(const codeptr_t **)(byte_stream + 2); - return *indirect_location; - } - return address; -} - -extern "C" void __attribute((__stdcall__)) -__menter_internal (codeptr_t func) -{ - func = resolve_shared_library_address (func); - volatile thread_prof *thread = get_thread_profile(); - volatile stack_entry *stacktop = thread->stacktop; - arc *current_arc = find_arc(thread, stacktop->current_arc, func); - - stacktop++; - - /* Dodge a signal race: We can't bump thread->stacktop until current_arc - * is there or a signal handler will pass a bogus arc to find_arc. */ - stacktop->current_arc = current_arc; - thread->stacktop++; /* should be atomic */ - /* And if a signal came in before thread->stacktop++, it will have - * overwritten stacktop->current_arc, so put it back. */ - stacktop->current_arc = current_arc; - - get_timestamp(stacktop->entry_timestamp); - - if (status == mstatus_on) - current_arc->count++; - -} - -extern "C" void __attribute((__stdcall__)) -__mexit_internal (void) -{ - thread_prof *thread = get_thread_profile(); - volatile stack_entry *stacktop = thread->stacktop; - arc *current_arc = stacktop->current_arc; - - if (status == mstatus_on) { - /* We have to decrement thread->stacktop before reading the timestamp, - * so that any signals that happen after we read the timestamp get - * changed against our parent. Note that we have to read the - * entry_timestamp before decrementing thread->stacktop or a signal - * might overwrite it. - */ - profctr_t entry_timestamp = stacktop->entry_timestamp; - profctr_t delta; - - thread->stacktop--; /* should be atomic */ - get_timestamp(delta); - - delta -= entry_timestamp; - update_arc_time(current_arc->func_and_children, delta); - } else - thread->stacktop--; /* should be atomic */ -} - -void -profile_on() -{ - status = mstatus_on; -} - -void -profile_off() -{ - status = mstatus_off; -} - -/* Due to the evil stride, this is not going to be very fast. */ -void -profile_reset() -{ - mstatus oldstatus = status; - status = mstatus_off; - - const arc *end = arc_table + header->valid_arcs; - for (arc *a = arc_table; a < end; a++) { - a->func_and_children = 0; - a->count = 0; - } - - status = oldstatus; -} - -static void -profile_dump() -{ - try { - FuncSummary::sort_order order = FuncSummary::sort_func; - ProfileData profile(profile_map_fd); - SymbolTable symbols("/gnome/bin/nautilus"); - TotalTime tt(profile); - - FuncSummary fs(profile, symbols, order, tt.total_time()); - fs.Output(cout); - -// GprofStack gs(profile, symbols); -// gs.Output(cout); - -// CallStack cs(profile, symbols); -// cs.Output(cout); - } catch (const exception &e) { - cerr << e.what() << '\n'; - } - catch (...) { - cerr << "Unknown exception\n"; - } - close (profile_map_fd); - unlink (dump_prefix); -} - -static void -profile_exit() -{ - profile_dump(); - printf("profiler done\n"); -} diff --git a/tools/profiler/profile.h b/tools/profiler/profile.h deleted file mode 100644 index 199361ebc..000000000 --- a/tools/profiler/profile.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * Copyright (C) 2000 Eazel - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * adapted for shared library support: - * Pavel Cisler <pavel@eazel.com> - */ - -/* Public definitions for the profiler. */ - -#ifndef PROFILE_H_INCLUDED -#define PROFILE_H_INCLUDED - -#include <stdint.h> - -#include <sys/types.h> -#include <sys/time.h> -#include <unistd.h> - -#include "machine-profile.h" - -enum { CPROF_MAGIC = 0x4e4f4d43 }; - -struct profile_header -{ - uint32_t magic; /* expect CPROF_MAGIC */ - struct timeval start_time; /* time at which the run started */ - struct timeval end_time; /* time at which the run was saved */ - - profctr_t frequency; /* counts per second */ - - size_t num_arcs; /* number of arcs (size of arc table) */ - size_t stack_size; /* size of each thread's stack */ - - size_t valid_arcs; /* number of used arcs - * arcs are used from the start of the table */ - uintptr_t arc_table_addr; /* virtual address of the arc table */ - - size_t num_threads; /* number of threads */ -}; - -struct arc -{ - /* FROM is implicit: each arc is on a linked list that belongs - * to an arc who's TO is our FROM. */ - - codeptr_t to; /* The destination of this arc. */ - struct arc *next; /* The next node in our FROM's linked list. */ - - profctr_t func_and_children; /* Exit - Enter delta */ - size_t count; /* number of times this arc has been traversed */ - struct arc *chain; /* arcs called from the destination of this arc */ -}; - -struct stack_entry -{ - struct arc *current_arc; - profctr_t entry_timestamp; -}; - -struct thread_prof -{ - /* Our stack goes upwards through memory. */ - struct stack_entry *stacktop; - - struct arc *root_arc; - - struct thread_prof *next; - - pid_t pid; -}; - -/* Profiling defaults to on. - * profile_on and profile_off just do the obvious thing. They don't save or - * reset counters. - * - * profile_reset resets all the counters and elapsed times to 0. - * profile_save saves the profiling data to the file named - */ -extern void profile_on(void); -extern void profile_off(void); -extern void profile_reset(void); -extern int profile_save(const char *prefix); - -#endif diff --git a/tools/profiler/profileP.h b/tools/profiler/profileP.h deleted file mode 100644 index 5459acbf9..000000000 --- a/tools/profiler/profileP.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef PROFILE_PRIVATE_H_INCLUDED -#define PROFILE_PRIVATE_H_INCLUDED - -#include "profile.h" - -#define ARC_TABLE_SIZE (16 * 1024 * 1024) /* global */ -#define STACK_SIZE 1024 /* 12k per-thread */ -/* And we put the thread_prof structure onto the stack. */ - -enum mstatus -{ - mstatus_on = 0, - mstatus_off, - mstatus_error -}; - -#ifndef INLINE1 -#define INLINE1 inline -#endif - -#ifndef INLINE2 -#define INLINE2 inline -#endif - -#endif diff --git a/tools/profiler/profiledata.C b/tools/profiler/profiledata.C deleted file mode 100644 index 8bfb50e47..000000000 --- a/tools/profiler/profiledata.C +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "profiledata.h" - -#include <stack> -#include <stdexcept> -#include <cerrno> -#include <cstring> - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <unistd.h> -#include <fcntl.h> - -using namespace std; - -namespace -{ - template <class T, class U> - inline T round_up(T t, U u) - { - return (t + u - 1) & -u; - } - - static void check_result_failure(void) - { - throw runtime_error(strerror(errno)); - } - - static inline void check_result(int res) - { - if (res == -1) - check_result_failure(); - } -} - -void ProfileData::assert_valid_arc_data_ptr(const struct ArcData *p) - const throw() -{ - uintptr_t pu = reinterpret_cast<uintptr_t>(p); - uintptr_t arc_table_u = reinterpret_cast<uintptr_t>(arc_table); - - assert(p == NULL - || (pu >= arc_table_u - && pu < arc_table_u + header->valid_arcs * sizeof(ArcData))); -} - -inline size_t ProfileData::arc_index(const struct arc *a) const throw() -{ - assert(map_arc_table != NULL); - return a - reinterpret_cast<const struct arc *>(arc_table_addr); -} - -inline ProfileData::ArcData *ProfileData::xlate_arc(const struct arc *a) const - throw() -{ - assert(arc_table != NULL); - - return (a == NULL) ? NULL : (arc_table + arc_index(a)); -} - -inline const struct thread_prof *ProfileData::get_thread(size_t i) const - throw() -{ - assert(map_threads != NULL); - assert(i < header->num_threads); - - const struct thread_prof *result = reinterpret_cast<const struct thread_prof *>(reinterpret_cast<uintptr_t>(map_threads) + i * header->stack_size * sizeof(struct stack_entry)); - - assert(static_cast<const void *>(result) < static_cast<char *>(map) + maplen); - - return result; -} - -ProfileData::ProfileData(const char *filename) -{ - map_profile(filename); - try { - load_header(); - load_threads(); - load_arcs(); - } catch (...) { - unmap_profile(); - throw; - } - unmap_profile(); -} - -ProfileData::ProfileData(int file_descriptor) -{ - map_profile(file_descriptor); - try { - load_header(); - load_threads(); - load_arcs(); - } catch (...) { - unmap_profile(); - throw; - } - unmap_profile(); -} - -void ProfileData::map_profile(int file_descriptor) -{ - check_result(file_descriptor); - - struct stat buf; - check_result(fstat(file_descriptor, &buf)); - - maplen = buf.st_size; - map = mmap(NULL, maplen, PROT_READ, MAP_PRIVATE, file_descriptor, 0); - - uintptr_t mapaddr = reinterpret_cast<uintptr_t>(map); - - map_header = static_cast<profile_header *>(map); - map_arc_table = reinterpret_cast<arc *>(mapaddr + getpagesize()); - - map_threads = reinterpret_cast<thread_prof *>(mapaddr + getpagesize() + map_header->num_arcs * sizeof(struct arc)); - - arc_table_addr = map_header->arc_table_addr; -} - -void ProfileData::map_profile(const char *filename) -{ - int fd = open(filename, O_RDONLY | O_NOCTTY); - check_result(fd); - - map_profile(fd); - close(fd); -} - -void ProfileData::unmap_profile(void) -{ - munmap(map, maplen); - - map = NULL; - map_header = NULL; - map_arc_table = NULL; - map_threads = NULL; - arc_table_addr = 0; -} - -void ProfileData::load_header(void) -{ - header = new profile_header; - *header = *map_header; -} - -void ProfileData::load_threads(void) -{ - assert(header != NULL); - assert(map_threads != NULL); - - // We can't really do much as the arc_table has not been created yet. - ThreadData td; - td.root_arc = NULL; - - threads.resize(header->num_threads, td); -} - -// Both implementations do the same thing, but the second uses an -// explicit stack to avoid recursion. -#if 1 -void ProfileData::update_arc_children(ArcData &a) -{ - for (ArcData *c = a.tochain; c != NULL; c = c->next_sibling) { - assert(arc_table <= c && c < arc_table + header->valid_arcs); - - c->from = &a; - c->fromfunc = a.tofunc; - update_arc_children(*c); - } - - // If we never return from a function, we never assign it a F+D - // time. Fake one by adding up the F+D time for all its children. - if (a.time == 0) - for (ArcData *c = a.tochain; c != NULL; c = c->next_sibling) - a.time += c->time; - -} -#else -void ProfileData::update_arc_children(ArcData &a) -{ - typedef stack<ArcData *> arcdata_stack_t; - arcdata_stack_t stack; - - stack.push(&a); - - while (!stack.empty()) { - ArcData *a = stack.top(); - stack.pop(); - - for (ArcData *c = a->tochain; c != NULL; c = c->next_sibling) { - assert(arc_table <= c && c < arc_table + header->valid_arcs); - - c->from = a; - c->fromfunc = a->tofunc; - stack.push(c); - } - } -} -#endif - -// Solely for debugging convenience. -static void *g_arc_table; -static void *g_arc_table_end; - -void ProfileData::load_arcs(void) -{ - size_t narcs = header->valid_arcs; - arc_table = new ArcData[narcs]; - - g_arc_table = arc_table; - g_arc_table_end = arc_table + narcs; - - for (size_t i=0; i < narcs; i++) { - arc_table[i].from = NULL; - arc_table[i].tochain = xlate_arc(map_arc_table[i].chain); - arc_table[i].count = map_arc_table[i].count; - arc_table[i].time = map_arc_table[i].func_and_children; - arc_table[i].next_sibling = xlate_arc(map_arc_table[i].next); - - arc_table[i].fromfunc = (codeptr_t)NULL; - arc_table[i].tofunc = map_arc_table[i].to; - } - -#ifndef NDEBUG - for (size_t i=0; i < narcs; i++) { - assert_valid_arc_data_ptr(arc_table[i].tochain); - assert_valid_arc_data_ptr(arc_table[i].next_sibling); - } -#endif - - // Now fill in the missing ArcData fields by following the child chains. - for (size_t i=0; i < header->num_threads; i++) - threads[i].root_arc = xlate_arc(get_thread(i)->root_arc); - - - if (header->num_threads > 0) { - for (size_t i=0; i < header->num_threads - 1; i++) - threads[i].root_arc->next_sibling = threads[i+1].root_arc; - - threads[header->num_threads-1].root_arc->next_sibling = NULL; - } - - for (size_t i=0; i < header->num_threads; i++) { - update_arc_children(*threads[i].root_arc); - } -} - -ProfileData::~ProfileData() -{ - delete header; - delete[] arc_table; -} - -void -ProfileData::VisitArcs(ArcVisitor *v) const -{ - for (threads_const_iterator i = threads.begin(); i != threads.end(); i++) - VisitArc(v, *i->root_arc); -} - -// This is done in depth-first order, and is defined to always be this way. -void -ProfileData::VisitArc(ArcVisitor *v, const ArcData &a) const -{ - assert(&a != NULL); - assert_valid_arc_data_ptr(&a); - - typedef stack<const ArcData *> arcdata_stack_t; - arcdata_stack_t stack; - - stack.push(&a); - - while (!stack.empty()) { - const ArcData *a = stack.top(); - stack.pop(); - - assert(a != NULL); - assert_valid_arc_data_ptr(a); - - v->visit(*a); - - for (ArcData *c = a->tochain; c != NULL; c = c->next_sibling) { - assert(c != NULL); - assert_valid_arc_data_ptr(c); - - stack.push(c); - } - } -} diff --git a/tools/profiler/profiledata.h b/tools/profiler/profiledata.h deleted file mode 100644 index 16be54b9d..000000000 --- a/tools/profiler/profiledata.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef PROFILEDATA_H_INCLUDED -#define PROFILEDATA_H_INCLUDED - -#include <string> -#include <vector> -#include <iterator> - -#include <stdint.h> - -#include <sys/types.h> -#include <unistd.h> - -#include "profile.h" - -class ProfileData -{ -public: - explicit ProfileData(int file_descriptor); - explicit ProfileData(const char *filename); - virtual ~ProfileData(); - - // These report real-word absolute time and can be used to identify - // the run. If you save multiple times during the same run, they will - // have the same start_time, but different end_times. - inline timeval start_time() const; - inline timeval end_time() const; - - inline profctr_t total_time() const; - - inline profctr_t frequency() const; - - // really valid_arcs, but the outside world shouldn't know that - // unused arcs exist at all - inline size_t num_arcs() const; - - struct ArcData { - ArcData *from, *tochain; - codeptr_t fromfunc, tofunc; - size_t count; - profctr_t time; - ArcData *next_sibling; - }; - - struct ThreadData { - ArcData *root_arc; - }; - - struct ArcVisitor { - virtual void visit(const ArcData &a) = 0; - }; - - void VisitArcs(ArcVisitor *v) const; - - struct const_arc_iterator; - struct arc_iterator { - // SGI STL does not include struct iterator :( - typedef forward_iterator_tag iterator_category; - typedef const ArcData value_type; - typedef ptrdiff_t difference_type; - typedef value_type *pointer; - typedef value_type &reference; - - friend struct const_arc_iterator; - friend class ProfileData; - friend bool operator == (const arc_iterator &, const arc_iterator &); - - arc_iterator() { } - arc_iterator(const arc_iterator &i) : p(i.p) { } - arc_iterator &operator = (const arc_iterator &i) - { - p = i.p; - return *this; - } - - reference operator *() const throw() { return *p; } - pointer operator ->() const throw() { return p; } - - arc_iterator &operator ++ () throw() - { p = p->next_sibling; return *this; } - arc_iterator operator ++ (int) throw() - { - arc_iterator temp(*this); - p = p->next_sibling; - return temp; - } - - private: - explicit arc_iterator(ArcData *_p) : p(_p) { } - static inline arc_iterator end() - { return arc_iterator(NULL); } - - pointer p; - }; - - struct const_arc_iterator { - // SGI STL does not include struct iterator :( - typedef forward_iterator_tag iterator_category; - typedef const ArcData value_type; - typedef ptrdiff_t difference_type; - typedef value_type *pointer; - typedef value_type &reference; - - friend class ProfileData; - friend bool operator == (const const_arc_iterator &, - const const_arc_iterator &); - - const_arc_iterator() throw() { } - const_arc_iterator(const arc_iterator &i) throw() : p(i.p) { } - const_arc_iterator(const const_arc_iterator &i) throw() : p(i.p) { } - - const_arc_iterator &operator = (const arc_iterator &i) throw() - { - p = i.p; - return *this; - } - const_arc_iterator &operator = (const const_arc_iterator &i) throw() - { - p = i.p; - return *this; - } - - reference operator *() const throw() { return *p; } - pointer operator ->() const throw() { return p; } - - const_arc_iterator &operator ++ () throw() - { p = p->next_sibling; return *this; } - const_arc_iterator operator ++ (int) throw() - { - const_arc_iterator temp(*this); - p = p->next_sibling; - return temp; - } - - private: - explicit const_arc_iterator(const ArcData *_p) throw() : p(_p) { } - static inline const arc_iterator end() throw() - { return arc_iterator(NULL); } - - pointer p; - }; - - inline const_arc_iterator begin_children(const ArcData &a) const throw(); - inline const_arc_iterator end_children(const ArcData &a) const throw(); - - inline const_arc_iterator begin_roots() const throw(); - inline const_arc_iterator end_roots() const throw(); - -private: - void VisitArc(ArcVisitor *v, const ArcData &a) const; - - void assert_valid_arc_data_ptr(const ArcData *p) const throw(); - inline size_t arc_index(const struct arc *a) const throw(); - inline ArcData *xlate_arc(const struct arc *a) const throw(); - inline const struct thread_prof *get_thread(size_t i) const throw(); - - void map_profile(const char *filename); - void map_profile(int file_descriptor); - void unmap_profile(); - - void load_header(); - void load_threads(); - void load_arcs(); - void update_arc_children(ArcData &a); - - // These are only valid while the map is active. (i.e. during the ctor) - void *map; // Mmaped cmon.out. - const profile_header *map_header; // profiler_header in map - const arc *map_arc_table; // arc table in map - const thread_prof *map_threads; // first thread in map - size_t maplen; // length of entire map - uintptr_t arc_table_addr; // VA of arc table in profiled program - - profile_header *header; - ArcData *arc_table; - typedef std::vector<ThreadData> threads_list_t; - typedef threads_list_t::iterator threads_iterator; - typedef threads_list_t::const_iterator threads_const_iterator; - threads_list_t threads; - - profctr_t m_total_time; - - // unimplemented - ProfileData(const ProfileData &); - void operator = (const ProfileData &); -}; - -inline timeval -ProfileData::start_time() const -{ - return header->start_time; -} - -inline timeval -ProfileData::end_time() const -{ - return header->end_time; -} - -inline profctr_t -ProfileData::total_time() const -{ - return m_total_time; -} - -inline profctr_t -ProfileData::frequency() const -{ - return header->frequency; -} - -inline size_t -ProfileData::num_arcs() const -{ - return header->valid_arcs; -} - -inline ProfileData::const_arc_iterator -ProfileData::begin_children(const ArcData &a) const throw() -{ - return const_arc_iterator(a.tochain); -} - -inline ProfileData::const_arc_iterator -ProfileData::end_children(const ArcData &) const throw() -{ - return const_arc_iterator::end(); -} - -inline ProfileData::const_arc_iterator -ProfileData::end_roots() - const throw() -{ - return const_arc_iterator::end(); -} - -inline ProfileData::const_arc_iterator -ProfileData::begin_roots() - const throw() -{ - return (header->num_threads > 0) - ? const_arc_iterator(threads[0].root_arc) - : end_roots(); -} - -inline bool -operator == (const ProfileData::arc_iterator &left, - const ProfileData::arc_iterator &right) -{ - return left.p == right.p; -} - -inline bool -operator == (const ProfileData::const_arc_iterator &left, - const ProfileData::const_arc_iterator &right) -{ - return left.p == right.p; -} -#endif diff --git a/tools/profiler/symbol-table.h b/tools/profiler/symbol-table.h deleted file mode 100644 index 99631f5c5..000000000 --- a/tools/profiler/symbol-table.h +++ /dev/null @@ -1,67 +0,0 @@ -/* symbol-table.h - symbol lookup for a leak checking and profiling - library - - Copyright (C) 2000 Eazel - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Pavel Cisler <pavel@eazel.com> -*/ - -#ifndef SYMBOL_TABLE__ -#define SYMBOL_TABLE__ - -#include <string> -#include <stdio.h> -#include "nautilus-leak-symbol-lookup.h" - -#include "profile.h" - -class SymbolTable { -public: - SymbolTable(const char *app_path) - : app_path(app_path) - {} - ~SymbolTable() - {} - - void Lookup (codeptr_t address, string &name) const - { - name = ""; - -#if 1 - char buffer[256]; - sprintf(buffer, "x/i 0x%x ", address); - name = buffer; -#endif - - string function_name; - get_function_at_address (app_path.c_str(), - (void *)address, function_name); - name += function_name; - } - - void LookupExact (codeptr_t address, string &name) const - { - // for now - Lookup(address, name); - } - -private: - string app_path; -}; - -#endif diff --git a/tools/profiler/test.cpp b/tools/profiler/test.cpp deleted file mode 100644 index baf5c1fb9..000000000 --- a/tools/profiler/test.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include <stdio.h> -#include <unistd.h> - -void libcall2(void); -void libcall1(void); -void libcall(void); -void xlibcall(void); - -#ifdef TEST_LIB - - -void -libcall2(void) -{ - xlibcall(); - printf("-\n"); -} - -void -libcall1(void) -{ - libcall2(); -} - -void -libcall(void) -{ - libcall1(); -} - -void -xlibcall(void) -{ -} - -#else - -static int -a() -{ - libcall(); -} - -static int -b() -{ - for (int i = 0; i < 10; i++) - a(); -} - -static int -c() -{ - for (int i = 0; i < 10; i++) { - a(); - b(); - } -} - -static int -d() -{ - libcall(); - for (int i = 0; i < 10; i++) { - a(); - b(); - c(); - } -} - -int -main() -{ - xlibcall(); - //d(); - printf("test done\n"); -} - -#endif
\ No newline at end of file diff --git a/tools/profiler/totaltime.C b/tools/profiler/totaltime.C deleted file mode 100644 index 725f9e367..000000000 --- a/tools/profiler/totaltime.C +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "totaltime.h" - -TotalTime::~TotalTime() -{ -} - -void TotalTime::CountTotalTime(const ProfileData &data) -{ - m_total_time = 0; - for (ProfileData::const_arc_iterator i = data.begin_roots(); - i != data.end_roots(); ++i) - { - m_total_time += i->time; - } -} diff --git a/tools/profiler/totaltime.h b/tools/profiler/totaltime.h deleted file mode 100644 index fcc7e0305..000000000 --- a/tools/profiler/totaltime.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Cprof profiler tool - * (C) Copyright 1999-2000 Corel Corporation - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef TOTALTIME_H_INCLUDED -#define TOTALTIME_H_INCLUDED - -#include "profiledata.h" - -class TotalTime -{ -public: - explicit TotalTime(const ProfileData &data) { CountTotalTime(data); } - virtual ~TotalTime(); - - inline profctr_t total_time(void) const; - -private: - profctr_t m_total_time; - - void CountTotalTime(const ProfileData &data); - - // unimplemented - TotalTime(const TotalTime &); - void operator = (const TotalTime &); -}; - -inline profctr_t TotalTime::total_time(void) const -{ - return m_total_time; -} - -#endif |