+/***************************************************************************
+ * Installs handlers for malloc(), realloc() and free() *
+ * *
+ * Copyright (C) 2006 by Niko Välimäki *
+ * *
+ * *
+ * 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., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "HeapProfiler.h"
+
+// Static data
+unsigned long HeapProfiler::consumption = 0, HeapProfiler::maxConsumption = 0;
+AllocatedBlocks HeapProfiler::blocks;
+
+// Override initialising hook from the C library.
+void (*__malloc_initialize_hook) (void) = HeapProfiler::InitHooks;
+
+// Variables to save original hooks.
+void *(*HeapProfiler::old_malloc_hook)(size_t, const void *);
+void (*HeapProfiler::old_free_hook)(void *, const void *);
+void *(*HeapProfiler::old_realloc_hook)(void *, size_t, const void *);
+
+unsigned long HeapProfiler::GetMaxHeapConsumption() {
+ return maxConsumption;
+}
+
+unsigned long HeapProfiler::GetHeapConsumption() {
+ return consumption;
+}
+
+void HeapProfiler::InitHooks(void) {
+ old_malloc_hook = __malloc_hook;
+ old_free_hook = __free_hook;
+ old_realloc_hook = __realloc_hook;
+ __malloc_hook = HeapProfiler::MallocHook;
+ __free_hook = HeapProfiler::FreeHook;
+ __realloc_hook = HeapProfiler::ReallocHook;
+}
+
+
+void *HeapProfiler::MallocHook (size_t size, const void *caller) {
+ void *result;
+
+ /* Restore all old hooks */
+ __malloc_hook = old_malloc_hook;
+ __free_hook = old_free_hook;
+ __realloc_hook = old_realloc_hook;
+
+ /* Call recursively */
+ result = malloc (size);
+
+ blocks[result] = (unsigned long)size;
+
+ consumption += (unsigned long)size;
+ if (consumption > maxConsumption)
+ maxConsumption = consumption;
+
+ #ifdef DEBUG_HEAPPROFILER
+ std::cout << "malloc(" << size << ") called from " << caller << " returns " << result << " (" << consumption << ", max " << maxConsumption << ")" << std::endl;
+ #endif
+
+ /* Save underlying hooks */
+ old_malloc_hook = __malloc_hook;
+ old_free_hook = __free_hook;
+ old_realloc_hook = __realloc_hook;
+
+ /* Restore our own hooks */
+ __malloc_hook = HeapProfiler::MallocHook;
+ __free_hook = HeapProfiler::FreeHook;
+ __realloc_hook = HeapProfiler::ReallocHook;
+
+ return result;
+}
+
+void HeapProfiler::FreeHook (void *ptr, const void *caller) {
+
+ /* Restore all old hooks */
+ __malloc_hook = old_malloc_hook;
+ __free_hook = old_free_hook;
+ __realloc_hook = old_realloc_hook;
+
+ /* Call recursively */
+ free (ptr);
+
+ AllocatedBlocks::iterator result = blocks.find(ptr);
+ if (result != blocks.end())
+ {
+ #ifdef DEBUG_HEAPPROFILER
+ std::cout << "found: " << (*result).second << std::endl;
+ #endif
+ consumption -= (*result).second;
+ blocks.erase(result);
+ } else {
+ #ifdef DEBUG_HEAPPROFILER
+ std::cout << "not found" << std::endl;
+ #endif
+ }
+
+ #ifdef DEBUG_HEAPPROFILER
+ std::cout << "free(" << ptr << ") called from " << caller << " (" << consumption << ", max " << maxConsumption << ")" << std::endl;
+ #endif
+
+ /* Save underlying hooks */
+ old_malloc_hook = __malloc_hook;
+ old_free_hook = __free_hook;
+ old_realloc_hook = __realloc_hook;
+
+ /* Restore our own hooks */
+ __malloc_hook = HeapProfiler::MallocHook;
+ __free_hook = HeapProfiler::FreeHook;
+ __realloc_hook = HeapProfiler::ReallocHook;
+}
+
+
+void *HeapProfiler::ReallocHook (void *ptr, size_t size, const void *caller) {
+ void *newptr;
+
+ /* Restore all old hooks */
+ __malloc_hook = old_malloc_hook;
+ __free_hook = old_free_hook;
+ __realloc_hook = old_realloc_hook;
+
+ /* Call recursively */
+ newptr = realloc(ptr, size);
+
+ AllocatedBlocks::iterator result = blocks.find(ptr);
+ if (result != blocks.end())
+ {
+ #ifdef DEBUG_HEAPPROFILER
+ std::cout << "found: " << (*result).second << std::endl;
+ #endif
+ consumption -= (*result).second;
+ blocks.erase(result);
+ } else {
+ #ifdef DEBUG_HEAPPROFILER
+ std::cout << "not found" << std::endl;
+ #endif
+ }
+
+ blocks[newptr] = (unsigned long)size;
+ consumption += (unsigned long)size;
+ if (consumption > maxConsumption)
+ maxConsumption = consumption;
+
+ #ifdef DEBUG_HEAPPROFILER
+ std::cout << "realloc(" << ptr << ", " << size << ") called from " << caller << ", result " << newptr << " (" << consumption << ", max " << maxConsumption << ")" << std::endl;
+ #endif
+
+ /* Save underlying hooks */
+ old_malloc_hook = __malloc_hook;
+ old_free_hook = __free_hook;
+ old_realloc_hook = __realloc_hook;
+
+ /* Restore our own hooks */
+ __malloc_hook = HeapProfiler::MallocHook;
+ __free_hook = HeapProfiler::FreeHook;
+ __realloc_hook = HeapProfiler::ReallocHook;
+
+ return newptr;
+}
+