Loading libs/hwui/Android.bp +1 −2 Original line number Diff line number Diff line Loading @@ -215,6 +215,7 @@ cc_defaults { android: { srcs: [ "pipeline/skia/ATraceMemoryDump.cpp", "pipeline/skia/GLFunctorDrawable.cpp", "pipeline/skia/LayerDrawable.cpp", "pipeline/skia/ShaderCache.cpp", Loading Loading @@ -244,7 +245,6 @@ cc_defaults { "DeviceInfo.cpp", "FrameInfo.cpp", "FrameInfoVisualizer.cpp", "GpuMemoryTracker.cpp", "HardwareBitmapUploader.cpp", "HWUIProperties.sysprop", "JankTracker.cpp", Loading Loading @@ -325,7 +325,6 @@ cc_test { "tests/unit/DamageAccumulatorTests.cpp", "tests/unit/DeferredLayerUpdaterTests.cpp", "tests/unit/FatVectorTests.cpp", "tests/unit/GpuMemoryTrackerTests.cpp", "tests/unit/GraphicsStatsServiceTests.cpp", "tests/unit/LayerUpdateQueueTests.cpp", "tests/unit/LinearAllocatorTests.cpp", Loading libs/hwui/GpuMemoryTracker.cppdeleted 100644 → 0 +0 −122 Original line number Diff line number Diff line /* * 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 "utils/StringUtils.h" #include <GpuMemoryTracker.h> #include <cutils/compiler.h> #include <utils/Trace.h> #include <array> #include <sstream> #include <unordered_set> #include <vector> namespace android { namespace uirenderer { pthread_t gGpuThread = 0; #define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount) const char* TYPE_NAMES[] = { "Texture", "OffscreenBuffer", "Layer", }; struct TypeStats { int totalSize = 0; int count = 0; }; static std::array<TypeStats, NUM_TYPES> gObjectStats; static std::unordered_set<GpuMemoryTracker*> gObjectSet; void GpuMemoryTracker::notifySizeChanged(int newSize) { int delta = newSize - mSize; mSize = newSize; gObjectStats[static_cast<int>(mType)].totalSize += delta; } void GpuMemoryTracker::startTrackingObject() { auto result = gObjectSet.insert(this); LOG_ALWAYS_FATAL_IF(!result.second, "startTrackingObject() on %p failed, already being tracked!", this); gObjectStats[static_cast<int>(mType)].count++; } void GpuMemoryTracker::stopTrackingObject() { size_t removed = gObjectSet.erase(this); LOG_ALWAYS_FATAL_IF(removed != 1, "stopTrackingObject removed %zd, is %p not being tracked?", removed, this); gObjectStats[static_cast<int>(mType)].count--; } void GpuMemoryTracker::onGpuContextCreated() { LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a gpu thread? " "current = %lu, gpu thread = %lu", pthread_self(), gGpuThread); gGpuThread = pthread_self(); } void GpuMemoryTracker::onGpuContextDestroyed() { gGpuThread = 0; if (CC_UNLIKELY(gObjectSet.size() > 0)) { std::stringstream os; dump(os); ALOGE("%s", os.str().c_str()); LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size()); } } void GpuMemoryTracker::dump() { std::stringstream strout; dump(strout); ALOGD("%s", strout.str().c_str()); } void GpuMemoryTracker::dump(std::ostream& stream) { for (int type = 0; type < NUM_TYPES; type++) { const TypeStats& stats = gObjectStats[type]; stream << TYPE_NAMES[type]; stream << " is using " << SizePrinter{stats.totalSize}; stream << ", count = " << stats.count; stream << std::endl; } } int GpuMemoryTracker::getInstanceCount(GpuObjectType type) { return gObjectStats[static_cast<int>(type)].count; } int GpuMemoryTracker::getTotalSize(GpuObjectType type) { return gObjectStats[static_cast<int>(type)].totalSize; } void GpuMemoryTracker::onFrameCompleted() { if (ATRACE_ENABLED()) { char buf[128]; for (int type = 0; type < NUM_TYPES; type++) { snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]); const TypeStats& stats = gObjectStats[type]; ATRACE_INT(buf, stats.totalSize); snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]); ATRACE_INT(buf, stats.count); } } } } // namespace uirenderer } // namespace android; libs/hwui/pipeline/skia/ATraceMemoryDump.cpp 0 → 100644 +175 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 "ATraceMemoryDump.h" #include <utils/Trace.h> #include <cstring> namespace android { namespace uirenderer { namespace skiapipeline { // When purgeable is INVALID_TIME it won't be logged at all. #define INVALID_TIME -1 /** * Skia invokes the following SkTraceMemoryDump functions: * 1. dumpNumericValue (dumpName, units="bytes", valueName="size") * 2. dumpStringValue (dumpName, valueName="type") [optional -> for example CPU memory does not * invoke dumpStringValue] * 3. dumpNumericValue (dumpName, units="bytes", valueName="purgeable_size") [optional] * 4. setMemoryBacking(dumpName, backingType) [optional -> for example Vulkan GPU resources do not * invoke setMemoryBacking] * * ATraceMemoryDump calculates memory category first by looking at the "type" string passed to * dumpStringValue and then by looking at "backingType" passed to setMemoryBacking. * Only GPU Texture memory is tracked separately and everything else is grouped as one * "GPU Memory" category. */ static std::unordered_map<const char*, const char*> sResourceMap = { {"malloc", "Graphics CPU Memory"}, // taken from setMemoryBacking(backingType) {"gl_texture", "Graphics Texture Memory"}, // taken from setMemoryBacking(backingType) {"Texture", "Graphics Texture Memory"}, // taken from dumpStringValue(value, valueName="type") // Uncomment categories below to split "GPU Memory" into more brackets for debugging. /*{"vk_buffer", "vk_buffer"}, {"gl_renderbuffer", "gl_renderbuffer"}, {"gl_buffer", "gl_buffer"}, {"RenderTarget", "RenderTarget"}, {"Stencil", "Stencil"}, {"Path Data", "Path Data"}, {"Buffer Object", "Buffer Object"}, {"Surface", "Surface"},*/ }; ATraceMemoryDump::ATraceMemoryDump() { mLastDumpName.reserve(100); mCategory.reserve(100); } void ATraceMemoryDump::dumpNumericValue(const char* dumpName, const char* valueName, const char* units, uint64_t value) { if (!strcmp(units, "bytes")) { recordAndResetCountersIfNeeded(dumpName); if (!strcmp(valueName, "size")) { mLastDumpValue = value; } else if (!strcmp(valueName, "purgeable_size")) { mLastPurgeableDumpValue = value; } } } void ATraceMemoryDump::dumpStringValue(const char* dumpName, const char* valueName, const char* value) { if (!strcmp(valueName, "type")) { recordAndResetCountersIfNeeded(dumpName); auto categoryIt = sResourceMap.find(value); if (categoryIt != sResourceMap.end()) { mCategory = categoryIt->second; } } } void ATraceMemoryDump::setMemoryBacking(const char* dumpName, const char* backingType, const char* backingObjectId) { recordAndResetCountersIfNeeded(dumpName); auto categoryIt = sResourceMap.find(backingType); if (categoryIt != sResourceMap.end()) { mCategory = categoryIt->second; } } /** * startFrame is invoked before dumping anything. It resets counters from the previous frame. * This is important, because if there is no new data for a given category trace would assume * usage has not changed (instead of reporting 0). */ void ATraceMemoryDump::startFrame() { resetCurrentCounter(""); for (auto& it : mCurrentValues) { // Once a category is observed in at least one frame, it is always reported in subsequent // frames (even if it is 0). Not logging a category to ATRACE would mean its value has not // changed since the previous frame, which is not what we want. it.second.time = 0; // If purgeableTime is INVALID_TIME, then logTraces won't log it at all. if (it.second.purgeableTime != INVALID_TIME) { it.second.purgeableTime = 0; } } } /** * logTraces reads from mCurrentValues and logs the counters with ATRACE. */ void ATraceMemoryDump::logTraces() { // Accumulate data from last dumpName recordAndResetCountersIfNeeded(""); for (auto& it : mCurrentValues) { ATRACE_INT64(it.first.c_str(), it.second.time); if (it.second.purgeableTime != INVALID_TIME) { ATRACE_INT64((std::string("Purgeable ") + it.first).c_str(), it.second.purgeableTime); } } } /** * recordAndResetCountersIfNeeded reads memory usage from mLastDumpValue/mLastPurgeableDumpValue and * accumulates in mCurrentValues[category]. It makes provision to create a new category and track * purgeable memory only if there is at least one observation. * recordAndResetCountersIfNeeded won't do anything until all the information for a given dumpName * is received. */ void ATraceMemoryDump::recordAndResetCountersIfNeeded(const char* dumpName) { if (!mLastDumpName.compare(dumpName)) { // Still waiting for more data for current dumpName. return; } // First invocation will have an empty mLastDumpName. if (!mLastDumpName.empty()) { // A new dumpName observed -> store the data already collected. auto memoryCounter = mCurrentValues.find(mCategory); if (memoryCounter != mCurrentValues.end()) { memoryCounter->second.time += mLastDumpValue; if (mLastPurgeableDumpValue != INVALID_TIME) { if (memoryCounter->second.purgeableTime == INVALID_TIME) { memoryCounter->second.purgeableTime = mLastPurgeableDumpValue; } else { memoryCounter->second.purgeableTime += mLastPurgeableDumpValue; } } } else { mCurrentValues[mCategory] = {mLastDumpValue, mLastPurgeableDumpValue}; } } // Reset counters and default category for the newly observed "dumpName". resetCurrentCounter(dumpName); } void ATraceMemoryDump::resetCurrentCounter(const char* dumpName) { mLastDumpValue = 0; mLastPurgeableDumpValue = INVALID_TIME; mLastDumpName = dumpName; // Categories not listed in sResourceMap are reported as "GPU memory" mCategory = "GPU Memory"; } } /* namespace skiapipeline */ } /* namespace uirenderer */ } /* namespace android */ libs/hwui/GpuMemoryTracker.h→libs/hwui/pipeline/skia/ATraceMemoryDump.h +79 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * Copyright (C) 2020 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. Loading @@ -13,65 +13,67 @@ * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <pthread.h> #include <ostream> #include <SkString.h> #include <SkTraceMemoryDump.h> #include <log/log.h> #include <string> #include <unordered_map> #include <utility> namespace android { namespace uirenderer { namespace skiapipeline { extern pthread_t gGpuThread; #define ASSERT_GPU_THREAD() \ LOG_ALWAYS_FATAL_IF(!pthread_equal(gGpuThread, pthread_self()), \ "Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \ "!= gpu thread %lu", \ this, static_cast<int>(mType), mSize, pthread_self(), gGpuThread) class ATraceMemoryDump : public SkTraceMemoryDump { public: ATraceMemoryDump(); ~ATraceMemoryDump() override {} enum class GpuObjectType { Texture = 0, OffscreenBuffer, Layer, void dumpNumericValue(const char* dumpName, const char* valueName, const char* units, uint64_t value) override; TypeCount, }; void dumpStringValue(const char* dumpName, const char* valueName, const char* value) override; class GpuMemoryTracker { public: GpuObjectType objectType() { return mType; } int objectSize() { return mSize; } static void onGpuContextCreated(); static void onGpuContextDestroyed(); static void dump(); static void dump(std::ostream& stream); static int getInstanceCount(GpuObjectType type); static int getTotalSize(GpuObjectType type); static void onFrameCompleted(); protected: explicit GpuMemoryTracker(GpuObjectType type) : mType(type) { ASSERT_GPU_THREAD(); startTrackingObject(); LevelOfDetail getRequestedDetails() const override { return SkTraceMemoryDump::kLight_LevelOfDetail; } ~GpuMemoryTracker() { notifySizeChanged(0); stopTrackingObject(); } bool shouldDumpWrappedObjects() const override { return false; } void setMemoryBacking(const char* dumpName, const char* backingType, const char* backingObjectId) override; void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override {} void notifySizeChanged(int newSize); void startFrame(); void logTraces(); private: void startTrackingObject(); void stopTrackingObject(); std::string mLastDumpName; uint64_t mLastDumpValue; uint64_t mLastPurgeableDumpValue; std::string mCategory; struct TraceValue { uint64_t time; uint64_t purgeableTime; }; // keys are define in sResourceMap std::unordered_map<std::string, TraceValue> mCurrentValues; void recordAndResetCountersIfNeeded(const char* dumpName); int mSize = 0; GpuObjectType mType; void resetCurrentCounter(const char* dumpName); }; } // namespace uirenderer } // namespace android; } /* namespace skiapipeline */ } /* namespace uirenderer */ } /* namespace android */ No newline at end of file libs/hwui/renderstate/RenderState.cpp +0 −6 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ #include "renderstate/RenderState.h" #include "renderthread/RenderThread.h" #include "GpuMemoryTracker.h" namespace android { namespace uirenderer { Loading @@ -25,15 +24,10 @@ RenderState::RenderState(renderthread::RenderThread& thread) : mRenderThread(thr mThreadId = pthread_self(); } void RenderState::onContextCreated() { GpuMemoryTracker::onGpuContextCreated(); } void RenderState::onContextDestroyed() { for(auto callback : mContextCallbacks) { callback->onContextDestroyed(); } GpuMemoryTracker::onGpuContextDestroyed(); } void RenderState::postDecStrong(VirtualLightRefBase* object) { Loading Loading
libs/hwui/Android.bp +1 −2 Original line number Diff line number Diff line Loading @@ -215,6 +215,7 @@ cc_defaults { android: { srcs: [ "pipeline/skia/ATraceMemoryDump.cpp", "pipeline/skia/GLFunctorDrawable.cpp", "pipeline/skia/LayerDrawable.cpp", "pipeline/skia/ShaderCache.cpp", Loading Loading @@ -244,7 +245,6 @@ cc_defaults { "DeviceInfo.cpp", "FrameInfo.cpp", "FrameInfoVisualizer.cpp", "GpuMemoryTracker.cpp", "HardwareBitmapUploader.cpp", "HWUIProperties.sysprop", "JankTracker.cpp", Loading Loading @@ -325,7 +325,6 @@ cc_test { "tests/unit/DamageAccumulatorTests.cpp", "tests/unit/DeferredLayerUpdaterTests.cpp", "tests/unit/FatVectorTests.cpp", "tests/unit/GpuMemoryTrackerTests.cpp", "tests/unit/GraphicsStatsServiceTests.cpp", "tests/unit/LayerUpdateQueueTests.cpp", "tests/unit/LinearAllocatorTests.cpp", Loading
libs/hwui/GpuMemoryTracker.cppdeleted 100644 → 0 +0 −122 Original line number Diff line number Diff line /* * 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 "utils/StringUtils.h" #include <GpuMemoryTracker.h> #include <cutils/compiler.h> #include <utils/Trace.h> #include <array> #include <sstream> #include <unordered_set> #include <vector> namespace android { namespace uirenderer { pthread_t gGpuThread = 0; #define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount) const char* TYPE_NAMES[] = { "Texture", "OffscreenBuffer", "Layer", }; struct TypeStats { int totalSize = 0; int count = 0; }; static std::array<TypeStats, NUM_TYPES> gObjectStats; static std::unordered_set<GpuMemoryTracker*> gObjectSet; void GpuMemoryTracker::notifySizeChanged(int newSize) { int delta = newSize - mSize; mSize = newSize; gObjectStats[static_cast<int>(mType)].totalSize += delta; } void GpuMemoryTracker::startTrackingObject() { auto result = gObjectSet.insert(this); LOG_ALWAYS_FATAL_IF(!result.second, "startTrackingObject() on %p failed, already being tracked!", this); gObjectStats[static_cast<int>(mType)].count++; } void GpuMemoryTracker::stopTrackingObject() { size_t removed = gObjectSet.erase(this); LOG_ALWAYS_FATAL_IF(removed != 1, "stopTrackingObject removed %zd, is %p not being tracked?", removed, this); gObjectStats[static_cast<int>(mType)].count--; } void GpuMemoryTracker::onGpuContextCreated() { LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a gpu thread? " "current = %lu, gpu thread = %lu", pthread_self(), gGpuThread); gGpuThread = pthread_self(); } void GpuMemoryTracker::onGpuContextDestroyed() { gGpuThread = 0; if (CC_UNLIKELY(gObjectSet.size() > 0)) { std::stringstream os; dump(os); ALOGE("%s", os.str().c_str()); LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size()); } } void GpuMemoryTracker::dump() { std::stringstream strout; dump(strout); ALOGD("%s", strout.str().c_str()); } void GpuMemoryTracker::dump(std::ostream& stream) { for (int type = 0; type < NUM_TYPES; type++) { const TypeStats& stats = gObjectStats[type]; stream << TYPE_NAMES[type]; stream << " is using " << SizePrinter{stats.totalSize}; stream << ", count = " << stats.count; stream << std::endl; } } int GpuMemoryTracker::getInstanceCount(GpuObjectType type) { return gObjectStats[static_cast<int>(type)].count; } int GpuMemoryTracker::getTotalSize(GpuObjectType type) { return gObjectStats[static_cast<int>(type)].totalSize; } void GpuMemoryTracker::onFrameCompleted() { if (ATRACE_ENABLED()) { char buf[128]; for (int type = 0; type < NUM_TYPES; type++) { snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]); const TypeStats& stats = gObjectStats[type]; ATRACE_INT(buf, stats.totalSize); snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]); ATRACE_INT(buf, stats.count); } } } } // namespace uirenderer } // namespace android;
libs/hwui/pipeline/skia/ATraceMemoryDump.cpp 0 → 100644 +175 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 "ATraceMemoryDump.h" #include <utils/Trace.h> #include <cstring> namespace android { namespace uirenderer { namespace skiapipeline { // When purgeable is INVALID_TIME it won't be logged at all. #define INVALID_TIME -1 /** * Skia invokes the following SkTraceMemoryDump functions: * 1. dumpNumericValue (dumpName, units="bytes", valueName="size") * 2. dumpStringValue (dumpName, valueName="type") [optional -> for example CPU memory does not * invoke dumpStringValue] * 3. dumpNumericValue (dumpName, units="bytes", valueName="purgeable_size") [optional] * 4. setMemoryBacking(dumpName, backingType) [optional -> for example Vulkan GPU resources do not * invoke setMemoryBacking] * * ATraceMemoryDump calculates memory category first by looking at the "type" string passed to * dumpStringValue and then by looking at "backingType" passed to setMemoryBacking. * Only GPU Texture memory is tracked separately and everything else is grouped as one * "GPU Memory" category. */ static std::unordered_map<const char*, const char*> sResourceMap = { {"malloc", "Graphics CPU Memory"}, // taken from setMemoryBacking(backingType) {"gl_texture", "Graphics Texture Memory"}, // taken from setMemoryBacking(backingType) {"Texture", "Graphics Texture Memory"}, // taken from dumpStringValue(value, valueName="type") // Uncomment categories below to split "GPU Memory" into more brackets for debugging. /*{"vk_buffer", "vk_buffer"}, {"gl_renderbuffer", "gl_renderbuffer"}, {"gl_buffer", "gl_buffer"}, {"RenderTarget", "RenderTarget"}, {"Stencil", "Stencil"}, {"Path Data", "Path Data"}, {"Buffer Object", "Buffer Object"}, {"Surface", "Surface"},*/ }; ATraceMemoryDump::ATraceMemoryDump() { mLastDumpName.reserve(100); mCategory.reserve(100); } void ATraceMemoryDump::dumpNumericValue(const char* dumpName, const char* valueName, const char* units, uint64_t value) { if (!strcmp(units, "bytes")) { recordAndResetCountersIfNeeded(dumpName); if (!strcmp(valueName, "size")) { mLastDumpValue = value; } else if (!strcmp(valueName, "purgeable_size")) { mLastPurgeableDumpValue = value; } } } void ATraceMemoryDump::dumpStringValue(const char* dumpName, const char* valueName, const char* value) { if (!strcmp(valueName, "type")) { recordAndResetCountersIfNeeded(dumpName); auto categoryIt = sResourceMap.find(value); if (categoryIt != sResourceMap.end()) { mCategory = categoryIt->second; } } } void ATraceMemoryDump::setMemoryBacking(const char* dumpName, const char* backingType, const char* backingObjectId) { recordAndResetCountersIfNeeded(dumpName); auto categoryIt = sResourceMap.find(backingType); if (categoryIt != sResourceMap.end()) { mCategory = categoryIt->second; } } /** * startFrame is invoked before dumping anything. It resets counters from the previous frame. * This is important, because if there is no new data for a given category trace would assume * usage has not changed (instead of reporting 0). */ void ATraceMemoryDump::startFrame() { resetCurrentCounter(""); for (auto& it : mCurrentValues) { // Once a category is observed in at least one frame, it is always reported in subsequent // frames (even if it is 0). Not logging a category to ATRACE would mean its value has not // changed since the previous frame, which is not what we want. it.second.time = 0; // If purgeableTime is INVALID_TIME, then logTraces won't log it at all. if (it.second.purgeableTime != INVALID_TIME) { it.second.purgeableTime = 0; } } } /** * logTraces reads from mCurrentValues and logs the counters with ATRACE. */ void ATraceMemoryDump::logTraces() { // Accumulate data from last dumpName recordAndResetCountersIfNeeded(""); for (auto& it : mCurrentValues) { ATRACE_INT64(it.first.c_str(), it.second.time); if (it.second.purgeableTime != INVALID_TIME) { ATRACE_INT64((std::string("Purgeable ") + it.first).c_str(), it.second.purgeableTime); } } } /** * recordAndResetCountersIfNeeded reads memory usage from mLastDumpValue/mLastPurgeableDumpValue and * accumulates in mCurrentValues[category]. It makes provision to create a new category and track * purgeable memory only if there is at least one observation. * recordAndResetCountersIfNeeded won't do anything until all the information for a given dumpName * is received. */ void ATraceMemoryDump::recordAndResetCountersIfNeeded(const char* dumpName) { if (!mLastDumpName.compare(dumpName)) { // Still waiting for more data for current dumpName. return; } // First invocation will have an empty mLastDumpName. if (!mLastDumpName.empty()) { // A new dumpName observed -> store the data already collected. auto memoryCounter = mCurrentValues.find(mCategory); if (memoryCounter != mCurrentValues.end()) { memoryCounter->second.time += mLastDumpValue; if (mLastPurgeableDumpValue != INVALID_TIME) { if (memoryCounter->second.purgeableTime == INVALID_TIME) { memoryCounter->second.purgeableTime = mLastPurgeableDumpValue; } else { memoryCounter->second.purgeableTime += mLastPurgeableDumpValue; } } } else { mCurrentValues[mCategory] = {mLastDumpValue, mLastPurgeableDumpValue}; } } // Reset counters and default category for the newly observed "dumpName". resetCurrentCounter(dumpName); } void ATraceMemoryDump::resetCurrentCounter(const char* dumpName) { mLastDumpValue = 0; mLastPurgeableDumpValue = INVALID_TIME; mLastDumpName = dumpName; // Categories not listed in sResourceMap are reported as "GPU memory" mCategory = "GPU Memory"; } } /* namespace skiapipeline */ } /* namespace uirenderer */ } /* namespace android */
libs/hwui/GpuMemoryTracker.h→libs/hwui/pipeline/skia/ATraceMemoryDump.h +79 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * Copyright (C) 2020 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. Loading @@ -13,65 +13,67 @@ * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <pthread.h> #include <ostream> #include <SkString.h> #include <SkTraceMemoryDump.h> #include <log/log.h> #include <string> #include <unordered_map> #include <utility> namespace android { namespace uirenderer { namespace skiapipeline { extern pthread_t gGpuThread; #define ASSERT_GPU_THREAD() \ LOG_ALWAYS_FATAL_IF(!pthread_equal(gGpuThread, pthread_self()), \ "Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \ "!= gpu thread %lu", \ this, static_cast<int>(mType), mSize, pthread_self(), gGpuThread) class ATraceMemoryDump : public SkTraceMemoryDump { public: ATraceMemoryDump(); ~ATraceMemoryDump() override {} enum class GpuObjectType { Texture = 0, OffscreenBuffer, Layer, void dumpNumericValue(const char* dumpName, const char* valueName, const char* units, uint64_t value) override; TypeCount, }; void dumpStringValue(const char* dumpName, const char* valueName, const char* value) override; class GpuMemoryTracker { public: GpuObjectType objectType() { return mType; } int objectSize() { return mSize; } static void onGpuContextCreated(); static void onGpuContextDestroyed(); static void dump(); static void dump(std::ostream& stream); static int getInstanceCount(GpuObjectType type); static int getTotalSize(GpuObjectType type); static void onFrameCompleted(); protected: explicit GpuMemoryTracker(GpuObjectType type) : mType(type) { ASSERT_GPU_THREAD(); startTrackingObject(); LevelOfDetail getRequestedDetails() const override { return SkTraceMemoryDump::kLight_LevelOfDetail; } ~GpuMemoryTracker() { notifySizeChanged(0); stopTrackingObject(); } bool shouldDumpWrappedObjects() const override { return false; } void setMemoryBacking(const char* dumpName, const char* backingType, const char* backingObjectId) override; void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override {} void notifySizeChanged(int newSize); void startFrame(); void logTraces(); private: void startTrackingObject(); void stopTrackingObject(); std::string mLastDumpName; uint64_t mLastDumpValue; uint64_t mLastPurgeableDumpValue; std::string mCategory; struct TraceValue { uint64_t time; uint64_t purgeableTime; }; // keys are define in sResourceMap std::unordered_map<std::string, TraceValue> mCurrentValues; void recordAndResetCountersIfNeeded(const char* dumpName); int mSize = 0; GpuObjectType mType; void resetCurrentCounter(const char* dumpName); }; } // namespace uirenderer } // namespace android; } /* namespace skiapipeline */ } /* namespace uirenderer */ } /* namespace android */ No newline at end of file
libs/hwui/renderstate/RenderState.cpp +0 −6 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ #include "renderstate/RenderState.h" #include "renderthread/RenderThread.h" #include "GpuMemoryTracker.h" namespace android { namespace uirenderer { Loading @@ -25,15 +24,10 @@ RenderState::RenderState(renderthread::RenderThread& thread) : mRenderThread(thr mThreadId = pthread_self(); } void RenderState::onContextCreated() { GpuMemoryTracker::onGpuContextCreated(); } void RenderState::onContextDestroyed() { for(auto callback : mContextCallbacks) { callback->onContextDestroyed(); } GpuMemoryTracker::onGpuContextDestroyed(); } void RenderState::postDecStrong(VirtualLightRefBase* object) { Loading