stackstash.c
来自「memprof source code, linux」· C语言 代码 · 共 316 行
C
316 行
/* -*- mode: C; c-file-style: "linux" -*- *//* MemProf -- memory profiler and leak detector * Copyright 1999, 2000, 2001, 2002, Red Hat, Inc. * Copyright 2002, Kristian Rietveld * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//*====*/#include <stdlib.h>#include <glib.h>#include "stackstash.h"/* #define BUILD_TEST_CASE */#ifdef BUILD_TEST_CASEstatic size_t test_unique_bytes = 0;static size_t test_bytes_used = 0;static int test_nodes_used = 0;static int test_n_singletons = 0;#endifstruct _StackStash { StackElement *root;};static StackElement *stack_element_new (void){ StackElement *element = g_new (StackElement, 1); element->n_children = 0; element->children = NULL;#ifdef BUILD_TEST_CASE test_bytes_used += sizeof (StackElement); test_nodes_used++;#endif return element;}static voidstack_element_free (StackElement *element){#ifdef BUILD_TEST_CASE test_bytes_used -= element->n_children * sizeof (StackElement *); test_bytes_used -= sizeof (StackElement); test_nodes_used--;#endif g_free (element->children); g_free (element);}static voidinsert_child (StackElement *element, StackElement *child){ StackElement **old_children; StackElement **old_child, **new_child; int n_children = element->n_children; element->n_children = n_children + 1; old_children = element->children; element->children = g_new (StackElement *, n_children + 1); old_child = old_children; new_child = element->children; while (n_children && (*old_child)->address < child->address) { *new_child++ = *old_child++; n_children--; } *new_child++ = child; while (n_children) { *new_child++ = *old_child++; n_children--; } g_free (old_children);#ifdef BUILD_TEST_CASE if (element->n_children == 1) test_n_singletons++; else if (element->n_children == 2) test_n_singletons--; test_bytes_used += sizeof (StackElement *);#endif}StackStash *stack_stash_new (void){ StackStash *stash = g_new (StackStash, 1); stash->root = stack_element_new (); stash->root->parent = NULL; stash->root->address = NULL; return stash;}StackElement *stack_stash_store (StackStash *stash, gpointer *addresses, int n_addresses){ StackElement *current; current = stash->root; while (n_addresses) { int first = 0; int last = current->n_children; gpointer address = addresses[n_addresses - 1]; while (first < last) { int mid = (first + last) / 2; if (address == current->children[mid]->address) { current = current->children[mid]; goto next_address; } else if (address < current->children[mid]->address) { last = mid; } else first = mid + 1; } break; next_address: n_addresses--; } while (n_addresses) { StackElement *next = stack_element_new (); next->address = addresses[n_addresses - 1]; next->parent = current; insert_child (current, next); current = next; n_addresses--; } return current;}static voidfree_element_recurse (StackElement *element){ int i; for (i = 0; i < element->n_children; i++) free_element_recurse (element->children[i]); stack_element_free (element);}voidstack_stash_free (StackStash *stash){ free_element_recurse (stash->root); g_free (stash);}#ifdef BUILD_TEST_CASEguintstack_trace_hash (const void *trace){ guint result = 0; const guint32 *p = trace; guint32 n_elements = *p; while (n_elements--) { p++; result ^= *p; } return result;}gbooleanstack_trace_equal (const void *trace_a, const void *trace_b){ const guint32 *p = trace_a; const guint32 *q = trace_b; guint32 n_elements = *p; if (n_elements != *q) return FALSE; while (n_elements--) { p++; q++; if (*p != *q) return FALSE; } return TRUE;}void *stack_trace_copy (const void *trace){ size_t n_bytes = sizeof (guint32) * (1 + *(guint32 *)trace); test_unique_bytes += n_bytes; return g_memdup (trace, n_bytes);}int main (void){ char *bytes; guint32 *p; size_t len; GError *err = NULL; int n_traces, i; StackStash *stash; StackElement **traces; int n_unique = 0;; GHashTable *unique_hash = g_hash_table_new_full (stack_trace_hash, stack_trace_equal, (GDestroyNotify)g_free, NULL); GTimer *timer = g_timer_new (); if (!g_file_get_contents ("stacktrace.test", &bytes, &len, &err)) { g_message ("Cannot read stracktrace.test: %s\n", err->message); exit (1); } /* Count the number of stacktraces */ g_timer_start (timer); n_traces = 0; p = (guint32 *)bytes; while (p < (guint32 *)(bytes + len)) { guint32 n_elements = *p; if (!g_hash_table_lookup (unique_hash, p)) { g_hash_table_insert (unique_hash, stack_trace_copy (p), GUINT_TO_POINTER (1)); n_unique++; } p += n_elements + 1; n_traces++; } g_timer_stop (timer); g_print ("Preparation took %g seconds\n", g_timer_elapsed (timer, NULL)); traces = g_new (StackElement *, n_traces); /* Insert them all */ g_timer_start (timer); stash = stack_stash_new (); p = (guint32 *)bytes; for (i = 0; i < n_traces; i++) { guint32 n_elements = *p; p++; traces[i] = stack_stash_store (stash, (gpointer *)p, n_elements); p += n_elements; } g_timer_stop (timer); g_print ("Inserted %d stacktraces, %zd bytes (unique: %d/%zd):\n\t%g seconds, using %zd bytes, %d nodes, %d nodes with one child\n", n_traces, len, n_unique, test_unique_bytes, g_timer_elapsed (timer, NULL), test_bytes_used, test_nodes_used, test_n_singletons); /* Now verify the inserted traces */ p = (guint32 *)bytes; for (i = 0; i < n_traces; i++) { StackElement *tmp_element = traces[i]; guint32 n_elements = *p; p++; while (n_elements--) { g_assert (tmp_element->address == *(gpointer *)p); g_assert (tmp_element->parent); tmp_element = tmp_element->parent; p++; } g_assert (!tmp_element->parent); } g_free (traces); stack_stash_free (stash); g_hash_table_destroy (unique_hash); g_free (bytes); g_timer_destroy (timer); return 0;}#endif /* BUILD_TEST_CASE */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?