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 "Caches.h"
     20 #include "TestUtils.h"
     21 
     22 #include <memunreachable/memunreachable.h>
     23 #include <unistd.h>
     24 #include <cstdio>
     25 #include <iostream>
     26 #include <unordered_set>
     27 
     28 using namespace std;
     29 
     30 namespace android {
     31 namespace uirenderer {
     32 namespace test {
     33 
     34 static void logUnreachable(initializer_list<UnreachableMemoryInfo> infolist) {
     35     // merge them all
     36     UnreachableMemoryInfo merged;
     37     unordered_set<uintptr_t> addrs;
     38     merged.allocation_bytes = 0;
     39     merged.leak_bytes = 0;
     40     merged.num_allocations = 0;
     41     merged.num_leaks = 0;
     42     for (auto& info : infolist) {
     43         // We'll be a little hazzy about these ones and just hope the biggest
     44         // is the most accurate
     45         merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes);
     46         merged.num_allocations = max(merged.num_allocations, info.num_allocations);
     47         for (auto& leak : info.leaks) {
     48             if (addrs.find(leak.begin) == addrs.end()) {
     49                 merged.leaks.push_back(leak);
     50                 merged.num_leaks++;
     51                 merged.leak_bytes += leak.size;
     52                 addrs.insert(leak.begin);
     53             }
     54         }
     55     }
     56 
     57     // Now log the result
     58     if (merged.num_leaks) {
     59         cout << endl << "Leaked memory!" << endl;
     60         if (!merged.leaks[0].backtrace.num_frames) {
     61             cout << "Re-run with 'export LIBC_DEBUG_MALLOC_OPTIONS=backtrace' to get backtraces"
     62                  << endl;
     63         }
     64         cout << merged.ToString(false);
     65     }
     66 }
     67 
     68 void LeakChecker::checkForLeaks() {
     69     // TODO: Until we can shutdown the RT thread we need to do this in
     70     // two passes as GetUnreachableMemory has limited insight into
     71     // thread-local caches so some leaks will not be properly tagged as leaks
     72     UnreachableMemoryInfo rtMemInfo;
     73     TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) {
     74         if (Caches::hasInstance()) {
     75             Caches::getInstance().tasks.stop();
     76         }
     77         // Check for leaks
     78         if (!GetUnreachableMemory(rtMemInfo)) {
     79             cerr << "Failed to get unreachable memory!" << endl;
     80             return;
     81         }
     82     });
     83     UnreachableMemoryInfo uiMemInfo;
     84     if (!GetUnreachableMemory(uiMemInfo)) {
     85         cerr << "Failed to get unreachable memory!" << endl;
     86         return;
     87     }
     88     logUnreachable({rtMemInfo, uiMemInfo});
     89 }
     90 
     91 } /* namespace test */
     92 } /* namespace uirenderer */
     93 } /* namespace android */
     94