Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "LeakChecker.h"
     18 
     19 #include "TestUtils.h"
     20 
     21 #include <memunreachable/memunreachable.h>
     22 #include <unistd.h>
     23 #include <cstdio>
     24 #include <iostream>
     25 #include <unordered_set>
     26 
     27 using namespace std;
     28 
     29 namespace android {
     30 namespace uirenderer {
     31 namespace test {
     32 
     33 static void logUnreachable(initializer_list<UnreachableMemoryInfo> infolist) {
     34     // merge them all
     35     UnreachableMemoryInfo merged;
     36     unordered_set<uintptr_t> addrs;
     37     merged.allocation_bytes = 0;
     38     merged.leak_bytes = 0;
     39     merged.num_allocations = 0;
     40     merged.num_leaks = 0;
     41     for (auto& info : infolist) {
     42         // We'll be a little hazzy about these ones and just hope the biggest
     43         // is the most accurate
     44         merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes);
     45         merged.num_allocations = max(merged.num_allocations, info.num_allocations);
     46         for (auto& leak : info.leaks) {
     47             if (addrs.find(leak.begin) == addrs.end()) {
     48                 merged.leaks.push_back(leak);
     49                 merged.num_leaks++;
     50                 merged.leak_bytes += leak.size;
     51                 addrs.insert(leak.begin);
     52             }
     53         }
     54     }
     55 
     56     // Now log the result
     57     if (merged.num_leaks) {
     58         cout << endl << "Leaked memory!" << endl;
     59         if (!merged.leaks[0].backtrace.num_frames) {
     60             cout << "Re-run with 'export LIBC_DEBUG_MALLOC_OPTIONS=backtrace' to get backtraces"
     61                  << endl;
     62         }
     63         cout << merged.ToString(false);
     64     }
     65 }
     66 
     67 void LeakChecker::checkForLeaks() {
     68     // TODO: Until we can shutdown the RT thread we need to do this in
     69     // two passes as GetUnreachableMemory has limited insight into
     70     // thread-local caches so some leaks will not be properly tagged as leaks
     71     UnreachableMemoryInfo rtMemInfo;
     72     TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) {
     73         // Check for leaks
     74         if (!GetUnreachableMemory(rtMemInfo)) {
     75             cerr << "Failed to get unreachable memory!" << endl;
     76             return;
     77         }
     78     });
     79     UnreachableMemoryInfo uiMemInfo;
     80     if (!GetUnreachableMemory(uiMemInfo)) {
     81         cerr << "Failed to get unreachable memory!" << endl;
     82         return;
     83     }
     84     logUnreachable({rtMemInfo, uiMemInfo});
     85 }
     86 
     87 } /* namespace test */
     88 } /* namespace uirenderer */
     89 } /* namespace android */
     90