Index: src/LinuxMallocProfiling.cpp |
diff --git a/src/LinuxMallocProfiling.cpp b/src/LinuxMallocProfiling.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..61b123384e5ee162a7866be67065528e3ee82bd2 |
--- /dev/null |
+++ b/src/LinuxMallocProfiling.cpp |
@@ -0,0 +1,106 @@ |
+//===- subzero/src/LinuxMallocProfiling.cpp - malloc/new tracing ---------===// |
+// |
+// The Subzero Code Generator |
+// |
+// This file is distributed under the University of Illinois Open Source |
+// License. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+/// |
+/// \file |
+/// \brief malloc/new/...caller tracing. |
+/// |
+//===----------------------------------------------------------------------===// |
+ |
+#include "LinuxMallocProfiling.h" |
+ |
+#ifdef ALLOW_LINUX_MALLOC_PROFILE |
Jim Stichnoth
2016/03/17 20:09:06
I would be happier with a blank line before and af
sehr
2016/03/17 20:58:21
Done.
|
+#include <dlfcn.h> |
+#include <malloc.h> |
+#include <unordered_map> |
+ |
+extern "C" void *__libc_malloc(size_t size); |
+ |
+namespace { |
+// The Callers structure allocates memory, which would perturb the tracing. |
+// InAllocatorFunction is true when we are tracing a new/malloc/... |
+bool InAllocatorFunction = false; |
+ |
+// Keep track of the number of times a particular call site address invoked |
+// an allocator. NOTE: this is not thread safe, so the user must invoke with |
+// --threads=0 to enable profiling. |
+using MallocMap = std::unordered_map<void *, uint64_t>; |
+MallocMap *Callers; |
+ |
+void *internalAllocator(size_t size, void *caller) { |
+ if (Callers != nullptr && !InAllocatorFunction) { |
+ InAllocatorFunction = true; |
+ ++(*Callers)[caller]; |
+ InAllocatorFunction = false; |
+ } |
+ return __libc_malloc(size); |
+} |
+} // end of anonymous namespace |
+ |
+// new, new[], and malloc are all defined as weak symbols to allow them |
Jim Stichnoth
2016/03/17 20:09:05
reflow comment to 80-col
sehr
2016/03/17 20:58:21
Done.
|
+// to be overridden by user code. This gives us a convenient place to hook |
+// allocation tracking, to record the IP of the caller, which we get from the |
+// call to __builtin_return_address. |
+void *operator new(size_t size) { |
+ void *caller = __builtin_return_address(0); |
+ return internalAllocator(size, caller); |
+} |
+ |
+void *operator new[](size_t size) { |
+ void *caller = __builtin_return_address(0); |
+ return internalAllocator(size, caller); |
+} |
+ |
+extern "C" void *malloc(size_t size) { |
+ void *caller = __builtin_return_address(0); |
+ return internalAllocator(size, caller); |
+} |
+ |
+namespace Ice { |
+ |
+LinuxMallocProfiling::LinuxMallocProfiling(size_t NumThreads, Ostream *Ls) |
+ : Ls(Ls) { |
+ if (NumThreads != 0) { |
+ *Ls << "NOTE: Malloc profiling is not thread safe. " |
+ << "Use --threads=0 to enable.\n"; |
Jim Stichnoth
2016/03/17 20:09:06
Tiny nit: omit the last "<<" and take advantage of
sehr
2016/03/17 20:58:21
Done.
|
+ return; |
+ } |
+ Callers = new MallocMap(); |
+} |
+ |
+LinuxMallocProfiling::~LinuxMallocProfiling() { |
+ if (Callers == nullptr) { |
+ return; |
+ } |
+ for (const auto &C : *Callers) { |
+ Dl_info dli; |
+ dladdr(C.first, &dli); |
+ |
+ *Ls << C.second << " "; |
+ if (dli.dli_sname == NULL) { |
+ *Ls << C.first; |
+ } else { |
+ *Ls << dli.dli_sname; |
+ } |
+ *Ls << "\n"; |
+ } |
+ delete Callers; |
+ Callers = nullptr; |
+} |
+} // end of namespace Ice |
+#else // !ALLOW_LINUX_MALLOC_PROFILE |
+namespace Ice { |
+ |
+LinuxMallocProfiling::LinuxMallocProfiling(size_t NumThreads, Ostream *Ls) { |
+ (void)NumThreads; |
+ (void)Ls; |
+} |
+ |
+LinuxMallocProfiling::~LinuxMallocProfiling() {} |
+} // end of namespace Ice |
+#endif // ALLOW_LINUX_MALLOC_PROFILE |