1df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck/* 2df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * Copyright (C) 2017 The Android Open Source Project 3df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * 4df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * Licensed under the Apache License, Version 2.0 (the "License"); 5df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * you may not use this file except in compliance with the License. 6df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * You may obtain a copy of the License at 7df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * 8df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * http://www.apache.org/licenses/LICENSE-2.0 9df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * 10df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * Unless required by applicable law or agreed to in writing, software 11df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * distributed under the License is distributed on an "AS IS" BASIS, 12df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * See the License for the specific language governing permissions and 14df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck * limitations under the License. 15df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck */ 16df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 17df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include "GraphicsStatsService.h" 18df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 19df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include "JankTracker.h" 20df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 21df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <frameworks/base/core/proto/android/service/graphicsstats.pb.h> 22df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <google/protobuf/io/zero_copy_stream_impl.h> 23df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <log/log.h> 24df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 25df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <inttypes.h> 26df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <sys/types.h> 27df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <sys/stat.h> 28df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <fcntl.h> 29df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck#include <unistd.h> 30df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 31df1742ed47da1e9b61afeae16fa448d5302a8aa0John Recknamespace android { 32df1742ed47da1e9b61afeae16fa448d5302a8aa0John Recknamespace uirenderer { 33df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 34df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckusing namespace google::protobuf; 35df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 36df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckconstexpr int32_t sCurrentFileVersion = 1; 37df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckconstexpr int32_t sHeaderSize = 4; 38df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckstatic_assert(sizeof(sCurrentFileVersion) == sHeaderSize, "Header size is wrong"); 39df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 40df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckconstexpr int sHistogramSize = 41df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck std::tuple_size<decltype(ProfileData::frameCounts)>::value + 42df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck std::tuple_size<decltype(ProfileData::slowFrameCounts)>::value; 43df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 44df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckstatic void mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, 45df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck const std::string& package, int versionCode, int64_t startTime, int64_t endTime, 46df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck const ProfileData* data); 47df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckstatic void dumpAsTextToFd(service::GraphicsStatsProto* proto, int outFd); 48df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 49df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckbool GraphicsStatsService::parseFromFile(const std::string& path, service::GraphicsStatsProto* output) { 50df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 51df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int fd = open(path.c_str(), O_RDONLY); 52df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (fd == -1) { 53df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int err = errno; 54df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck // The file not existing is normal for addToDump(), so only log if 55df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck // we get an unexpected error 56df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (err != ENOENT) { 57df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck ALOGW("Failed to open '%s', errno=%d (%s)", path.c_str(), err, strerror(err)); 58df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 59df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck return false; 60df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 61df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck uint32_t file_version; 62df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck ssize_t bytesRead = read(fd, &file_version, sHeaderSize); 63df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (bytesRead != sHeaderSize || file_version != sCurrentFileVersion) { 64df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck ALOGW("Failed to read '%s', bytesRead=%zd file_version=%d", path.c_str(), bytesRead, 65df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck file_version); 66df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck close(fd); 67df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck return false; 68df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 69df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 70df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck io::FileInputStream input(fd); 71df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bool success = output->ParseFromZeroCopyStream(&input); 72df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (input.GetErrno() != 0) { 73df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck ALOGW("Error reading from fd=%d, path='%s' err=%d (%s)", 74df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck fd, path.c_str(), input.GetErrno(), strerror(input.GetErrno())); 75df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck success = false; 76df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } else if (!success) { 77df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck ALOGW("Parse failed on '%s' error='%s'", 78df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck path.c_str(), output->InitializationErrorString().c_str()); 79df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 80df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck close(fd); 81df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck return success; 82df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} 83df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 84df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package, 85df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) { 86df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (proto->stats_start() == 0 || proto->stats_start() > startTime) { 87df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck proto->set_stats_start(startTime); 88df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 89df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (proto->stats_end() == 0 || proto->stats_end() < endTime) { 90df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck proto->set_stats_end(endTime); 91df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 92df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck proto->set_package_name(package); 93df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck proto->set_version_code(versionCode); 94df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck auto summary = proto->mutable_summary(); 95df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->set_total_frames(summary->total_frames() + data->totalFrameCount); 96df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->set_janky_frames(summary->janky_frames() + data->jankFrameCount); 97df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->set_missed_vsync_count( 98df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->missed_vsync_count() + data->jankTypeCounts[kMissedVsync]); 99df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->set_high_input_latency_count( 100df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->high_input_latency_count() + data->jankTypeCounts[kHighInputLatency]); 101df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->set_slow_ui_thread_count( 102df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->slow_ui_thread_count() + data->jankTypeCounts[kSlowUI]); 103df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->set_slow_bitmap_upload_count( 104df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->slow_bitmap_upload_count() + data->jankTypeCounts[kSlowSync]); 105df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->set_slow_draw_count( 106df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck summary->slow_draw_count() + data->jankTypeCounts[kSlowRT]); 107df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 108df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bool creatingHistogram = false; 109df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (proto->histogram_size() == 0) { 110df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck proto->mutable_histogram()->Reserve(sHistogramSize); 111df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck creatingHistogram = true; 112df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } else if (proto->histogram_size() != sHistogramSize) { 113df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck LOG_ALWAYS_FATAL("Histogram size mismatch, proto is %d expected %d", 114df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck proto->histogram_size(), sHistogramSize); 115df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 116df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck for (size_t i = 0; i < data->frameCounts.size(); i++) { 117df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck service::GraphicsStatsHistogramBucketProto* bucket; 118df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int32_t renderTime = JankTracker::frameTimeForFrameCountIndex(i); 119df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (creatingHistogram) { 120df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bucket = proto->add_histogram(); 121df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bucket->set_render_millis(renderTime); 122df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } else { 123df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bucket = proto->mutable_histogram(i); 124df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck LOG_ALWAYS_FATAL_IF(bucket->render_millis() != renderTime, 125df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck "Frame time mistmatch %d vs. %d", bucket->render_millis(), renderTime); 126df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 127df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bucket->set_frame_count(bucket->frame_count() + data->frameCounts[i]); 128df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 129df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck for (size_t i = 0; i < data->slowFrameCounts.size(); i++) { 130df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck service::GraphicsStatsHistogramBucketProto* bucket; 131df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int32_t renderTime = JankTracker::frameTimeForSlowFrameCountIndex(i); 132df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (creatingHistogram) { 133df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bucket = proto->add_histogram(); 134df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bucket->set_render_millis(renderTime); 135df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } else { 136df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck constexpr int offset = std::tuple_size<decltype(ProfileData::frameCounts)>::value; 137df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bucket = proto->mutable_histogram(offset + i); 138df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck LOG_ALWAYS_FATAL_IF(bucket->render_millis() != renderTime, 139df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck "Frame time mistmatch %d vs. %d", bucket->render_millis(), renderTime); 140df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 141df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bucket->set_frame_count(bucket->frame_count() + data->slowFrameCounts[i]); 142df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 143df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} 144df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 145df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckstatic int32_t findPercentile(service::GraphicsStatsProto* proto, int percentile) { 146df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int32_t pos = percentile * proto->summary().total_frames() / 100; 147df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int32_t remaining = proto->summary().total_frames() - pos; 148df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck for (auto it = proto->histogram().rbegin(); it != proto->histogram().rend(); ++it) { 149df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck remaining -= it->frame_count(); 150df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (remaining <= 0) { 151df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck return it->render_millis(); 152df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 153df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 154df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck return 0; 155df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} 156df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 157df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid dumpAsTextToFd(service::GraphicsStatsProto* proto, int fd) { 158df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck // This isn't a full validation, just enough that we can deref at will 159df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck LOG_ALWAYS_FATAL_IF(proto->package_name().empty() 160df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck || !proto->has_summary(), "package_name() '%s' summary %d", 161df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck proto->package_name().c_str(), proto->has_summary()); 162df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nPackage: %s", proto->package_name().c_str()); 163df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nVersion: %d", proto->version_code()); 164df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nStats since: %lldns", proto->stats_start()); 165df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nStats end: %lldns", proto->stats_end()); 166df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck auto summary = proto->summary(); 167df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nTotal frames rendered: %d", summary.total_frames()); 168df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nJanky frames: %d (%.2f%%)", summary.janky_frames(), 169df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck (float) summary.janky_frames() / (float) summary.total_frames() * 100.0f); 170df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\n50th percentile: %dms", findPercentile(proto, 50)); 171df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\n90th percentile: %dms", findPercentile(proto, 90)); 172df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\n95th percentile: %dms", findPercentile(proto, 95)); 173df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\n99th percentile: %dms", findPercentile(proto, 99)); 174df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nNumber Missed Vsync: %d", summary.missed_vsync_count()); 175df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nNumber High input latency: %d", summary.high_input_latency_count()); 176df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nNumber Slow UI thread: %d", summary.slow_ui_thread_count()); 177df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nNumber Slow bitmap uploads: %d", summary.slow_bitmap_upload_count()); 178df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nNumber Slow issue draw commands: %d", summary.slow_draw_count()); 179df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\nHISTOGRAM:"); 180df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck for (const auto& it : proto->histogram()) { 181df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count()); 182df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 183df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dprintf(fd, "\n"); 184df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} 185df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 186df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid GraphicsStatsService::saveBuffer(const std::string& path, const std::string& package, 187df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) { 188df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck service::GraphicsStatsProto statsProto; 189df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (!parseFromFile(path, &statsProto)) { 190df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck statsProto.Clear(); 191df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 192df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data); 193df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck // Although we might not have read any data from the file, merging the existing data 194df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck // should always fully-initialize the proto 195df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck LOG_ALWAYS_FATAL_IF(!statsProto.IsInitialized(), "%s", 196df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck statsProto.InitializationErrorString().c_str()); 197df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck LOG_ALWAYS_FATAL_IF(statsProto.package_name().empty() 198df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck || !statsProto.has_summary(), "package_name() '%s' summary %d", 199df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck statsProto.package_name().c_str(), statsProto.has_summary()); 200df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int outFd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0660); 201df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (outFd <= 0) { 202df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int err = errno; 203df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck ALOGW("Failed to open '%s', error=%d (%s)", path.c_str(), err, strerror(err)); 204df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck return; 205df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 206df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int wrote = write(outFd, &sCurrentFileVersion, sHeaderSize); 207df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (wrote != sHeaderSize) { 208df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int err = errno; 209df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck ALOGW("Failed to write header to '%s', returned=%d errno=%d (%s)", 210df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck path.c_str(), wrote, err, strerror(err)); 211df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck close(outFd); 212df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck return; 213df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 214df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck { 215df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck io::FileOutputStream output(outFd); 216df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck bool success = statsProto.SerializeToZeroCopyStream(&output) && output.Flush(); 217df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (output.GetErrno() != 0) { 218df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck ALOGW("Error writing to fd=%d, path='%s' err=%d (%s)", 219df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck outFd, path.c_str(), output.GetErrno(), strerror(output.GetErrno())); 220df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck success = false; 221df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } else if (!success) { 222df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck ALOGW("Serialize failed on '%s' unknown error", path.c_str()); 223df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 224df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 225df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck close(outFd); 226df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} 227df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 228df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckclass GraphicsStatsService::Dump { 229df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckpublic: 230df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck Dump(int outFd, DumpType type) : mFd(outFd), mType(type) {} 231df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int fd() { return mFd; } 232df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck DumpType type() { return mType; } 233df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck service::GraphicsStatsServiceDumpProto& proto() { return mProto; } 234df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckprivate: 235df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int mFd; 236df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck DumpType mType; 237df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck service::GraphicsStatsServiceDumpProto mProto; 238df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck}; 239df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 240df1742ed47da1e9b61afeae16fa448d5302a8aa0John ReckGraphicsStatsService::Dump* GraphicsStatsService::createDump(int outFd, DumpType type) { 241df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck return new Dump(outFd, type); 242df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} 243df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 244df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid GraphicsStatsService::addToDump(Dump* dump, const std::string& path, const std::string& package, 245df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) { 246df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck service::GraphicsStatsProto statsProto; 247df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (!path.empty() && !parseFromFile(path, &statsProto)) { 248df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck statsProto.Clear(); 249df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 250df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (data) { 251df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data); 252df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 253df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (!statsProto.IsInitialized()) { 254df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck ALOGW("Failed to load profile data from path '%s' and data %p", 255df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck path.empty() ? "<empty>" : path.c_str(), data); 256df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck return; 257df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 258df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 259df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (dump->type() == DumpType::Protobuf) { 260df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dump->proto().add_stats()->CopyFrom(statsProto); 261df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } else { 262df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dumpAsTextToFd(&statsProto, dump->fd()); 263df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 264df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} 265df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 266df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid GraphicsStatsService::addToDump(Dump* dump, const std::string& path) { 267df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck service::GraphicsStatsProto statsProto; 268df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (!parseFromFile(path, &statsProto)) { 269df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck return; 270df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 271df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (dump->type() == DumpType::Protobuf) { 272df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dump->proto().add_stats()->CopyFrom(statsProto); 273df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } else { 274df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dumpAsTextToFd(&statsProto, dump->fd()); 275df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 276df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} 277df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 278df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reckvoid GraphicsStatsService::finishDump(Dump* dump) { 279df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck if (dump->type() == DumpType::Protobuf) { 280df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck io::FileOutputStream stream(dump->fd()); 281df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck dump->proto().SerializeToZeroCopyStream(&stream); 282df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck } 283df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck delete dump; 284df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} 285df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck 286df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} /* namespace uirenderer */ 287df1742ed47da1e9b61afeae16fa448d5302a8aa0John Reck} /* namespace android */