1 /*
2 * Copyright (c) 2018, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 #include <fstream>
23 #include "gtest/gtest.h"
24 #include "memory_leak_detector.h"
25
26 using namespace std;
27
Detect(int32_t memNinjaCnt,int32_t memNinjaCntGfx,Platform_t platform)28 void MemoryLeakDetector::Detect(int32_t memNinjaCnt, int32_t memNinjaCntGfx, Platform_t platform)
29 {
30 static bool delReport = true;
31 if (delReport)
32 {
33 remove(MEM_LEAK_REPORT_PATH);
34 delReport = false;
35 }
36
37 if (memNinjaCnt != 0 || memNinjaCntGfx != 0)
38 {
39 const ::testing::TestInfo* curTest = ::testing::UnitTest::GetInstance()->current_test_info();
40 string title(curTest->test_case_name());
41 title = title + "." + curTest->name() + " Platform: " + g_platformName[platform] + " System memory counter: "
42 + to_string(memNinjaCnt) + " Graphic memory counter: "+ to_string(memNinjaCntGfx);
43
44 auto detector = MemoryLeakDetectorIpl::GetInstance();
45 detector->Detect(LOG_PATH);
46 detector->GenerateReport(MEM_LEAK_REPORT_PATH, title);
47 EXPECT_TRUE(false) << "Memory leak detected, system memory counter = " << memNinjaCnt << ", graphic memory counter = "
48 << memNinjaCntGfx << ", platform = " << g_platformName[platform] << endl;
49 }
50
51 remove(LOG_PATH);
52 remove(HLT_PATH);
53 }
54
55 MemoryLeakDetectorIpl *MemoryLeakDetectorIpl::m_instance = nullptr;
56
GetInstance()57 MemoryLeakDetectorIpl *MemoryLeakDetectorIpl::GetInstance()
58 {
59 if (m_instance == nullptr)
60 {
61 m_instance = new MemoryLeakDetectorIpl();
62 }
63
64 return m_instance;
65 }
66
Detect(const string & logPath)67 void MemoryLeakDetectorIpl::Detect(const string &logPath)
68 {
69 m_memPtr.clear();
70 m_memInfoTable.clear();
71
72 ifstream log(logPath);
73 if (!log)
74 {
75 return;
76 }
77
78 string line;
79 while(getline(log, line))
80 {
81 if (line.find("MemNinja leak detection begin") < line.size())
82 {
83 break;
84 }
85 }
86
87 MemInfo memInfo;
88 map<uint64_t, int32_t>::iterator pos;
89 while(getline(log, line))
90 {
91 if (ParseLine(line, memInfo))
92 {
93 if (memInfo.type == MEM_INFO_TYPE_COUNT)
94 {
95 break;
96 }
97
98 uint64_t ptr = stoull(memInfo.ptr, 0, 16);
99 if (memInfo.type == MEM_INFO_TYPE_ALLOC_SYS || memInfo.type == MEM_INFO_TYPE_ALLOC_GFX
100 || (pos = m_memPtr.find(ptr)) == m_memPtr.end())
101 {
102 m_memPtr[ptr] = static_cast<int32_t>(m_memInfoTable.size());
103 }
104 else
105 {
106 m_memPtr.erase(pos);
107 }
108
109 m_memInfoTable.push_back(memInfo);
110 }
111 }
112 }
113
GenerateReport(const string & reportPath,const string & title) const114 void MemoryLeakDetectorIpl::GenerateReport(const string &reportPath, const string &title) const
115 {
116 ofstream report(reportPath, ios_base::app);
117 string line;
118
119 report << title << endl;
120 for (auto it = m_memPtr.cbegin(); it != m_memPtr.cend(); it++)
121 {
122 auto idx = it->second;
123 line = m_memInfoTable[idx].ptr + ", " + m_memInfoTable[idx].functionName + ", "
124 + m_memInfoTable[idx].filename + ", " + m_memInfoTable[idx].line;
125
126 if (m_memInfoTable[idx].type == MEM_INFO_TYPE_ALLOC_SYS || m_memInfoTable[idx].type == MEM_INFO_TYPE_ALLOC_GFX)
127 {
128 line += ", no free, ";
129 }
130 else
131 {
132 line += ", no alloc, ";
133 }
134
135 line += to_string(GetHitNum(idx));
136 TEST_COUT << "Memory leak: " << line << endl;
137 report << line << endl;
138 }
139 report << endl;
140 }
141
ParseLine(const string & line,MemInfo & memInfo) const142 bool MemoryLeakDetectorIpl::ParseLine(const string &line, MemInfo &memInfo) const
143 {
144 if (line.find("MemNinjaSysAlloc") < line.size())
145 {
146 memInfo.type = MEM_INFO_TYPE_ALLOC_SYS;
147 }
148 else if (line.find("MemNinjaGfxAlloc") < line.size())
149 {
150 memInfo.type = MEM_INFO_TYPE_ALLOC_GFX;
151 }
152 else if (line.find("MemNinjaSysFree") < line.size())
153 {
154 memInfo.type = MEM_INFO_TYPE_FREE_SYS;
155 }
156 else if (line.find("MemNinjaGfxFree") < line.size())
157 {
158 memInfo.type = MEM_INFO_TYPE_FREE_GFX;
159 }
160 else if (line.find("MemNinja leak detection end") < line.size())
161 {
162 memInfo.type = MEM_INFO_TYPE_COUNT;
163 return true;
164 }
165 else
166 {
167 return false;
168 }
169
170 auto beg = line.find("memPtr = ");
171 beg += strlen("memPtr = ");
172 auto end = line.find(",", beg);
173 memInfo.ptr = line.substr(beg, end - beg);
174
175 beg = line.find("functionName = \"");
176 beg += strlen("functionName = \"");
177 end = line.find("\"", beg);
178 memInfo.functionName = line.substr(beg, end - beg);
179
180 beg = line.find("filename = \"");
181 beg += strlen("filename = \"");
182 end = line.find("\"", beg);
183 memInfo.filename = line.substr(beg, end - beg);
184
185 beg = line.find("line = ");
186 beg += strlen("line = ");
187 end = line.find("/", beg);
188 memInfo.line = line.substr(beg, end - beg);
189
190 return true;
191 }
192
GetHitNum(int32_t idx) const193 uint32_t MemoryLeakDetectorIpl::GetHitNum(int32_t idx) const
194 {
195 uint32_t hitNum = 1;
196 for (int32_t i = idx - 1; i >= 0; i--)
197 {
198 if (m_memInfoTable[i].filename == m_memInfoTable[idx].filename
199 && m_memInfoTable[i].line == m_memInfoTable[idx].line)
200 {
201 ++hitNum;
202 }
203 }
204
205 return hitNum;
206 }
207