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 <cstdio>
     23 #include <iostream>
     24 #include <memunreachable/memunreachable.h>
     25 #include <unistd.h>
     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 'setprop libc.debug.malloc.program hwui_unit_test'"
     62                     << endl << "and 'setprop libc.debug.malloc.options backtrace=8'"
     63                     << " to get backtraces" << endl;
     64         }
     65         cout << merged.ToString(false);
     66     }
     67 }
     68 
     69 void LeakChecker::checkForLeaks() {
     70     // TODO: Until we can shutdown the RT thread we need to do this in
     71     // two passes as GetUnreachableMemory has limited insight into
     72     // thread-local caches so some leaks will not be properly tagged as leaks
     73     UnreachableMemoryInfo rtMemInfo;
     74     TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) {
     75         if (Caches::hasInstance()) {
     76             Caches::getInstance().tasks.stop();
     77         }
     78         // Check for leaks
     79         if (!GetUnreachableMemory(rtMemInfo)) {
     80             cerr << "Failed to get unreachable memory!" << endl;
     81             return;
     82         }
     83     });
     84     UnreachableMemoryInfo uiMemInfo;
     85     if (!GetUnreachableMemory(uiMemInfo)) {
     86         cerr << "Failed to get unreachable memory!" << endl;
     87         return;
     88     }
     89     logUnreachable({rtMemInfo, uiMemInfo});
     90 }
     91 
     92 } /* namespace test */
     93 } /* namespace uirenderer */
     94 } /* namespace android */
     95