diff options
Diffstat (limited to 'services/surfaceflinger/TimeStats/TimeStats.cpp')
-rw-r--r-- | services/surfaceflinger/TimeStats/TimeStats.cpp | 532 |
1 files changed, 160 insertions, 372 deletions
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 7c1f21f9e4..37194c6355 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -14,14 +14,18 @@ * limitations under the License. */ -#include <unordered_map> +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" #undef LOG_TAG #define LOG_TAG "TimeStats" #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include "TimeStats.h" + #include <android-base/stringprintf.h> +#include <android/util/ProtoOutputStream.h> #include <log/log.h> -#include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h> #include <utils/String8.h> #include <utils/Timers.h> #include <utils/Trace.h> @@ -29,131 +33,100 @@ #include <algorithm> #include <chrono> -#include "TimeStats.h" -#include "timestatsproto/TimeStatsHelper.h" - namespace android { namespace impl { -namespace { +AStatsManager_PullAtomCallbackReturn TimeStats::pullAtomCallback(int32_t atom_tag, + AStatsEventList* data, + void* cookie) { + impl::TimeStats* timeStats = reinterpret_cast<impl::TimeStats*>(cookie); + AStatsManager_PullAtomCallbackReturn result = AStatsManager_PULL_SKIP; + if (atom_tag == android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) { + result = timeStats->populateGlobalAtom(data); + } else if (atom_tag == android::util::SURFACEFLINGER_STATS_LAYER_INFO) { + result = timeStats->populateLayerAtom(data); + } + + // Enable timestats now. The first full pull for a given build is expected to + // have empty or very little stats, as stats are first enabled after the + // first pull is completed for either the global or layer stats. + timeStats->enable(); + return result; +} -FrameTimingHistogram histogramToProto(const std::unordered_map<int32_t, int32_t>& histogram, - size_t maxPulledHistogramBuckets) { +namespace { +// Histograms align with the order of fields in SurfaceflingerStatsLayerInfo. +const std::array<std::string, 6> kHistogramNames = { + "present2present", "post2present", "acquire2present", + "latch2present", "desired2present", "post2acquire", +}; + +std::string histogramToProtoByteString(const std::unordered_map<int32_t, int32_t>& histogram, + size_t maxPulledHistogramBuckets) { auto buckets = std::vector<std::pair<int32_t, int32_t>>(histogram.begin(), histogram.end()); std::sort(buckets.begin(), buckets.end(), [](std::pair<int32_t, int32_t>& left, std::pair<int32_t, int32_t>& right) { return left.second > right.second; }); - FrameTimingHistogram histogramProto; + util::ProtoOutputStream proto; int histogramSize = 0; for (const auto& bucket : buckets) { if (++histogramSize > maxPulledHistogramBuckets) { break; } - histogramProto.add_time_millis_buckets((int32_t)bucket.first); - histogramProto.add_frame_counts((int64_t)bucket.second); - } - return histogramProto; -} - -SurfaceflingerStatsLayerInfo_GameMode gameModeToProto(int32_t gameMode) { - switch (gameMode) { - case TimeStatsHelper::GameModeUnsupported: - return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSUPPORTED; - case TimeStatsHelper::GameModeStandard: - return SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD; - case TimeStatsHelper::GameModePerformance: - return SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE; - case TimeStatsHelper::GameModeBattery: - return SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY; - default: - return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSPECIFIED; + proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED | + 1 /* field id */, + (int32_t)bucket.first); + proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED | + 2 /* field id */, + (int64_t)bucket.second); } -} -SurfaceflingerStatsLayerInfo_SetFrameRateVote frameRateVoteToProto( - const TimeStats::SetFrameRateVote& setFrameRateVote) { - using FrameRateCompatibilityEnum = - SurfaceflingerStatsLayerInfo::SetFrameRateVote::FrameRateCompatibility; - using SeamlessnessEnum = SurfaceflingerStatsLayerInfo::SetFrameRateVote::Seamlessness; - - SurfaceflingerStatsLayerInfo_SetFrameRateVote proto; - proto.set_frame_rate(setFrameRateVote.frameRate); - proto.set_frame_rate_compatibility( - static_cast<FrameRateCompatibilityEnum>(setFrameRateVote.frameRateCompatibility)); - proto.set_seamlessness(static_cast<SeamlessnessEnum>(setFrameRateVote.seamlessness)); - return proto; + std::string byteString; + proto.serializeToString(&byteString); + return byteString; } } // namespace -bool TimeStats::populateGlobalAtom(std::string* pulledData) { +AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) { std::lock_guard<std::mutex> lock(mMutex); - if (mTimeStats.statsStartLegacy == 0) { - return false; + if (mTimeStats.statsStart == 0) { + return AStatsManager_PULL_SKIP; } flushPowerTimeLocked(); - SurfaceflingerStatsGlobalInfoWrapper atomList; - for (const auto& globalSlice : mTimeStats.stats) { - SurfaceflingerStatsGlobalInfo* atom = atomList.add_atom(); - atom->set_total_frames(mTimeStats.totalFramesLegacy); - atom->set_missed_frames(mTimeStats.missedFramesLegacy); - atom->set_client_composition_frames(mTimeStats.clientCompositionFramesLegacy); - atom->set_display_on_millis(mTimeStats.displayOnTimeLegacy); - atom->set_animation_millis(mTimeStats.presentToPresentLegacy.totalTime()); - atom->set_event_connection_count(mTimeStats.displayEventConnectionsCountLegacy); - *atom->mutable_frame_duration() = - histogramToProto(mTimeStats.frameDurationLegacy.hist, mMaxPulledHistogramBuckets); - *atom->mutable_render_engine_timing() = - histogramToProto(mTimeStats.renderEngineTimingLegacy.hist, - mMaxPulledHistogramBuckets); - atom->set_total_timeline_frames(globalSlice.second.jankPayload.totalFrames); - atom->set_total_janky_frames(globalSlice.second.jankPayload.totalJankyFrames); - atom->set_total_janky_frames_with_long_cpu(globalSlice.second.jankPayload.totalSFLongCpu); - atom->set_total_janky_frames_with_long_gpu(globalSlice.second.jankPayload.totalSFLongGpu); - atom->set_total_janky_frames_sf_unattributed( - globalSlice.second.jankPayload.totalSFUnattributed); - atom->set_total_janky_frames_app_unattributed( - globalSlice.second.jankPayload.totalAppUnattributed); - atom->set_total_janky_frames_sf_scheduling( - globalSlice.second.jankPayload.totalSFScheduling); - atom->set_total_jank_frames_sf_prediction_error( - globalSlice.second.jankPayload.totalSFPredictionError); - atom->set_total_jank_frames_app_buffer_stuffing( - globalSlice.second.jankPayload.totalAppBufferStuffing); - atom->set_display_refresh_rate_bucket(globalSlice.first.displayRefreshRateBucket); - *atom->mutable_sf_deadline_misses() = - histogramToProto(globalSlice.second.displayDeadlineDeltas.hist, - mMaxPulledHistogramBuckets); - *atom->mutable_sf_prediction_errors() = - histogramToProto(globalSlice.second.displayPresentDeltas.hist, - mMaxPulledHistogramBuckets); - atom->set_render_rate_bucket(globalSlice.first.renderRateBucket); - } - // Always clear data. + AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data); + mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime()); + mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount); + std::string frameDurationBytes = + histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets); + mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(), + frameDurationBytes.size()); + std::string renderEngineTimingBytes = + histogramToProtoByteString(mTimeStats.renderEngineTiming.hist, + mMaxPulledHistogramBuckets); + mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(), + renderEngineTimingBytes.size()); + mStatsDelegate->statsEventBuild(event); clearGlobalLocked(); - return atomList.SerializeToString(pulledData); + return AStatsManager_PULL_SUCCESS; } -bool TimeStats::populateLayerAtom(std::string* pulledData) { +AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) { std::lock_guard<std::mutex> lock(mMutex); - std::vector<TimeStatsHelper::TimeStatsLayer*> dumpStats; - uint32_t numLayers = 0; - for (const auto& globalSlice : mTimeStats.stats) { - numLayers += globalSlice.second.stats.size(); - } - - dumpStats.reserve(numLayers); - - for (auto& globalSlice : mTimeStats.stats) { - for (auto& layerSlice : globalSlice.second.stats) { - dumpStats.push_back(&layerSlice.second); - } + std::vector<TimeStatsHelper::TimeStatsLayer const*> dumpStats; + for (const auto& ele : mTimeStats.stats) { + dumpStats.push_back(&ele.second); } std::sort(dumpStats.begin(), dumpStats.end(), @@ -166,74 +139,44 @@ bool TimeStats::populateLayerAtom(std::string* pulledData) { dumpStats.resize(mMaxPulledLayers); } - SurfaceflingerStatsLayerInfoWrapper atomList; - for (auto& layer : dumpStats) { - SurfaceflingerStatsLayerInfo* atom = atomList.add_atom(); - atom->set_layer_name(layer->layerName); - atom->set_total_frames(layer->totalFrames); - atom->set_dropped_frames(layer->droppedFrames); - const auto& present2PresentHist = layer->deltas.find("present2present"); - if (present2PresentHist != layer->deltas.cend()) { - *atom->mutable_present_to_present() = - histogramToProto(present2PresentHist->second.hist, mMaxPulledHistogramBuckets); - } - const auto& post2presentHist = layer->deltas.find("post2present"); - if (post2presentHist != layer->deltas.cend()) { - *atom->mutable_post_to_present() = - histogramToProto(post2presentHist->second.hist, mMaxPulledHistogramBuckets); - } - const auto& acquire2presentHist = layer->deltas.find("acquire2present"); - if (acquire2presentHist != layer->deltas.cend()) { - *atom->mutable_acquire_to_present() = - histogramToProto(acquire2presentHist->second.hist, mMaxPulledHistogramBuckets); - } - const auto& latch2presentHist = layer->deltas.find("latch2present"); - if (latch2presentHist != layer->deltas.cend()) { - *atom->mutable_latch_to_present() = - histogramToProto(latch2presentHist->second.hist, mMaxPulledHistogramBuckets); - } - const auto& desired2presentHist = layer->deltas.find("desired2present"); - if (desired2presentHist != layer->deltas.cend()) { - *atom->mutable_desired_to_present() = - histogramToProto(desired2presentHist->second.hist, mMaxPulledHistogramBuckets); - } - const auto& post2acquireHist = layer->deltas.find("post2acquire"); - if (post2acquireHist != layer->deltas.cend()) { - *atom->mutable_post_to_acquire() = - histogramToProto(post2acquireHist->second.hist, mMaxPulledHistogramBuckets); + for (const auto& layer : dumpStats) { + AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data); + mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_LAYER_INFO); + mStatsDelegate->statsEventWriteString8(event, layer->layerName.c_str()); + mStatsDelegate->statsEventWriteInt64(event, layer->totalFrames); + mStatsDelegate->statsEventWriteInt64(event, layer->droppedFrames); + + for (const auto& name : kHistogramNames) { + const auto& histogram = layer->deltas.find(name); + if (histogram == layer->deltas.cend()) { + mStatsDelegate->statsEventWriteByteArray(event, nullptr, 0); + } else { + std::string bytes = histogramToProtoByteString(histogram->second.hist, + mMaxPulledHistogramBuckets); + mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)bytes.c_str(), + bytes.size()); + } } - atom->set_late_acquire_frames(layer->lateAcquireFrames); - atom->set_bad_desired_present_frames(layer->badDesiredPresentFrames); - atom->set_uid(layer->uid); - atom->set_total_timeline_frames(layer->jankPayload.totalFrames); - atom->set_total_janky_frames(layer->jankPayload.totalJankyFrames); - atom->set_total_janky_frames_with_long_cpu(layer->jankPayload.totalSFLongCpu); - atom->set_total_janky_frames_with_long_gpu(layer->jankPayload.totalSFLongGpu); - atom->set_total_janky_frames_sf_unattributed(layer->jankPayload.totalSFUnattributed); - atom->set_total_janky_frames_app_unattributed(layer->jankPayload.totalAppUnattributed); - atom->set_total_janky_frames_sf_scheduling(layer->jankPayload.totalSFScheduling); - atom->set_total_jank_frames_sf_prediction_error(layer->jankPayload.totalSFPredictionError); - atom->set_total_jank_frames_app_buffer_stuffing(layer->jankPayload.totalAppBufferStuffing); - atom->set_display_refresh_rate_bucket(layer->displayRefreshRateBucket); - atom->set_render_rate_bucket(layer->renderRateBucket); - *atom->mutable_set_frame_rate_vote() = frameRateVoteToProto(layer->setFrameRateVote); - *atom->mutable_app_deadline_misses() = - histogramToProto(layer->deltas["appDeadlineDeltas"].hist, - mMaxPulledHistogramBuckets); - atom->set_game_mode(gameModeToProto(layer->gameMode)); - } + mStatsDelegate->statsEventWriteInt64(event, layer->lateAcquireFrames); + mStatsDelegate->statsEventWriteInt64(event, layer->badDesiredPresentFrames); - // Always clear data. + mStatsDelegate->statsEventBuild(event); + } clearLayersLocked(); - return atomList.SerializeToString(pulledData); + return AStatsManager_PULL_SUCCESS; } -TimeStats::TimeStats() : TimeStats(std::nullopt, std::nullopt) {} +TimeStats::TimeStats() : TimeStats(nullptr, std::nullopt, std::nullopt) {} -TimeStats::TimeStats(std::optional<size_t> maxPulledLayers, +TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate, + std::optional<size_t> maxPulledLayers, std::optional<size_t> maxPulledHistogramBuckets) { + if (statsDelegate != nullptr) { + mStatsDelegate = std::move(statsDelegate); + } + if (maxPulledLayers) { mMaxPulledLayers = *maxPulledLayers; } @@ -243,19 +186,18 @@ TimeStats::TimeStats(std::optional<size_t> maxPulledLayers, } } -bool TimeStats::onPullAtom(const int atomId, std::string* pulledData) { - bool success = false; - if (atomId == 10062) { // SURFACEFLINGER_STATS_GLOBAL_INFO - success = populateGlobalAtom(pulledData); - } else if (atomId == 10063) { // SURFACEFLINGER_STATS_LAYER_INFO - success = populateLayerAtom(pulledData); - } +TimeStats::~TimeStats() { + std::lock_guard<std::mutex> lock(mMutex); + mStatsDelegate->clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); + mStatsDelegate->clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO); +} - // Enable timestats now. The first full pull for a given build is expected to - // have empty or very little stats, as stats are first enabled after the - // first pull is completed for either the global or layer stats. - enable(); - return success; +void TimeStats::onBootFinished() { + std::lock_guard<std::mutex> lock(mMutex); + mStatsDelegate->setStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, + nullptr, TimeStats::pullAtomCallback, this); + mStatsDelegate->setStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, + nullptr, TimeStats::pullAtomCallback, this); } void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) { @@ -309,7 +251,7 @@ void TimeStats::incrementTotalFrames() { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.totalFramesLegacy++; + mTimeStats.totalFrames++; } void TimeStats::incrementMissedFrames() { @@ -318,7 +260,7 @@ void TimeStats::incrementMissedFrames() { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.missedFramesLegacy++; + mTimeStats.missedFrames++; } void TimeStats::incrementClientCompositionFrames() { @@ -327,7 +269,7 @@ void TimeStats::incrementClientCompositionFrames() { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.clientCompositionFramesLegacy++; + mTimeStats.clientCompositionFrames++; } void TimeStats::incrementClientCompositionReusedFrames() { @@ -336,7 +278,7 @@ void TimeStats::incrementClientCompositionReusedFrames() { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.clientCompositionReusedFramesLegacy++; + mTimeStats.clientCompositionReusedFrames++; } void TimeStats::incrementRefreshRateSwitches() { @@ -345,7 +287,7 @@ void TimeStats::incrementRefreshRateSwitches() { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.refreshRateSwitchesLegacy++; + mTimeStats.refreshRateSwitches++; } void TimeStats::incrementCompositionStrategyChanges() { @@ -354,7 +296,7 @@ void TimeStats::incrementCompositionStrategyChanges() { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.compositionStrategyChangesLegacy++; + mTimeStats.compositionStrategyChanges++; } void TimeStats::recordDisplayEventConnectionCount(int32_t count) { @@ -363,20 +305,16 @@ void TimeStats::recordDisplayEventConnectionCount(int32_t count) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.displayEventConnectionsCountLegacy = - std::max(mTimeStats.displayEventConnectionsCountLegacy, count); -} - -static int32_t toMs(nsecs_t nanos) { - int64_t millis = - std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::nanoseconds(nanos)) - .count(); - millis = std::clamp(millis, int64_t(INT32_MIN), int64_t(INT32_MAX)); - return static_cast<int32_t>(millis); + mTimeStats.displayEventConnectionsCount = + std::max(mTimeStats.displayEventConnectionsCount, count); } static int32_t msBetween(nsecs_t start, nsecs_t end) { - return toMs(end - start); + int64_t delta = std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::nanoseconds(end - start)) + .count(); + delta = std::clamp(delta, int64_t(INT32_MIN), int64_t(INT32_MAX)); + return static_cast<int32_t>(delta); } void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) { @@ -384,7 +322,7 @@ void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) { std::lock_guard<std::mutex> lock(mMutex); if (mPowerTime.powerMode == PowerMode::ON) { - mTimeStats.frameDurationLegacy.insert(msBetween(startTime, endTime)); + mTimeStats.frameDuration.insert(msBetween(startTime, endTime)); } } @@ -447,52 +385,23 @@ bool TimeStats::recordReadyLocked(int32_t layerId, TimeRecord* timeRecord) { return true; } -static int32_t clampToNearestBucket(Fps fps, size_t bucketWidth) { - return std::round(fps.getValue() / bucketWidth) * bucketWidth; -} - -void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, - std::optional<Fps> renderRate, - SetFrameRateVote frameRateVote, - int32_t gameMode) { +void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) { ATRACE_CALL(); - ALOGV("[%d]-flushAvailableRecordsToStatsLocked", layerId); LayerRecord& layerRecord = mTimeStatsTracker[layerId]; TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord; std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords; - const int32_t refreshRateBucket = - clampToNearestBucket(displayRefreshRate, REFRESH_RATE_BUCKET_WIDTH); - const int32_t renderRateBucket = - clampToNearestBucket(renderRate ? *renderRate : displayRefreshRate, - RENDER_RATE_BUCKET_WIDTH); while (!timeRecords.empty()) { if (!recordReadyLocked(layerId, &timeRecords[0])) break; ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerId, timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime); if (prevTimeRecord.ready) { - uid_t uid = layerRecord.uid; const std::string& layerName = layerRecord.layerName; - TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket}; - if (!mTimeStats.stats.count(timelineKey)) { - mTimeStats.stats[timelineKey].key = timelineKey; + if (!mTimeStats.stats.count(layerName)) { + mTimeStats.stats[layerName].layerName = layerName; } - - TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey]; - - TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName, gameMode}; - if (!displayStats.stats.count(layerKey)) { - displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket; - displayStats.stats[layerKey].renderRateBucket = renderRateBucket; - displayStats.stats[layerKey].uid = uid; - displayStats.stats[layerKey].layerName = layerName; - displayStats.stats[layerKey].gameMode = gameMode; - } - if (frameRateVote.frameRate > 0.0f) { - displayStats.stats[layerKey].setFrameRateVote = frameRateVote; - } - TimeStatsHelper::TimeStatsLayer& timeStatsLayer = displayStats.stats[layerKey]; + TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[layerName]; timeStatsLayer.totalFrames++; timeStatsLayer.droppedFrames += layerRecord.droppedFrames; timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames; @@ -553,22 +462,8 @@ static bool layerNameIsValid(const std::string& layerName) { layerName.compare(0, kMinLenLayerName, kPopupWindowPrefix) != 0; } -bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName, - int32_t gameMode) { - uint32_t layerRecords = 0; - for (const auto& record : mTimeStats.stats) { - if (record.second.stats.count({uid, layerName, gameMode}) > 0) { - return true; - } - - layerRecords += record.second.stats.size(); - } - - return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS; -} - void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, - uid_t uid, nsecs_t postTime, int32_t gameMode) { + nsecs_t postTime) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -576,14 +471,12 @@ void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::st postTime); std::lock_guard<std::mutex> lock(mMutex); - if (!canAddNewAggregatedStats(uid, layerName, gameMode)) { + if (!mTimeStats.stats.count(layerName) && mTimeStats.stats.size() >= MAX_NUM_LAYER_STATS) { return; } if (!mTimeStatsTracker.count(layerId) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS && layerNameIsValid(layerName)) { - mTimeStatsTracker[layerId].uid = uid; mTimeStatsTracker[layerId].layerName = layerName; - mTimeStatsTracker[layerId].gameMode = gameMode; } if (!mTimeStatsTracker.count(layerId)) return; LayerRecord& layerRecord = mTimeStatsTracker[layerId]; @@ -716,9 +609,7 @@ void TimeStats::setAcquireFence(int32_t layerId, uint64_t frameNumber, } } -void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, - Fps displayRefreshRate, std::optional<Fps> renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode) { +void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -737,14 +628,11 @@ void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t pr layerRecord.waitData++; } - flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote, - gameMode); + flushAvailableRecordsToStatsLocked(layerId); } void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, - const std::shared_ptr<FenceTime>& presentFence, - Fps displayRefreshRate, std::optional<Fps> renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode) { + const std::shared_ptr<FenceTime>& presentFence) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -764,103 +652,7 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, layerRecord.waitData++; } - flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote, - gameMode); -} - -static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL | - JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed | - JankType::AppDeadlineMissed | JankType::PredictionError | - JankType::SurfaceFlingerScheduling; - -template <class T> -static void updateJankPayload(T& t, int32_t reasons) { - t.jankPayload.totalFrames++; - - if (reasons & kValidJankyReason) { - t.jankPayload.totalJankyFrames++; - if ((reasons & JankType::SurfaceFlingerCpuDeadlineMissed) != 0) { - t.jankPayload.totalSFLongCpu++; - } - if ((reasons & JankType::SurfaceFlingerGpuDeadlineMissed) != 0) { - t.jankPayload.totalSFLongGpu++; - } - if ((reasons & JankType::DisplayHAL) != 0) { - t.jankPayload.totalSFUnattributed++; - } - if ((reasons & JankType::AppDeadlineMissed) != 0) { - t.jankPayload.totalAppUnattributed++; - } - if ((reasons & JankType::PredictionError) != 0) { - t.jankPayload.totalSFPredictionError++; - } - if ((reasons & JankType::SurfaceFlingerScheduling) != 0) { - t.jankPayload.totalSFScheduling++; - } - } - - // We want to track BufferStuffing separately as it can provide info on latency issues - if (reasons & JankType::BufferStuffing) { - t.jankPayload.totalAppBufferStuffing++; - } -} - -void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) { - if (!mEnabled.load()) return; - - ATRACE_CALL(); - std::lock_guard<std::mutex> lock(mMutex); - - // Only update layer stats if we're already tracking the layer in TimeStats. - // Otherwise, continue tracking the statistic but use a default layer name instead. - // As an implementation detail, we do this because this method is expected to be - // called from FrameTimeline, whose jank classification includes transaction jank - // that occurs without a buffer. But, in general those layer names are not suitable as - // aggregation keys: e.g., it's normal and expected for Window Manager to include the hash code - // for an animation leash. So while we can show that jank in dumpsys, aggregating based on the - // layer blows up the stats size, so as a workaround drop those stats. This assumes that - // TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that - // the first jank record is not dropped. - - static const std::string kDefaultLayerName = "none"; - static constexpr int32_t kDefaultGameMode = TimeStatsHelper::GameModeUnsupported; - - const int32_t refreshRateBucket = - clampToNearestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH); - const int32_t renderRateBucket = - clampToNearestBucket(info.renderRate ? *info.renderRate : info.refreshRate, - RENDER_RATE_BUCKET_WIDTH); - const TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket}; - - if (!mTimeStats.stats.count(timelineKey)) { - mTimeStats.stats[timelineKey].key = timelineKey; - } - - TimeStatsHelper::TimelineStats& timelineStats = mTimeStats.stats[timelineKey]; - - updateJankPayload<TimeStatsHelper::TimelineStats>(timelineStats, info.reasons); - - TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName, info.gameMode}; - if (!timelineStats.stats.count(layerKey)) { - layerKey = {info.uid, kDefaultLayerName, kDefaultGameMode}; - timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket; - timelineStats.stats[layerKey].renderRateBucket = renderRateBucket; - timelineStats.stats[layerKey].uid = info.uid; - timelineStats.stats[layerKey].layerName = kDefaultLayerName; - timelineStats.stats[layerKey].gameMode = kDefaultGameMode; - } - - TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey]; - updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, info.reasons); - - if (info.reasons & kValidJankyReason) { - // TimeStats Histograms only retain positive values, so we don't need to check if these - // deadlines were really missed if we know that the frame had jank, since deadlines - // that were met will be dropped. - timelineStats.displayDeadlineDeltas.insert(toMs(info.displayDeadlineDelta)); - timelineStats.displayPresentDeltas.insert(toMs(info.displayPresentJitter)); - timeStatsLayer.deltas["appDeadlineDeltas"].insert(toMs(info.appDeadlineDelta)); - } + flushAvailableRecordsToStatsLocked(layerId); } void TimeStats::onDestroy(int32_t layerId) { @@ -901,7 +693,7 @@ void TimeStats::flushPowerTimeLocked() { switch (mPowerTime.powerMode) { case PowerMode::ON: - mTimeStats.displayOnTimeLegacy += elapsedTime; + mTimeStats.displayOnTime += elapsedTime; break; case PowerMode::OFF: case PowerMode::DOZE: @@ -930,10 +722,10 @@ void TimeStats::setPowerMode(PowerMode powerMode) { void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) { std::lock_guard<std::mutex> lock(mMutex); - if (mTimeStats.refreshRateStatsLegacy.count(fps)) { - mTimeStats.refreshRateStatsLegacy[fps] += duration; + if (mTimeStats.refreshRateStats.count(fps)) { + mTimeStats.refreshRateStats[fps] += duration; } else { - mTimeStats.refreshRateStatsLegacy.insert({fps, duration}); + mTimeStats.refreshRateStats.insert({fps, duration}); } } @@ -959,7 +751,7 @@ void TimeStats::flushAvailableGlobalRecordsToStatsLocked() { msBetween(mGlobalRecord.prevPresentTime, curPresentTime); ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]", presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime); - mTimeStats.presentToPresentLegacy.insert(presentToPresentMs); + mTimeStats.presentToPresent.insert(presentToPresentMs); } mGlobalRecord.prevPresentTime = curPresentTime; @@ -986,7 +778,7 @@ void TimeStats::flushAvailableGlobalRecordsToStatsLocked() { } const int32_t renderEngineMs = msBetween(duration.startTime, endNs); - mTimeStats.renderEngineTimingLegacy.insert(renderEngineMs); + mTimeStats.renderEngineTiming.insert(renderEngineMs); mGlobalRecord.renderEngineDurations.pop_front(); } @@ -1029,7 +821,7 @@ void TimeStats::enable() { std::lock_guard<std::mutex> lock(mMutex); mEnabled.store(true); - mTimeStats.statsStartLegacy = static_cast<int64_t>(std::time(0)); + mTimeStats.statsStart = static_cast<int64_t>(std::time(0)); mPowerTime.prevTime = systemTime(); ALOGD("Enabled"); } @@ -1042,13 +834,12 @@ void TimeStats::disable() { std::lock_guard<std::mutex> lock(mMutex); flushPowerTimeLocked(); mEnabled.store(false); - mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0)); + mTimeStats.statsEnd = static_cast<int64_t>(std::time(0)); ALOGD("Disabled"); } void TimeStats::clearAll() { std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.stats.clear(); clearGlobalLocked(); clearLayersLocked(); } @@ -1056,24 +847,21 @@ void TimeStats::clearAll() { void TimeStats::clearGlobalLocked() { ATRACE_CALL(); - mTimeStats.statsStartLegacy = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0); - mTimeStats.statsEndLegacy = 0; - mTimeStats.totalFramesLegacy = 0; - mTimeStats.missedFramesLegacy = 0; - mTimeStats.clientCompositionFramesLegacy = 0; - mTimeStats.clientCompositionReusedFramesLegacy = 0; - mTimeStats.refreshRateSwitchesLegacy = 0; - mTimeStats.compositionStrategyChangesLegacy = 0; - mTimeStats.displayEventConnectionsCountLegacy = 0; - mTimeStats.displayOnTimeLegacy = 0; - mTimeStats.presentToPresentLegacy.hist.clear(); - mTimeStats.frameDurationLegacy.hist.clear(); - mTimeStats.renderEngineTimingLegacy.hist.clear(); - mTimeStats.refreshRateStatsLegacy.clear(); + mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0); + mTimeStats.statsEnd = 0; + mTimeStats.totalFrames = 0; + mTimeStats.missedFrames = 0; + mTimeStats.clientCompositionFrames = 0; + mTimeStats.clientCompositionReusedFrames = 0; + mTimeStats.refreshRateSwitches = 0; + mTimeStats.compositionStrategyChanges = 0; + mTimeStats.displayEventConnectionsCount = 0; + mTimeStats.displayOnTime = 0; + mTimeStats.presentToPresent.hist.clear(); + mTimeStats.frameDuration.hist.clear(); + mTimeStats.renderEngineTiming.hist.clear(); + mTimeStats.refreshRateStats.clear(); mPowerTime.prevTime = systemTime(); - for (auto& globalRecord : mTimeStats.stats) { - globalRecord.second.clearGlobals(); - } mGlobalRecord.prevPresentTime = 0; mGlobalRecord.presentFences.clear(); ALOGD("Cleared global stats"); @@ -1083,10 +871,7 @@ void TimeStats::clearLayersLocked() { ATRACE_CALL(); mTimeStatsTracker.clear(); - - for (auto& globalRecord : mTimeStats.stats) { - globalRecord.second.stats.clear(); - } + mTimeStats.stats.clear(); ALOGD("Cleared layer stats"); } @@ -1098,11 +883,11 @@ void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, std::strin ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - if (mTimeStats.statsStartLegacy == 0) { + if (mTimeStats.statsStart == 0) { return; } - mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0)); + mTimeStats.statsEnd = static_cast<int64_t>(std::time(0)); flushPowerTimeLocked(); @@ -1120,3 +905,6 @@ void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, std::strin } // namespace impl } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" |