file_progress fix
[libtorrent.git] / src / memdebug.cpp
blobbdc5aa3f2f8fcb7cce12f8830d8e3f9dda39b908
1 /*
3 Copyright (c) 2007, Arvid Norberg
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
33 #if defined __linux__ && defined __GNUC__
34 #include <execinfo.h>
36 // Prototypes for __malloc_hook, __free_hook
37 #include <malloc.h>
38 #include <boost/array.hpp>
39 #include <fstream>
40 #include <utility>
41 #include <map>
42 #include <boost/cstdint.hpp>
43 #include <boost/multi_index_container.hpp>
44 #include <boost/thread/mutex.hpp>
45 #include "libtorrent/time.hpp"
46 #include "libtorrent/assert.hpp"
48 using boost::multi_index_container;
49 using namespace boost::multi_index;
50 using libtorrent::time_now;
52 struct memdebug
54 memdebug()
56 malloc_log.open("memory.log");
57 malloc_index_log.open("memory_index.log");
59 assert(old_malloc_hook == 0);
60 assert(old_free_hook == 0);
61 old_malloc_hook = __malloc_hook;
62 old_free_hook = __free_hook;
63 __malloc_hook = my_malloc_hook;
64 __free_hook = my_free_hook;
67 static void my_free_hook(void *ptr, const void *caller);
68 static void* my_malloc_hook(size_t size, const void *caller);
70 static boost::mutex mutex;
71 static std::ofstream malloc_log;
72 static std::ofstream malloc_index_log;
74 // the original library functions
75 static void* (*old_malloc_hook)(size_t, const void *);
76 static void (*old_free_hook)(void*, const void *);
78 struct allocation_point_t
80 allocation_point_t()
81 : allocated(0)
82 , peak_allocated(0)
83 , spacetime(0)
84 , last_update(time_now()) {}
86 int index;
87 // total number of bytes allocated from this point
88 int allocated;
89 // the maximum total number of bytes allocated
90 // from this point
91 int peak_allocated;
92 // total number of bytes allocated times the number of
93 // milliseconds they were allocated from this point
94 boost::int64_t spacetime;
95 // the last malloc or free operation on
96 // this allocation point. The spacetime
97 // should be updated from this point to
98 // the current operation
99 libtorrent::ptime last_update;
102 typedef boost::array<void*, 15> stacktrace_t;
103 typedef std::map<stacktrace_t, allocation_point_t> allocation_map_t;
104 static allocation_map_t allocation_points;
105 static std::map<void*, std::pair<allocation_map_t::iterator, int> > allocations;
106 static int allocation_point_index;
107 static libtorrent::ptime start_time;
110 boost::mutex memdebug::mutex;
111 int memdebug::allocation_point_index = 0;
112 std::ofstream memdebug::malloc_log;
113 std::ofstream memdebug::malloc_index_log;
114 void* (*memdebug::old_malloc_hook)(size_t, const void *) = 0;
115 void (*memdebug::old_free_hook)(void*, const void *) = 0;
116 memdebug::allocation_map_t memdebug::allocation_points;
117 std::map<void*, std::pair<memdebug::allocation_map_t::iterator, int> > memdebug::allocations;
118 libtorrent::ptime memdebug::start_time = time_now();
120 void* memdebug::my_malloc_hook(size_t size, const void *caller)
122 boost::mutex::scoped_lock l(mutex);
123 /* Restore all old hooks */
124 __malloc_hook = old_malloc_hook;
125 __free_hook = old_free_hook;
126 /* Call recursively */
127 void* result = malloc(size);
128 /* Save underlying hooks */
129 old_malloc_hook = __malloc_hook;
130 old_free_hook = __free_hook;
132 stacktrace_t stack;
133 int stacksize = backtrace(&stack[0], stack.size());
134 libtorrent::ptime now = time_now();
136 allocation_map_t::iterator i = allocation_points.lower_bound(stack);
137 if (i == allocation_points.end() || i->first != stack)
139 i = allocation_points.insert(i, std::make_pair(stack, allocation_point_t()));
140 i->second.index = allocation_point_index++;
141 i->second.allocated = size;
143 malloc_index_log << i->second.index << "#";
144 char** symbols = backtrace_symbols(&stack[0], stacksize);
145 for (int j = 2; j < stacksize; ++j)
146 malloc_index_log << demangle(symbols[j]) << "#";
147 malloc_index_log << std::endl;
149 else
151 allocation_point_t& ap = i->second;
152 ap.spacetime += libtorrent::total_milliseconds(now - ap.last_update) * ap.allocated;
153 ap.allocated += size;
154 if (ap.allocated > ap.peak_allocated) ap.peak_allocated = ap.allocated;
155 ap.last_update = now;
157 allocation_point_t& ap = i->second;
159 allocations[result] = std::make_pair(i, size);
160 malloc_log << "#" << ap.index << " "
161 << libtorrent::total_milliseconds(time_now() - start_time) << " A "
162 << result << " " << size << " " << ap.allocated << " " << ap.spacetime
163 << " " << ap.peak_allocated << std::endl;
165 /* Restore our own hooks */
166 __malloc_hook = my_malloc_hook;
167 __free_hook = my_free_hook;
168 return result;
171 void memdebug::my_free_hook(void *ptr, const void *caller)
173 boost::mutex::scoped_lock l(mutex);
174 /* Restore all old hooks */
175 __malloc_hook = old_malloc_hook;
176 __free_hook = old_free_hook;
177 /* Call recursively */
178 free(ptr);
179 /* Save underlying hooks */
180 old_malloc_hook = __malloc_hook;
181 old_free_hook = __free_hook;
183 std::map<void*, std::pair<allocation_map_t::iterator, int> >::iterator i
184 = allocations.find(ptr);
186 if (i != allocations.end())
188 allocation_point_t& ap = i->second.first->second;
189 int size = i->second.second;
190 ap.allocated -= size;
191 malloc_log << "#" << ap.index << " "
192 << libtorrent::total_milliseconds(time_now() - start_time) << " F "
193 << ptr << " " << size << " " << ap.allocated << " " << ap.spacetime
194 << " " << ap.peak_allocated << std::endl;
196 allocations.erase(i);
199 /* Restore our own hooks */
200 __malloc_hook = my_malloc_hook;
201 __free_hook = my_free_hook;
204 static int ref_count = 0;
206 void start_malloc_debug()
208 boost::mutex::scoped_lock l(memdebug::mutex);
209 static memdebug mi;
210 ++ref_count;
213 void stop_malloc_debug()
215 boost::mutex::scoped_lock l(memdebug::mutex);
216 if (--ref_count == 0)
218 __malloc_hook = memdebug::old_malloc_hook;
219 __free_hook = memdebug::old_free_hook;
223 #endif