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