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 "Texture.h" 18 #include "utils/StringUtils.h" 19 20 #include <GpuMemoryTracker.h> 21 #include <cutils/compiler.h> 22 #include <utils/Trace.h> 23 #include <array> 24 #include <sstream> 25 #include <unordered_set> 26 #include <vector> 27 28 namespace android { 29 namespace uirenderer { 30 31 pthread_t gGpuThread = 0; 32 33 #define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount) 34 35 const char* TYPE_NAMES[] = { 36 "Texture", "OffscreenBuffer", "Layer", 37 }; 38 39 struct TypeStats { 40 int totalSize = 0; 41 int count = 0; 42 }; 43 44 static std::array<TypeStats, NUM_TYPES> gObjectStats; 45 static std::unordered_set<GpuMemoryTracker*> gObjectSet; 46 47 void GpuMemoryTracker::notifySizeChanged(int newSize) { 48 int delta = newSize - mSize; 49 mSize = newSize; 50 gObjectStats[static_cast<int>(mType)].totalSize += delta; 51 } 52 53 void GpuMemoryTracker::startTrackingObject() { 54 auto result = gObjectSet.insert(this); 55 LOG_ALWAYS_FATAL_IF(!result.second, 56 "startTrackingObject() on %p failed, already being tracked!", this); 57 gObjectStats[static_cast<int>(mType)].count++; 58 } 59 60 void GpuMemoryTracker::stopTrackingObject() { 61 size_t removed = gObjectSet.erase(this); 62 LOG_ALWAYS_FATAL_IF(removed != 1, "stopTrackingObject removed %zd, is %p not being tracked?", 63 removed, this); 64 gObjectStats[static_cast<int>(mType)].count--; 65 } 66 67 void GpuMemoryTracker::onGpuContextCreated() { 68 LOG_ALWAYS_FATAL_IF(gGpuThread != 0, 69 "We already have a gpu thread? " 70 "current = %lu, gpu thread = %lu", 71 pthread_self(), gGpuThread); 72 gGpuThread = pthread_self(); 73 } 74 75 void GpuMemoryTracker::onGpuContextDestroyed() { 76 gGpuThread = 0; 77 if (CC_UNLIKELY(gObjectSet.size() > 0)) { 78 std::stringstream os; 79 dump(os); 80 ALOGE("%s", os.str().c_str()); 81 LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size()); 82 } 83 } 84 85 void GpuMemoryTracker::dump() { 86 std::stringstream strout; 87 dump(strout); 88 ALOGD("%s", strout.str().c_str()); 89 } 90 91 void GpuMemoryTracker::dump(std::ostream& stream) { 92 for (int type = 0; type < NUM_TYPES; type++) { 93 const TypeStats& stats = gObjectStats[type]; 94 stream << TYPE_NAMES[type]; 95 stream << " is using " << SizePrinter{stats.totalSize}; 96 stream << ", count = " << stats.count; 97 stream << std::endl; 98 } 99 } 100 101 int GpuMemoryTracker::getInstanceCount(GpuObjectType type) { 102 return gObjectStats[static_cast<int>(type)].count; 103 } 104 105 int GpuMemoryTracker::getTotalSize(GpuObjectType type) { 106 return gObjectStats[static_cast<int>(type)].totalSize; 107 } 108 109 void GpuMemoryTracker::onFrameCompleted() { 110 if (ATRACE_ENABLED()) { 111 char buf[128]; 112 for (int type = 0; type < NUM_TYPES; type++) { 113 snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]); 114 const TypeStats& stats = gObjectStats[type]; 115 ATRACE_INT(buf, stats.totalSize); 116 snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]); 117 ATRACE_INT(buf, stats.count); 118 } 119 } 120 121 std::vector<const Texture*> freeList; 122 for (const auto& obj : gObjectSet) { 123 if (obj->objectType() == GpuObjectType::Texture) { 124 const Texture* texture = static_cast<Texture*>(obj); 125 if (texture->cleanup) { 126 ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u", texture->id(), 127 texture->width(), texture->height()); 128 freeList.push_back(texture); 129 } 130 } 131 } 132 for (auto& texture : freeList) { 133 const_cast<Texture*>(texture)->deleteTexture(); 134 delete texture; 135 } 136 } 137 138 } // namespace uirenderer 139 } // namespace android; 140