1 /*
2  * Copyright 2019 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 #undef LOG_TAG
17 #define LOG_TAG "GpuStats"
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19 
20 #include "GpuStats.h"
21 
22 #include <cutils/properties.h>
23 #include <log/log.h>
24 #include <utils/Trace.h>
25 
26 #include <unordered_set>
27 
28 namespace android {
29 
addLoadingCount(GraphicsEnv::Driver driver,bool isDriverLoaded,GpuStatsGlobalInfo * const outGlobalInfo)30 static void addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded,
31                             GpuStatsGlobalInfo* const outGlobalInfo) {
32     switch (driver) {
33         case GraphicsEnv::Driver::GL:
34         case GraphicsEnv::Driver::GL_UPDATED:
35             outGlobalInfo->glLoadingCount++;
36             if (!isDriverLoaded) outGlobalInfo->glLoadingFailureCount++;
37             break;
38         case GraphicsEnv::Driver::VULKAN:
39         case GraphicsEnv::Driver::VULKAN_UPDATED:
40             outGlobalInfo->vkLoadingCount++;
41             if (!isDriverLoaded) outGlobalInfo->vkLoadingFailureCount++;
42             break;
43         case GraphicsEnv::Driver::ANGLE:
44             outGlobalInfo->angleLoadingCount++;
45             if (!isDriverLoaded) outGlobalInfo->angleLoadingFailureCount++;
46             break;
47         default:
48             break;
49     }
50 }
51 
addLoadingTime(GraphicsEnv::Driver driver,int64_t driverLoadingTime,GpuStatsAppInfo * const outAppInfo)52 static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime,
53                            GpuStatsAppInfo* const outAppInfo) {
54     switch (driver) {
55         case GraphicsEnv::Driver::GL:
56         case GraphicsEnv::Driver::GL_UPDATED:
57             if (outAppInfo->glDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) {
58                 outAppInfo->glDriverLoadingTime.emplace_back(driverLoadingTime);
59             }
60             break;
61         case GraphicsEnv::Driver::VULKAN:
62         case GraphicsEnv::Driver::VULKAN_UPDATED:
63             if (outAppInfo->vkDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) {
64                 outAppInfo->vkDriverLoadingTime.emplace_back(driverLoadingTime);
65             }
66             break;
67         case GraphicsEnv::Driver::ANGLE:
68             if (outAppInfo->angleDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) {
69                 outAppInfo->angleDriverLoadingTime.emplace_back(driverLoadingTime);
70             }
71             break;
72         default:
73             break;
74     }
75 }
76 
insert(const std::string & driverPackageName,const std::string & driverVersionName,uint64_t driverVersionCode,int64_t driverBuildTime,const std::string & appPackageName,const int32_t vulkanVersion,GraphicsEnv::Driver driver,bool isDriverLoaded,int64_t driverLoadingTime)77 void GpuStats::insert(const std::string& driverPackageName, const std::string& driverVersionName,
78                       uint64_t driverVersionCode, int64_t driverBuildTime,
79                       const std::string& appPackageName, const int32_t vulkanVersion,
80                       GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) {
81     ATRACE_CALL();
82 
83     std::lock_guard<std::mutex> lock(mLock);
84     ALOGV("Received:\n"
85           "\tdriverPackageName[%s]\n"
86           "\tdriverVersionName[%s]\n"
87           "\tdriverVersionCode[%" PRIu64 "]\n"
88           "\tdriverBuildTime[%" PRId64 "]\n"
89           "\tappPackageName[%s]\n"
90           "\tvulkanVersion[%d]\n"
91           "\tdriver[%d]\n"
92           "\tisDriverLoaded[%d]\n"
93           "\tdriverLoadingTime[%" PRId64 "]",
94           driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
95           appPackageName.c_str(), vulkanVersion, static_cast<int32_t>(driver), isDriverLoaded,
96           driverLoadingTime);
97 
98     if (!mGlobalStats.count(driverVersionCode)) {
99         GpuStatsGlobalInfo globalInfo;
100         addLoadingCount(driver, isDriverLoaded, &globalInfo);
101         globalInfo.driverPackageName = driverPackageName;
102         globalInfo.driverVersionName = driverVersionName;
103         globalInfo.driverVersionCode = driverVersionCode;
104         globalInfo.driverBuildTime = driverBuildTime;
105         globalInfo.vulkanVersion = vulkanVersion;
106         mGlobalStats.insert({driverVersionCode, globalInfo});
107     } else {
108         addLoadingCount(driver, isDriverLoaded, &mGlobalStats[driverVersionCode]);
109     }
110 
111     const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
112     if (!mAppStats.count(appStatsKey)) {
113         if (mAppStats.size() >= MAX_NUM_APP_RECORDS) {
114             ALOGV("GpuStatsAppInfo has reached maximum size. Ignore new stats.");
115             return;
116         }
117 
118         GpuStatsAppInfo appInfo;
119         addLoadingTime(driver, driverLoadingTime, &appInfo);
120         appInfo.appPackageName = appPackageName;
121         appInfo.driverVersionCode = driverVersionCode;
122         mAppStats.insert({appStatsKey, appInfo});
123         return;
124     }
125 
126     addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
127 }
128 
insertTargetStats(const std::string & appPackageName,const uint64_t driverVersionCode,const GraphicsEnv::Stats stats,const uint64_t)129 void GpuStats::insertTargetStats(const std::string& appPackageName,
130                                  const uint64_t driverVersionCode, const GraphicsEnv::Stats stats,
131                                  const uint64_t /*value*/) {
132     ATRACE_CALL();
133 
134     const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
135 
136     std::lock_guard<std::mutex> lock(mLock);
137     if (!mAppStats.count(appStatsKey)) {
138         return;
139     }
140 
141     switch (stats) {
142         case GraphicsEnv::Stats::CPU_VULKAN_IN_USE:
143             mAppStats[appStatsKey].cpuVulkanInUse = true;
144             break;
145         default:
146             break;
147     }
148 }
149 
interceptSystemDriverStatsLocked()150 void GpuStats::interceptSystemDriverStatsLocked() {
151     // Append cpuVulkanVersion and glesVersion to system driver stats
152     if (!mGlobalStats.count(0) || mGlobalStats[0].glesVersion) {
153         return;
154     }
155 
156     mGlobalStats[0].cpuVulkanVersion = property_get_int32("ro.cpuvulkan.version", 0);
157     mGlobalStats[0].glesVersion = property_get_int32("ro.opengles.version", 0);
158 }
159 
dump(const Vector<String16> & args,std::string * result)160 void GpuStats::dump(const Vector<String16>& args, std::string* result) {
161     ATRACE_CALL();
162 
163     if (!result) {
164         ALOGE("Dump result shouldn't be nullptr.");
165         return;
166     }
167 
168     std::lock_guard<std::mutex> lock(mLock);
169     bool dumpAll = true;
170 
171     std::unordered_set<std::string> argsSet;
172     for (size_t i = 0; i < args.size(); i++) {
173         argsSet.insert(String8(args[i]).c_str());
174     }
175 
176     const bool dumpGlobal = argsSet.count("--global") != 0;
177     if (dumpGlobal) {
178         dumpGlobalLocked(result);
179         dumpAll = false;
180     }
181 
182     const bool dumpApp = argsSet.count("--app") != 0;
183     if (dumpApp) {
184         dumpAppLocked(result);
185         dumpAll = false;
186     }
187 
188     if (argsSet.count("--clear")) {
189         bool clearAll = true;
190 
191         if (dumpGlobal) {
192             mGlobalStats.clear();
193             clearAll = false;
194         }
195 
196         if (dumpApp) {
197             mAppStats.clear();
198             clearAll = false;
199         }
200 
201         if (clearAll) {
202             mGlobalStats.clear();
203             mAppStats.clear();
204         }
205 
206         dumpAll = false;
207     }
208 
209     if (dumpAll) {
210         dumpGlobalLocked(result);
211         dumpAppLocked(result);
212     }
213 }
214 
dumpGlobalLocked(std::string * result)215 void GpuStats::dumpGlobalLocked(std::string* result) {
216     interceptSystemDriverStatsLocked();
217 
218     for (const auto& ele : mGlobalStats) {
219         result->append(ele.second.toString());
220         result->append("\n");
221     }
222 }
223 
dumpAppLocked(std::string * result)224 void GpuStats::dumpAppLocked(std::string* result) {
225     for (const auto& ele : mAppStats) {
226         result->append(ele.second.toString());
227         result->append("\n");
228     }
229 }
230 
pullGlobalStats(std::vector<GpuStatsGlobalInfo> * outStats)231 void GpuStats::pullGlobalStats(std::vector<GpuStatsGlobalInfo>* outStats) {
232     ATRACE_CALL();
233 
234     std::lock_guard<std::mutex> lock(mLock);
235     outStats->clear();
236     outStats->reserve(mGlobalStats.size());
237 
238     interceptSystemDriverStatsLocked();
239 
240     for (const auto& ele : mGlobalStats) {
241         outStats->emplace_back(ele.second);
242     }
243 
244     mGlobalStats.clear();
245 }
246 
pullAppStats(std::vector<GpuStatsAppInfo> * outStats)247 void GpuStats::pullAppStats(std::vector<GpuStatsAppInfo>* outStats) {
248     ATRACE_CALL();
249 
250     std::lock_guard<std::mutex> lock(mLock);
251     outStats->clear();
252     outStats->reserve(mAppStats.size());
253 
254     for (const auto& ele : mAppStats) {
255         outStats->emplace_back(ele.second);
256     }
257 
258     mAppStats.clear();
259 }
260 
261 } // namespace android
262