diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 953d7051a03d3..8ce5d4c851aef 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -104,6 +104,7 @@ hwui_src_files := \ hwui_test_common_src_files := \ $(call all-cpp-files-under, tests/common/scenes) \ + tests/common/LeakChecker.cpp \ tests/common/TestListViewSceneBase.cpp \ tests/common/TestContext.cpp \ tests/common/TestScene.cpp \ @@ -307,6 +308,7 @@ LOCAL_C_INCLUDES := $(hwui_c_includes) # set to libhwui_static_debug to skip actual GL commands LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static +LOCAL_SHARED_LIBRARIES := libmemunreachable LOCAL_SRC_FILES += \ $(hwui_test_common_src_files) \ @@ -337,6 +339,7 @@ LOCAL_C_INCLUDES := $(hwui_c_includes) LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static_debug LOCAL_STATIC_LIBRARIES := libgoogle-benchmark +LOCAL_SHARED_LIBRARIES := libmemunreachable LOCAL_SRC_FILES += \ $(hwui_test_common_src_files) \ diff --git a/libs/hwui/tests/common/LeakChecker.cpp b/libs/hwui/tests/common/LeakChecker.cpp new file mode 100644 index 0000000000000..3ef4b45a3863d --- /dev/null +++ b/libs/hwui/tests/common/LeakChecker.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LeakChecker.h" + +#include "Caches.h" +#include "TestUtils.h" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace android { +namespace uirenderer { +namespace test { + +static void logUnreachable(initializer_list infolist) { + // merge them all + UnreachableMemoryInfo merged; + unordered_set addrs; + merged.allocation_bytes = 0; + merged.leak_bytes = 0; + merged.num_allocations = 0; + merged.num_leaks = 0; + for (auto& info : infolist) { + // We'll be a little hazzy about these ones and just hope the biggest + // is the most accurate + merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes); + merged.num_allocations = max(merged.num_allocations, info.num_allocations); + for (auto& leak : info.leaks) { + if (addrs.find(leak.begin) == addrs.end()) { + merged.leaks.push_back(leak); + merged.num_leaks++; + merged.leak_bytes += leak.size; + addrs.insert(leak.begin); + } + } + } + + // Now log the result + if (merged.num_leaks) { + cout << endl << "Leaked memory!" << endl; + if (!merged.leaks[0].backtrace.num_frames) { + cout << "Re-run with 'setprop libc.debug.malloc.program hwui_unit_test'" + << endl << "and 'setprop libc.debug.malloc.options backtrace=8'" + << " to get backtraces" << endl; + } + cout << merged.ToString(false); + } +} + +void LeakChecker::checkForLeaks() { + // TODO: Until we can shutdown the RT thread we need to do this in + // two passes as GetUnreachableMemory has limited insight into + // thread-local caches so some leaks will not be properly tagged as leaks + nsecs_t before = systemTime(); + UnreachableMemoryInfo rtMemInfo; + TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) { + if (Caches::hasInstance()) { + Caches::getInstance().tasks.stop(); + } + // Check for leaks + if (!GetUnreachableMemory(rtMemInfo)) { + cerr << "Failed to get unreachable memory!" << endl; + return; + } + }); + UnreachableMemoryInfo uiMemInfo; + if (!GetUnreachableMemory(uiMemInfo)) { + cerr << "Failed to get unreachable memory!" << endl; + return; + } + logUnreachable({rtMemInfo, uiMemInfo}); + nsecs_t after = systemTime(); + cout << "Leak check took " << ns2ms(after - before) << "ms" << endl; +} + +} /* namespace test */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/tests/common/LeakChecker.h b/libs/hwui/tests/common/LeakChecker.h new file mode 100644 index 0000000000000..cdf47d6bda806 --- /dev/null +++ b/libs/hwui/tests/common/LeakChecker.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +namespace android { +namespace uirenderer { +namespace test { + +class LeakChecker { +public: + static void checkForLeaks(); +}; // class TestUtils + +} /* namespace test */ +} /* namespace uirenderer */ +} /* namespace android */ \ No newline at end of file diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index c3eb0eac4e0c2..930067a9b2cc5 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -20,6 +20,7 @@ #include "DeferredLayerUpdater.h" #include "LayerRenderer.h" +#include #include namespace android { @@ -112,12 +113,18 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, void TestUtils::TestTask::run() { // RenderState only valid once RenderThread is running, so queried here - RenderState& renderState = renderthread::RenderThread::getInstance().renderState(); + renderthread::RenderThread& renderThread = renderthread::RenderThread::getInstance(); + bool hasEglContext = renderThread.eglManager().hasEglContext(); + RenderState& renderState = renderThread.renderState(); + if (!hasEglContext) { + renderState.onGLContextCreated(); + } - renderState.onGLContextCreated(); - rtCallback(renderthread::RenderThread::getInstance()); - renderState.flush(Caches::FlushMode::Full); - renderState.onGLContextDestroyed(); + rtCallback(renderThread); + if (!hasEglContext) { + renderState.flush(Caches::FlushMode::Full); + renderState.onGLContextDestroyed(); + } } std::unique_ptr TestUtils::asciiToUtf16(const char* str) { diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp index 02a39501e6478..5bad4369cf411 100644 --- a/libs/hwui/tests/macrobench/main.cpp +++ b/libs/hwui/tests/macrobench/main.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "tests/common/LeakChecker.h" #include "tests/common/TestScene.h" #include "protos/hwui.pb.h" @@ -262,5 +263,6 @@ int main(int argc, char* argv[]) { } } printf("Success!\n"); + LeakChecker::checkForLeaks(); return 0; } diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp index 27f95e692779e..d05bdbf1709ec 100644 --- a/libs/hwui/tests/unit/main.cpp +++ b/libs/hwui/tests/unit/main.cpp @@ -21,16 +21,9 @@ #include "debug/GlesDriver.h" #include "debug/NullGlesDriver.h" #include "thread/TaskManager.h" -#include "tests/common/TestUtils.h" +#include "tests/common/LeakChecker.h" -#include - -#include -#include -#include -#include #include -#include using namespace std; using namespace android; @@ -57,67 +50,6 @@ static void gtestSigHandler(int sig, siginfo_t* siginfo, void* context) { raise(sig); } -static void logUnreachable(initializer_list infolist) { - // merge them all - UnreachableMemoryInfo merged; - unordered_set addrs; - merged.allocation_bytes = 0; - merged.leak_bytes = 0; - merged.num_allocations = 0; - merged.num_leaks = 0; - for (auto& info : infolist) { - // We'll be a little hazzy about these ones and just hope the biggest - // is the most accurate - merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes); - merged.num_allocations = max(merged.num_allocations, info.num_allocations); - for (auto& leak : info.leaks) { - if (addrs.find(leak.begin) == addrs.end()) { - merged.leaks.push_back(leak); - merged.num_leaks++; - merged.leak_bytes += leak.size; - addrs.insert(leak.begin); - } - } - } - - // Now log the result - if (merged.num_leaks) { - cout << endl << "Leaked memory!" << endl; - if (!merged.leaks[0].backtrace.num_frames) { - cout << "Re-run with 'setprop libc.debug.malloc.program hwui_unit_test'" - << endl << "and 'setprop libc.debug.malloc.options backtrace=8'" - << " to get backtraces" << endl; - } - cout << merged.ToString(false); - } -} - -static void checkForLeaks() { - // TODO: Until we can shutdown the RT thread we need to do this in - // two passes as GetUnreachableMemory has limited insight into - // thread-local caches so some leaks will not be properly tagged as leaks - nsecs_t before = systemTime(); - UnreachableMemoryInfo rtMemInfo; - TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) { - if (Caches::hasInstance()) { - Caches::getInstance().tasks.stop(); - } - // Check for leaks - if (!GetUnreachableMemory(rtMemInfo)) { - cerr << "Failed to get unreachable memory!" << endl; - return; - } - }); - UnreachableMemoryInfo uiMemInfo; - if (!GetUnreachableMemory(uiMemInfo)) { - cerr << "Failed to get unreachable memory!" << endl; - return; - } - logUnreachable({rtMemInfo, uiMemInfo}); - nsecs_t after = systemTime(); - cout << "Leak check took " << ns2ms(after - before) << "ms" << endl; -} - int main(int argc, char* argv[]) { // Register a crash handler struct sigaction sa; @@ -138,7 +70,7 @@ int main(int argc, char* argv[]) { testing::InitGoogleMock(&argc, argv); int ret = RUN_ALL_TESTS(); - checkForLeaks(); + test::LeakChecker::checkForLeaks(); return ret; }