/* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #undef LOG_TAG #define LOG_TAG "GpuStats" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "gpustats/GpuStats.h" #include #include #include #include #include #include #include namespace android { GpuStats::~GpuStats() { if (mStatsdRegistered) { AStatsManager_clearPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO); AStatsManager_clearPullAtomCallback(android::util::GPU_STATS_APP_INFO); } } static void addLoadingCount(GpuStatsInfo::Driver driver, bool isDriverLoaded, GpuStatsGlobalInfo* const outGlobalInfo) { switch (driver) { case GpuStatsInfo::Driver::GL: case GpuStatsInfo::Driver::GL_UPDATED: outGlobalInfo->glLoadingCount++; if (!isDriverLoaded) outGlobalInfo->glLoadingFailureCount++; break; case GpuStatsInfo::Driver::VULKAN: case GpuStatsInfo::Driver::VULKAN_UPDATED: outGlobalInfo->vkLoadingCount++; if (!isDriverLoaded) outGlobalInfo->vkLoadingFailureCount++; break; case GpuStatsInfo::Driver::ANGLE: outGlobalInfo->angleLoadingCount++; if (!isDriverLoaded) outGlobalInfo->angleLoadingFailureCount++; break; default: break; } } static void addLoadingTime(GpuStatsInfo::Driver driver, int64_t driverLoadingTime, GpuStatsAppInfo* const outAppInfo) { switch (driver) { case GpuStatsInfo::Driver::GL: case GpuStatsInfo::Driver::GL_UPDATED: if (outAppInfo->glDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->glDriverLoadingTime.emplace_back(driverLoadingTime); } break; case GpuStatsInfo::Driver::VULKAN: case GpuStatsInfo::Driver::VULKAN_UPDATED: if (outAppInfo->vkDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->vkDriverLoadingTime.emplace_back(driverLoadingTime); } break; case GpuStatsInfo::Driver::ANGLE: if (outAppInfo->angleDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->angleDriverLoadingTime.emplace_back(driverLoadingTime); } break; default: break; } } void GpuStats::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) { ATRACE_CALL(); std::lock_guard lock(mLock); registerStatsdCallbacksIfNeeded(); ALOGV("Received:\n" "\tdriverPackageName[%s]\n" "\tdriverVersionName[%s]\n" "\tdriverVersionCode[%" PRIu64 "]\n" "\tdriverBuildTime[%" PRId64 "]\n" "\tappPackageName[%s]\n" "\tvulkanVersion[%d]\n" "\tdriver[%d]\n" "\tisDriverLoaded[%d]\n" "\tdriverLoadingTime[%" PRId64 "]", driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime, appPackageName.c_str(), vulkanVersion, static_cast(driver), isDriverLoaded, driverLoadingTime); if (!mGlobalStats.count(driverVersionCode)) { GpuStatsGlobalInfo globalInfo; addLoadingCount(driver, isDriverLoaded, &globalInfo); globalInfo.driverPackageName = driverPackageName; globalInfo.driverVersionName = driverVersionName; globalInfo.driverVersionCode = driverVersionCode; globalInfo.driverBuildTime = driverBuildTime; globalInfo.vulkanVersion = vulkanVersion; mGlobalStats.insert({driverVersionCode, globalInfo}); } else { addLoadingCount(driver, isDriverLoaded, &mGlobalStats[driverVersionCode]); } const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode); if (!mAppStats.count(appStatsKey)) { if (mAppStats.size() >= MAX_NUM_APP_RECORDS) { ALOGV("GpuStatsAppInfo has reached maximum size. Ignore new stats."); return; } GpuStatsAppInfo appInfo; addLoadingTime(driver, driverLoadingTime, &appInfo); appInfo.appPackageName = appPackageName; appInfo.driverVersionCode = driverVersionCode; mAppStats.insert({appStatsKey, appInfo}); return; } addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]); } void GpuStats::insertTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, const GpuStatsInfo::Stats stats, const uint64_t /*value*/) { ATRACE_CALL(); const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode); std::lock_guard lock(mLock); registerStatsdCallbacksIfNeeded(); if (!mAppStats.count(appStatsKey)) { return; } switch (stats) { case GpuStatsInfo::Stats::CPU_VULKAN_IN_USE: mAppStats[appStatsKey].cpuVulkanInUse = true; break; case GpuStatsInfo::Stats::FALSE_PREROTATION: mAppStats[appStatsKey].falsePrerotation = true; break; case GpuStatsInfo::Stats::GLES_1_IN_USE: mAppStats[appStatsKey].gles1InUse = true; break; default: break; } } void GpuStats::interceptSystemDriverStatsLocked() { // Append cpuVulkanVersion and glesVersion to system driver stats if (!mGlobalStats.count(0) || mGlobalStats[0].glesVersion) { return; } mGlobalStats[0].cpuVulkanVersion = property_get_int32("ro.cpuvulkan.version", 0); mGlobalStats[0].glesVersion = property_get_int32("ro.opengles.version", 0); } void GpuStats::registerStatsdCallbacksIfNeeded() { if (!mStatsdRegistered) { AStatsManager_setPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO, nullptr, GpuStats::pullAtomCallback, this); AStatsManager_setPullAtomCallback(android::util::GPU_STATS_APP_INFO, nullptr, GpuStats::pullAtomCallback, this); mStatsdRegistered = true; } } void GpuStats::dump(const Vector& args, std::string* result) { ATRACE_CALL(); if (!result) { ALOGE("Dump result shouldn't be nullptr."); return; } std::lock_guard lock(mLock); bool dumpAll = true; std::unordered_set argsSet; for (size_t i = 0; i < args.size(); i++) { argsSet.insert(String8(args[i]).c_str()); } const bool dumpGlobal = argsSet.count("--global") != 0; if (dumpGlobal) { dumpGlobalLocked(result); dumpAll = false; } const bool dumpApp = argsSet.count("--app") != 0; if (dumpApp) { dumpAppLocked(result); dumpAll = false; } if (dumpAll) { dumpGlobalLocked(result); dumpAppLocked(result); } if (argsSet.count("--clear")) { bool clearAll = true; if (dumpGlobal) { mGlobalStats.clear(); clearAll = false; } if (dumpApp) { mAppStats.clear(); clearAll = false; } if (clearAll) { mGlobalStats.clear(); mAppStats.clear(); } } } void GpuStats::dumpGlobalLocked(std::string* result) { interceptSystemDriverStatsLocked(); for (const auto& ele : mGlobalStats) { result->append(ele.second.toString()); result->append("\n"); } } void GpuStats::dumpAppLocked(std::string* result) { for (const auto& ele : mAppStats) { result->append(ele.second.toString()); result->append("\n"); } } static std::string protoOutputStreamToByteString(android::util::ProtoOutputStream& proto) { if (!proto.size()) return ""; std::string byteString; sp reader = proto.data(); while (reader->readBuffer() != nullptr) { const size_t toRead = reader->currentToRead(); byteString.append((char*)reader->readBuffer(), toRead); reader->move(toRead); } if (byteString.size() != proto.size()) return ""; return byteString; } static std::string int64VectorToProtoByteString(const std::vector& value) { if (value.empty()) return ""; android::util::ProtoOutputStream proto; for (const auto& ele : value) { proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED | 1 /* field id */, (long long)ele); } return protoOutputStreamToByteString(proto); } AStatsManager_PullAtomCallbackReturn GpuStats::pullAppInfoAtom(AStatsEventList* data) { ATRACE_CALL(); std::lock_guard lock(mLock); if (data) { for (const auto& ele : mAppStats) { std::string glDriverBytes = int64VectorToProtoByteString( ele.second.glDriverLoadingTime); std::string vkDriverBytes = int64VectorToProtoByteString( ele.second.vkDriverLoadingTime); std::string angleDriverBytes = int64VectorToProtoByteString( ele.second.angleDriverLoadingTime); android::util::addAStatsEvent( data, android::util::GPU_STATS_APP_INFO, ele.second.appPackageName.c_str(), ele.second.driverVersionCode, android::util::BytesField(glDriverBytes.c_str(), glDriverBytes.length()), android::util::BytesField(vkDriverBytes.c_str(), vkDriverBytes.length()), android::util::BytesField(angleDriverBytes.c_str(), angleDriverBytes.length()), ele.second.cpuVulkanInUse, ele.second.falsePrerotation, ele.second.gles1InUse); } } mAppStats.clear(); return AStatsManager_PULL_SUCCESS; } AStatsManager_PullAtomCallbackReturn GpuStats::pullGlobalInfoAtom(AStatsEventList* data) { ATRACE_CALL(); std::lock_guard lock(mLock); // flush cpuVulkanVersion and glesVersion to builtin driver stats interceptSystemDriverStatsLocked(); if (data) { for (const auto& ele : mGlobalStats) { android::util::addAStatsEvent( data, android::util::GPU_STATS_GLOBAL_INFO, ele.second.driverPackageName.c_str(), ele.second.driverVersionName.c_str(), ele.second.driverVersionCode, ele.second.driverBuildTime, ele.second.glLoadingCount, ele.second.glLoadingFailureCount, ele.second.vkLoadingCount, ele.second.vkLoadingFailureCount, ele.second.vulkanVersion, ele.second.cpuVulkanVersion, ele.second.glesVersion, ele.second.angleLoadingCount, ele.second.angleLoadingFailureCount); } } mGlobalStats.clear(); return AStatsManager_PULL_SUCCESS; } AStatsManager_PullAtomCallbackReturn GpuStats::pullAtomCallback(int32_t atomTag, AStatsEventList* data, void* cookie) { ATRACE_CALL(); GpuStats* pGpuStats = reinterpret_cast(cookie); if (atomTag == android::util::GPU_STATS_GLOBAL_INFO) { return pGpuStats->pullGlobalInfoAtom(data); } else if (atomTag == android::util::GPU_STATS_APP_INFO) { return pGpuStats->pullAppInfoAtom(data); } return AStatsManager_PULL_SKIP; } } // namespace android