forked from Samsung/gcutil
-
Notifications
You must be signed in to change notification settings - Fork 0
/
LeakChecker.cpp
103 lines (86 loc) · 3.29 KB
/
LeakChecker.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "GCUtil.h"
#include "LeakChecker.h"
#ifdef PROFILE_BDWGC
#include <sys/time.h>
#include <sys/resource.h>
namespace GCUtil {
std::string HeapUsageVisualizer::m_outputFile = "bdwgcUsage.dat";
size_t GCLeakChecker::m_totalFreed = 0;
std::vector<GCLeakChecker::LeakCheckedAddr> GCLeakChecker::m_leakCheckedAddrs;
static std::string s_gcLogPhaseName = "initial phase";
void HeapUsageVisualizer::initialize()
{
remove(HeapUsageVisualizer::m_outputFile.c_str());
FILE* fp = fopen(HeapUsageVisualizer::m_outputFile.c_str(), "a");
if (fp) {
fprintf(fp, "GC_no PeakRSS TotalHeap Marked # Phase\n");
fclose(fp);
}
GC_add_event_callback([](GC_EventType evtType, void*) {
if (GC_EVENT_RECLAIM_START == evtType) {
GC_dump_for_graph(HeapUsageVisualizer::m_outputFile.c_str(),
s_gcLogPhaseName.c_str());
}
}, nullptr);
}
void GCLeakChecker::registerAddress(void* ptr, std::string description)
{
RELEASE_ASSERT(ptr);
m_leakCheckedAddrs.push_back(LeakCheckedAddr{ (void*)((size_t)ptr + 1), description, false });
printf("GCLeakChecker::registerAddress %p (%zu - %zu = %zu)\n", ptr,
m_leakCheckedAddrs.size(), m_totalFreed, m_leakCheckedAddrs.size() - m_totalFreed);
GC_REGISTER_FINALIZER_NO_ORDER(ptr, [](void* obj, void* cd) {
GCLeakChecker::unregisterAddress(obj);
},
NULL, NULL, NULL);
}
void GCLeakChecker::unregisterAddress(void* ptr)
{
RELEASE_ASSERT(ptr);
m_totalFreed++;
printf("GCLeakChecker::unregisterAddress %p (%zu - %zu = %zu)\n", ptr,
m_leakCheckedAddrs.size(), m_totalFreed, m_leakCheckedAddrs.size() - m_totalFreed);
for (auto& it : m_leakCheckedAddrs) {
if (it.ptr == (void*)((size_t)ptr + 1)) {
it.deallocated = true;
return;
}
}
RELEASE_ASSERT_NOT_REACHED();
}
void GCLeakChecker::dumpBackTrace(const char* phase)
{
if (phase)
s_gcLogPhaseName = phase;
#ifdef GC_DEBUG
auto stream = stderr;
fprintf(stderr, "GCLeakChecker::dumpBackTrace %s start >>>>>>>>>>\n", s_gcLogPhaseName.c_str());
GC_gcollect();
for (const auto& it : m_leakCheckedAddrs) {
if (it.deallocated) {
fprintf(stderr, "%s (%p) deallocated\n", it.description.c_str(), (void*)((size_t)it.ptr - 1));
} else {
fprintf(stderr, "Backtrace of %s (%p):\n", it.description.c_str(), (void*)((size_t)it.ptr - 1));
GC_print_backtrace((void*)((size_t)it.ptr - 1));
}
}
fprintf(stderr, "GCLeakChecker::dumpBackTrace %s end <<<<<<<<<<\n", s_gcLogPhaseName.c_str());
#else
fprintf(stderr, "Cannot print the backtrace of leaked address.\n");
fprintf(stderr, "Please re-configure bdwgc with `--enable-gc-debug`, ");
fprintf(stderr, "and re-build escargot with `-DGC_DEBUG`.\n");
for (const auto& it : m_leakCheckedAddrs) {
if (it.deallocated) {
fprintf(stderr, "%s (%p) deallocated\n", it.description.c_str(), (void*)((size_t)it.ptr - 1));
} else {
fprintf(stderr, "%s (%p) still allocated\n", it.description.c_str(), (void*)((size_t)it.ptr - 1));
}
}
#endif
}
void GCLeakChecker::setGCPhaseName(std::string name)
{
s_gcLogPhaseName = name;
}
}
#endif // PROFILE_BDWGC