xref: /aosp_15_r20/external/intel-media-driver/media_driver/linux/ult/ult_app/memory_leak_detector.cpp (revision ba62d9d3abf0e404f2022b4cd7a85e107f48596f)
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