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