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 
notifySizeChanged(int newSize)47 void GpuMemoryTracker::notifySizeChanged(int newSize) {
48     int delta = newSize - mSize;
49     mSize = newSize;
50     gObjectStats[static_cast<int>(mType)].totalSize += delta;
51 }
52 
startTrackingObject()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 
stopTrackingObject()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 
onGpuContextCreated()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 
onGpuContextDestroyed()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 
dump()85 void GpuMemoryTracker::dump() {
86     std::stringstream strout;
87     dump(strout);
88     ALOGD("%s", strout.str().c_str());
89 }
90 
dump(std::ostream & stream)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 
getInstanceCount(GpuObjectType type)101 int GpuMemoryTracker::getInstanceCount(GpuObjectType type) {
102     return gObjectStats[static_cast<int>(type)].count;
103 }
104 
getTotalSize(GpuObjectType type)105 int GpuMemoryTracker::getTotalSize(GpuObjectType type) {
106     return gObjectStats[static_cast<int>(type)].totalSize;
107 }
108 
onFrameCompleted()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