• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/GpuStats.h"
21 
22 #include <android/util/ProtoOutputStream.h>
23 #include <cutils/properties.h>
24 #include <log/log.h>
25 #include <stats_event.h>
26 #include <statslog.h>
27 #include <utils/Trace.h>
28 
29 #include <unordered_set>
30 
31 namespace android {
32 
~GpuStats()33 GpuStats::~GpuStats() {
34     if (mStatsdRegistered) {
35         AStatsManager_clearPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO);
36         AStatsManager_clearPullAtomCallback(android::util::GPU_STATS_APP_INFO);
37     }
38 }
39 
addLoadingCount(GpuStatsInfo::Driver driver,bool isDriverLoaded,GpuStatsGlobalInfo * const outGlobalInfo)40 static void addLoadingCount(GpuStatsInfo::Driver driver, bool isDriverLoaded,
41                             GpuStatsGlobalInfo* const outGlobalInfo) {
42     switch (driver) {
43         case GpuStatsInfo::Driver::GL:
44         case GpuStatsInfo::Driver::GL_UPDATED:
45             outGlobalInfo->glLoadingCount++;
46             if (!isDriverLoaded) outGlobalInfo->glLoadingFailureCount++;
47             break;
48         case GpuStatsInfo::Driver::VULKAN:
49         case GpuStatsInfo::Driver::VULKAN_UPDATED:
50             outGlobalInfo->vkLoadingCount++;
51             if (!isDriverLoaded) outGlobalInfo->vkLoadingFailureCount++;
52             break;
53         case GpuStatsInfo::Driver::ANGLE:
54             outGlobalInfo->angleLoadingCount++;
55             if (!isDriverLoaded) outGlobalInfo->angleLoadingFailureCount++;
56             break;
57         default:
58             break;
59     }
60 }
61 
addLoadingTime(GpuStatsInfo::Driver driver,int64_t driverLoadingTime,GpuStatsAppInfo * const outAppInfo)62 static void addLoadingTime(GpuStatsInfo::Driver driver, int64_t driverLoadingTime,
63                            GpuStatsAppInfo* const outAppInfo) {
64     switch (driver) {
65         case GpuStatsInfo::Driver::GL:
66         case GpuStatsInfo::Driver::GL_UPDATED:
67             if (outAppInfo->glDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) {
68                 outAppInfo->glDriverLoadingTime.emplace_back(driverLoadingTime);
69             }
70             break;
71         case GpuStatsInfo::Driver::VULKAN:
72         case GpuStatsInfo::Driver::VULKAN_UPDATED:
73             if (outAppInfo->vkDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) {
74                 outAppInfo->vkDriverLoadingTime.emplace_back(driverLoadingTime);
75             }
76             break;
77         case GpuStatsInfo::Driver::ANGLE:
78             if (outAppInfo->angleDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) {
79                 outAppInfo->angleDriverLoadingTime.emplace_back(driverLoadingTime);
80             }
81             break;
82         default:
83             break;
84     }
85 }
86 
insertDriverStats(const std::string & driverPackageName,const std::string & driverVersionName,uint64_t driverVersionCode,int64_t driverBuildTime,const std::string & appPackageName,const int32_t vulkanVersion,GpuStatsInfo::Driver driver,bool isDriverLoaded,int64_t driverLoadingTime)87 void GpuStats::insertDriverStats(const std::string& driverPackageName,
88                                  const std::string& driverVersionName, uint64_t driverVersionCode,
89                                  int64_t driverBuildTime, const std::string& appPackageName,
90                                  const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
91                                  bool isDriverLoaded, int64_t driverLoadingTime) {
92     ATRACE_CALL();
93 
94     std::lock_guard<std::mutex> lock(mLock);
95     registerStatsdCallbacksIfNeeded();
96     ALOGV("Received:\n"
97           "\tdriverPackageName[%s]\n"
98           "\tdriverVersionName[%s]\n"
99           "\tdriverVersionCode[%" PRIu64 "]\n"
100           "\tdriverBuildTime[%" PRId64 "]\n"
101           "\tappPackageName[%s]\n"
102           "\tvulkanVersion[%d]\n"
103           "\tdriver[%d]\n"
104           "\tisDriverLoaded[%d]\n"
105           "\tdriverLoadingTime[%" PRId64 "]",
106           driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
107           appPackageName.c_str(), vulkanVersion, static_cast<int32_t>(driver), isDriverLoaded,
108           driverLoadingTime);
109 
110     if (!mGlobalStats.count(driverVersionCode)) {
111         GpuStatsGlobalInfo globalInfo;
112         addLoadingCount(driver, isDriverLoaded, &globalInfo);
113         globalInfo.driverPackageName = driverPackageName;
114         globalInfo.driverVersionName = driverVersionName;
115         globalInfo.driverVersionCode = driverVersionCode;
116         globalInfo.driverBuildTime = driverBuildTime;
117         globalInfo.vulkanVersion = vulkanVersion;
118         mGlobalStats.insert({driverVersionCode, globalInfo});
119     } else {
120         addLoadingCount(driver, isDriverLoaded, &mGlobalStats[driverVersionCode]);
121     }
122 
123     const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
124     if (!mAppStats.count(appStatsKey)) {
125         if (mAppStats.size() >= MAX_NUM_APP_RECORDS) {
126             ALOGV("GpuStatsAppInfo has reached maximum size. Ignore new stats.");
127             return;
128         }
129 
130         GpuStatsAppInfo appInfo;
131         addLoadingTime(driver, driverLoadingTime, &appInfo);
132         appInfo.appPackageName = appPackageName;
133         appInfo.driverVersionCode = driverVersionCode;
134         mAppStats.insert({appStatsKey, appInfo});
135         return;
136     }
137 
138     addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
139 }
140 
insertTargetStats(const std::string & appPackageName,const uint64_t driverVersionCode,const GpuStatsInfo::Stats stats,const uint64_t)141 void GpuStats::insertTargetStats(const std::string& appPackageName,
142                                  const uint64_t driverVersionCode, const GpuStatsInfo::Stats stats,
143                                  const uint64_t /*value*/) {
144     ATRACE_CALL();
145 
146     const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
147 
148     std::lock_guard<std::mutex> lock(mLock);
149     registerStatsdCallbacksIfNeeded();
150     if (!mAppStats.count(appStatsKey)) {
151         return;
152     }
153 
154     switch (stats) {
155         case GpuStatsInfo::Stats::CPU_VULKAN_IN_USE:
156             mAppStats[appStatsKey].cpuVulkanInUse = true;
157             break;
158         case GpuStatsInfo::Stats::FALSE_PREROTATION:
159             mAppStats[appStatsKey].falsePrerotation = true;
160             break;
161         case GpuStatsInfo::Stats::GLES_1_IN_USE:
162             mAppStats[appStatsKey].gles1InUse = true;
163             break;
164         default:
165             break;
166     }
167 }
168 
interceptSystemDriverStatsLocked()169 void GpuStats::interceptSystemDriverStatsLocked() {
170     // Append cpuVulkanVersion and glesVersion to system driver stats
171     if (!mGlobalStats.count(0) || mGlobalStats[0].glesVersion) {
172         return;
173     }
174 
175     mGlobalStats[0].cpuVulkanVersion = property_get_int32("ro.cpuvulkan.version", 0);
176     mGlobalStats[0].glesVersion = property_get_int32("ro.opengles.version", 0);
177 }
178 
registerStatsdCallbacksIfNeeded()179 void GpuStats::registerStatsdCallbacksIfNeeded() {
180     if (!mStatsdRegistered) {
181         AStatsManager_setPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO, nullptr,
182                                          GpuStats::pullAtomCallback, this);
183         AStatsManager_setPullAtomCallback(android::util::GPU_STATS_APP_INFO, nullptr,
184                                          GpuStats::pullAtomCallback, this);
185         mStatsdRegistered = true;
186     }
187 }
188 
dump(const Vector<String16> & args,std::string * result)189 void GpuStats::dump(const Vector<String16>& args, std::string* result) {
190     ATRACE_CALL();
191 
192     if (!result) {
193         ALOGE("Dump result shouldn't be nullptr.");
194         return;
195     }
196 
197     std::lock_guard<std::mutex> lock(mLock);
198     bool dumpAll = true;
199 
200     std::unordered_set<std::string> argsSet;
201     for (size_t i = 0; i < args.size(); i++) {
202         argsSet.insert(String8(args[i]).c_str());
203     }
204 
205     const bool dumpGlobal = argsSet.count("--global") != 0;
206     if (dumpGlobal) {
207         dumpGlobalLocked(result);
208         dumpAll = false;
209     }
210 
211     const bool dumpApp = argsSet.count("--app") != 0;
212     if (dumpApp) {
213         dumpAppLocked(result);
214         dumpAll = false;
215     }
216 
217     if (dumpAll) {
218         dumpGlobalLocked(result);
219         dumpAppLocked(result);
220     }
221 
222     if (argsSet.count("--clear")) {
223         bool clearAll = true;
224 
225         if (dumpGlobal) {
226             mGlobalStats.clear();
227             clearAll = false;
228         }
229 
230         if (dumpApp) {
231             mAppStats.clear();
232             clearAll = false;
233         }
234 
235         if (clearAll) {
236             mGlobalStats.clear();
237             mAppStats.clear();
238         }
239     }
240 }
241 
dumpGlobalLocked(std::string * result)242 void GpuStats::dumpGlobalLocked(std::string* result) {
243     interceptSystemDriverStatsLocked();
244 
245     for (const auto& ele : mGlobalStats) {
246         result->append(ele.second.toString());
247         result->append("\n");
248     }
249 }
250 
dumpAppLocked(std::string * result)251 void GpuStats::dumpAppLocked(std::string* result) {
252     for (const auto& ele : mAppStats) {
253         result->append(ele.second.toString());
254         result->append("\n");
255     }
256 }
257 
protoOutputStreamToByteString(android::util::ProtoOutputStream & proto)258 static std::string protoOutputStreamToByteString(android::util::ProtoOutputStream& proto) {
259     if (!proto.size()) return "";
260 
261     std::string byteString;
262     sp<android::util::ProtoReader> reader = proto.data();
263     while (reader->readBuffer() != nullptr) {
264         const size_t toRead = reader->currentToRead();
265         byteString.append((char*)reader->readBuffer(), toRead);
266         reader->move(toRead);
267     }
268 
269     if (byteString.size() != proto.size()) return "";
270 
271     return byteString;
272 }
273 
int64VectorToProtoByteString(const std::vector<int64_t> & value)274 static std::string int64VectorToProtoByteString(const std::vector<int64_t>& value) {
275     if (value.empty()) return "";
276 
277     android::util::ProtoOutputStream proto;
278     for (const auto& ele : value) {
279         proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
280                             1 /* field id */,
281                     (long long)ele);
282     }
283 
284     return protoOutputStreamToByteString(proto);
285 }
286 
pullAppInfoAtom(AStatsEventList * data)287 AStatsManager_PullAtomCallbackReturn GpuStats::pullAppInfoAtom(AStatsEventList* data) {
288     ATRACE_CALL();
289 
290     std::lock_guard<std::mutex> lock(mLock);
291 
292     if (data) {
293         for (const auto& ele : mAppStats) {
294             std::string glDriverBytes = int64VectorToProtoByteString(
295                 ele.second.glDriverLoadingTime);
296             std::string vkDriverBytes = int64VectorToProtoByteString(
297                 ele.second.vkDriverLoadingTime);
298             std::string angleDriverBytes = int64VectorToProtoByteString(
299                 ele.second.angleDriverLoadingTime);
300 
301             android::util::addAStatsEvent(
302                     data,
303                     android::util::GPU_STATS_APP_INFO,
304                     ele.second.appPackageName.c_str(),
305                     ele.second.driverVersionCode,
306                     android::util::BytesField(glDriverBytes.c_str(),
307                                               glDriverBytes.length()),
308                     android::util::BytesField(vkDriverBytes.c_str(),
309                                               vkDriverBytes.length()),
310                     android::util::BytesField(angleDriverBytes.c_str(),
311                                               angleDriverBytes.length()),
312                     ele.second.cpuVulkanInUse,
313                     ele.second.falsePrerotation,
314                     ele.second.gles1InUse);
315         }
316     }
317 
318     mAppStats.clear();
319 
320     return AStatsManager_PULL_SUCCESS;
321 }
322 
pullGlobalInfoAtom(AStatsEventList * data)323 AStatsManager_PullAtomCallbackReturn GpuStats::pullGlobalInfoAtom(AStatsEventList* data) {
324     ATRACE_CALL();
325 
326     std::lock_guard<std::mutex> lock(mLock);
327     // flush cpuVulkanVersion and glesVersion to builtin driver stats
328     interceptSystemDriverStatsLocked();
329 
330     if (data) {
331         for (const auto& ele : mGlobalStats) {
332           android::util::addAStatsEvent(
333                   data,
334                   android::util::GPU_STATS_GLOBAL_INFO,
335                   ele.second.driverPackageName.c_str(),
336                   ele.second.driverVersionName.c_str(),
337                   ele.second.driverVersionCode,
338                   ele.second.driverBuildTime,
339                   ele.second.glLoadingCount,
340                   ele.second.glLoadingFailureCount,
341                   ele.second.vkLoadingCount,
342                   ele.second.vkLoadingFailureCount,
343                   ele.second.vulkanVersion,
344                   ele.second.cpuVulkanVersion,
345                   ele.second.glesVersion,
346                   ele.second.angleLoadingCount,
347                   ele.second.angleLoadingFailureCount);
348         }
349     }
350 
351     mGlobalStats.clear();
352 
353     return AStatsManager_PULL_SUCCESS;
354 }
355 
pullAtomCallback(int32_t atomTag,AStatsEventList * data,void * cookie)356 AStatsManager_PullAtomCallbackReturn GpuStats::pullAtomCallback(int32_t atomTag,
357                                                                 AStatsEventList* data,
358                                                                 void* cookie) {
359     ATRACE_CALL();
360 
361     GpuStats* pGpuStats = reinterpret_cast<GpuStats*>(cookie);
362     if (atomTag == android::util::GPU_STATS_GLOBAL_INFO) {
363         return pGpuStats->pullGlobalInfoAtom(data);
364     } else if (atomTag == android::util::GPU_STATS_APP_INFO) {
365         return pGpuStats->pullAppInfoAtom(data);
366     }
367 
368     return AStatsManager_PULL_SKIP;
369 }
370 
371 } // namespace android
372