blob: c60ded6e56883c072a680fa4fa4de30b018aeafc [file] [log] [blame]
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001/*
2 * Copyright 2018 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 */
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -080016
Yiwei Zhang0102ad22018-05-02 17:37:17 -070017#undef LOG_TAG
18#define LOG_TAG "TimeStats"
19#define ATRACE_TAG ATRACE_TAG_GRAPHICS
20
Yiwei Zhang0102ad22018-05-02 17:37:17 -070021#include <android-base/stringprintf.h>
Vishnu Nairbe0ad902024-06-27 23:38:43 +000022#include <common/trace.h>
Yiwei Zhang0102ad22018-05-02 17:37:17 -070023#include <log/log.h>
Tej Singhe2751772021-04-06 22:05:29 -070024#include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h>
Yiwei Zhang0102ad22018-05-02 17:37:17 -070025#include <utils/String8.h>
Yiwei Zhang3a226d22018-10-16 09:23:03 -070026#include <utils/Timers.h>
Yiwei Zhang0102ad22018-05-02 17:37:17 -070027
28#include <algorithm>
Alec Mouri9519bf12019-11-15 16:54:44 -080029#include <chrono>
Alberto Gonzalez9fe14512022-09-29 21:27:34 +000030#include <cmath>
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070031#include <unordered_map>
Yiwei Zhang0102ad22018-05-02 17:37:17 -070032
Tej Singhe2751772021-04-06 22:05:29 -070033#include "TimeStats.h"
Alec Mouri9a29e672020-09-14 12:39:14 -070034#include "timestatsproto/TimeStatsHelper.h"
35
Yiwei Zhang0102ad22018-05-02 17:37:17 -070036namespace android {
37
Alec Mourifb571ea2019-01-24 18:42:10 -080038namespace impl {
39
Alec Mouri37384342020-01-02 17:23:37 -080040namespace {
Alec Mouri8e2f31b2020-01-16 22:04:35 +000041
Tej Singhe2751772021-04-06 22:05:29 -070042FrameTimingHistogram histogramToProto(const std::unordered_map<int32_t, int32_t>& histogram,
43 size_t maxPulledHistogramBuckets) {
Alec Mouri37384342020-01-02 17:23:37 -080044 auto buckets = std::vector<std::pair<int32_t, int32_t>>(histogram.begin(), histogram.end());
45 std::sort(buckets.begin(), buckets.end(),
46 [](std::pair<int32_t, int32_t>& left, std::pair<int32_t, int32_t>& right) {
47 return left.second > right.second;
48 });
49
Tej Singhe2751772021-04-06 22:05:29 -070050 FrameTimingHistogram histogramProto;
Alec Mouri37384342020-01-02 17:23:37 -080051 int histogramSize = 0;
52 for (const auto& bucket : buckets) {
53 if (++histogramSize > maxPulledHistogramBuckets) {
54 break;
55 }
Tej Singhe2751772021-04-06 22:05:29 -070056 histogramProto.add_time_millis_buckets((int32_t)bucket.first);
57 histogramProto.add_frame_counts((int64_t)bucket.second);
Alec Mouri37384342020-01-02 17:23:37 -080058 }
Tej Singhe2751772021-04-06 22:05:29 -070059 return histogramProto;
Alec Mouri37384342020-01-02 17:23:37 -080060}
Alec Mouri75de8f22021-01-20 14:53:44 -080061
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070062SurfaceflingerStatsLayerInfo_GameMode gameModeToProto(GameMode gameMode) {
Adithya Srinivasan58069dc2021-06-04 20:37:02 +000063 switch (gameMode) {
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070064 case GameMode::Unsupported:
Adithya Srinivasan58069dc2021-06-04 20:37:02 +000065 return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSUPPORTED;
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070066 case GameMode::Standard:
Adithya Srinivasan58069dc2021-06-04 20:37:02 +000067 return SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD;
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070068 case GameMode::Performance:
Adithya Srinivasan58069dc2021-06-04 20:37:02 +000069 return SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE;
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070070 case GameMode::Battery:
Adithya Srinivasan58069dc2021-06-04 20:37:02 +000071 return SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY;
Xiang Wangf0c5cca2022-11-09 18:03:09 -080072 case GameMode::Custom:
73 return SurfaceflingerStatsLayerInfo::GAME_MODE_CUSTOM;
Adithya Srinivasan58069dc2021-06-04 20:37:02 +000074 default:
75 return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSPECIFIED;
76 }
77}
78
Tej Singhe2751772021-04-06 22:05:29 -070079SurfaceflingerStatsLayerInfo_SetFrameRateVote frameRateVoteToProto(
80 const TimeStats::SetFrameRateVote& setFrameRateVote) {
81 using FrameRateCompatibilityEnum =
82 SurfaceflingerStatsLayerInfo::SetFrameRateVote::FrameRateCompatibility;
83 using SeamlessnessEnum = SurfaceflingerStatsLayerInfo::SetFrameRateVote::Seamlessness;
Alec Mouri75de8f22021-01-20 14:53:44 -080084
Tej Singhe2751772021-04-06 22:05:29 -070085 SurfaceflingerStatsLayerInfo_SetFrameRateVote proto;
86 proto.set_frame_rate(setFrameRateVote.frameRate);
87 proto.set_frame_rate_compatibility(
88 static_cast<FrameRateCompatibilityEnum>(setFrameRateVote.frameRateCompatibility));
89 proto.set_seamlessness(static_cast<SeamlessnessEnum>(setFrameRateVote.seamlessness));
90 return proto;
Alec Mouri75de8f22021-01-20 14:53:44 -080091}
Alec Mouri37384342020-01-02 17:23:37 -080092} // namespace
93
Huihong Luo30aa4372022-10-03 14:54:12 -070094bool TimeStats::populateGlobalAtom(std::vector<uint8_t>* pulledData) {
Alec Mouridfad9002020-02-12 17:49:09 -080095 std::lock_guard<std::mutex> lock(mMutex);
96
Alec Mouri7d436ec2021-01-27 20:40:50 -080097 if (mTimeStats.statsStartLegacy == 0) {
Tej Singhe2751772021-04-06 22:05:29 -070098 return false;
Alec Mouridfad9002020-02-12 17:49:09 -080099 }
100 flushPowerTimeLocked();
Tej Singhe2751772021-04-06 22:05:29 -0700101 SurfaceflingerStatsGlobalInfoWrapper atomList;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800102 for (const auto& globalSlice : mTimeStats.stats) {
Tej Singhe2751772021-04-06 22:05:29 -0700103 SurfaceflingerStatsGlobalInfo* atom = atomList.add_atom();
104 atom->set_total_frames(mTimeStats.totalFramesLegacy);
105 atom->set_missed_frames(mTimeStats.missedFramesLegacy);
106 atom->set_client_composition_frames(mTimeStats.clientCompositionFramesLegacy);
107 atom->set_display_on_millis(mTimeStats.displayOnTimeLegacy);
108 atom->set_animation_millis(mTimeStats.presentToPresentLegacy.totalTime());
Alec Mouri6cc025b2023-07-13 00:48:19 +0000109 // Deprecated
110 atom->set_event_connection_count(0);
Tej Singhe2751772021-04-06 22:05:29 -0700111 *atom->mutable_frame_duration() =
112 histogramToProto(mTimeStats.frameDurationLegacy.hist, mMaxPulledHistogramBuckets);
113 *atom->mutable_render_engine_timing() =
114 histogramToProto(mTimeStats.renderEngineTimingLegacy.hist,
115 mMaxPulledHistogramBuckets);
116 atom->set_total_timeline_frames(globalSlice.second.jankPayload.totalFrames);
117 atom->set_total_janky_frames(globalSlice.second.jankPayload.totalJankyFrames);
118 atom->set_total_janky_frames_with_long_cpu(globalSlice.second.jankPayload.totalSFLongCpu);
119 atom->set_total_janky_frames_with_long_gpu(globalSlice.second.jankPayload.totalSFLongGpu);
120 atom->set_total_janky_frames_sf_unattributed(
121 globalSlice.second.jankPayload.totalSFUnattributed);
122 atom->set_total_janky_frames_app_unattributed(
123 globalSlice.second.jankPayload.totalAppUnattributed);
124 atom->set_total_janky_frames_sf_scheduling(
125 globalSlice.second.jankPayload.totalSFScheduling);
126 atom->set_total_jank_frames_sf_prediction_error(
127 globalSlice.second.jankPayload.totalSFPredictionError);
128 atom->set_total_jank_frames_app_buffer_stuffing(
129 globalSlice.second.jankPayload.totalAppBufferStuffing);
130 atom->set_display_refresh_rate_bucket(globalSlice.first.displayRefreshRateBucket);
131 *atom->mutable_sf_deadline_misses() =
132 histogramToProto(globalSlice.second.displayDeadlineDeltas.hist,
133 mMaxPulledHistogramBuckets);
134 *atom->mutable_sf_prediction_errors() =
135 histogramToProto(globalSlice.second.displayPresentDeltas.hist,
136 mMaxPulledHistogramBuckets);
137 atom->set_render_rate_bucket(globalSlice.first.renderRateBucket);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800138 }
139
Tej Singhe2751772021-04-06 22:05:29 -0700140 // Always clear data.
Alec Mouridfad9002020-02-12 17:49:09 -0800141 clearGlobalLocked();
142
Huihong Luo30aa4372022-10-03 14:54:12 -0700143 pulledData->resize(atomList.ByteSizeLong());
144 return atomList.SerializeToArray(pulledData->data(), atomList.ByteSizeLong());
Alec Mouridfad9002020-02-12 17:49:09 -0800145}
146
Huihong Luo30aa4372022-10-03 14:54:12 -0700147bool TimeStats::populateLayerAtom(std::vector<uint8_t>* pulledData) {
Alec Mouri37384342020-01-02 17:23:37 -0800148 std::lock_guard<std::mutex> lock(mMutex);
149
Alec Mouri363faf02021-01-29 16:34:55 -0800150 std::vector<TimeStatsHelper::TimeStatsLayer*> dumpStats;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800151 uint32_t numLayers = 0;
152 for (const auto& globalSlice : mTimeStats.stats) {
153 numLayers += globalSlice.second.stats.size();
154 }
155
156 dumpStats.reserve(numLayers);
157
Alec Mouri363faf02021-01-29 16:34:55 -0800158 for (auto& globalSlice : mTimeStats.stats) {
159 for (auto& layerSlice : globalSlice.second.stats) {
Alec Mouri7d436ec2021-01-27 20:40:50 -0800160 dumpStats.push_back(&layerSlice.second);
161 }
Alec Mouri37384342020-01-02 17:23:37 -0800162 }
163
164 std::sort(dumpStats.begin(), dumpStats.end(),
165 [](TimeStatsHelper::TimeStatsLayer const* l,
166 TimeStatsHelper::TimeStatsLayer const* r) {
167 return l->totalFrames > r->totalFrames;
168 });
169
170 if (mMaxPulledLayers < dumpStats.size()) {
171 dumpStats.resize(mMaxPulledLayers);
172 }
173
Tej Singhe2751772021-04-06 22:05:29 -0700174 SurfaceflingerStatsLayerInfoWrapper atomList;
Alec Mouri363faf02021-01-29 16:34:55 -0800175 for (auto& layer : dumpStats) {
Tej Singhe2751772021-04-06 22:05:29 -0700176 SurfaceflingerStatsLayerInfo* atom = atomList.add_atom();
177 atom->set_layer_name(layer->layerName);
178 atom->set_total_frames(layer->totalFrames);
179 atom->set_dropped_frames(layer->droppedFrames);
180 const auto& present2PresentHist = layer->deltas.find("present2present");
181 if (present2PresentHist != layer->deltas.cend()) {
182 *atom->mutable_present_to_present() =
183 histogramToProto(present2PresentHist->second.hist, mMaxPulledHistogramBuckets);
184 }
Alberto Gonzalez9fe14512022-09-29 21:27:34 +0000185 const auto& present2PresentDeltaHist = layer->deltas.find("present2presentDelta");
186 if (present2PresentDeltaHist != layer->deltas.cend()) {
187 *atom->mutable_present_to_present_delta() =
188 histogramToProto(present2PresentDeltaHist->second.hist,
189 mMaxPulledHistogramBuckets);
190 }
Tej Singhe2751772021-04-06 22:05:29 -0700191 const auto& post2presentHist = layer->deltas.find("post2present");
192 if (post2presentHist != layer->deltas.cend()) {
193 *atom->mutable_post_to_present() =
194 histogramToProto(post2presentHist->second.hist, mMaxPulledHistogramBuckets);
195 }
196 const auto& acquire2presentHist = layer->deltas.find("acquire2present");
197 if (acquire2presentHist != layer->deltas.cend()) {
198 *atom->mutable_acquire_to_present() =
199 histogramToProto(acquire2presentHist->second.hist, mMaxPulledHistogramBuckets);
200 }
201 const auto& latch2presentHist = layer->deltas.find("latch2present");
202 if (latch2presentHist != layer->deltas.cend()) {
203 *atom->mutable_latch_to_present() =
204 histogramToProto(latch2presentHist->second.hist, mMaxPulledHistogramBuckets);
205 }
206 const auto& desired2presentHist = layer->deltas.find("desired2present");
207 if (desired2presentHist != layer->deltas.cend()) {
208 *atom->mutable_desired_to_present() =
209 histogramToProto(desired2presentHist->second.hist, mMaxPulledHistogramBuckets);
210 }
211 const auto& post2acquireHist = layer->deltas.find("post2acquire");
212 if (post2acquireHist != layer->deltas.cend()) {
213 *atom->mutable_post_to_acquire() =
214 histogramToProto(post2acquireHist->second.hist, mMaxPulledHistogramBuckets);
Alec Mouri37384342020-01-02 17:23:37 -0800215 }
216
Tej Singhe2751772021-04-06 22:05:29 -0700217 atom->set_late_acquire_frames(layer->lateAcquireFrames);
218 atom->set_bad_desired_present_frames(layer->badDesiredPresentFrames);
219 atom->set_uid(layer->uid);
220 atom->set_total_timeline_frames(layer->jankPayload.totalFrames);
221 atom->set_total_janky_frames(layer->jankPayload.totalJankyFrames);
222 atom->set_total_janky_frames_with_long_cpu(layer->jankPayload.totalSFLongCpu);
223 atom->set_total_janky_frames_with_long_gpu(layer->jankPayload.totalSFLongGpu);
224 atom->set_total_janky_frames_sf_unattributed(layer->jankPayload.totalSFUnattributed);
225 atom->set_total_janky_frames_app_unattributed(layer->jankPayload.totalAppUnattributed);
226 atom->set_total_janky_frames_sf_scheduling(layer->jankPayload.totalSFScheduling);
227 atom->set_total_jank_frames_sf_prediction_error(layer->jankPayload.totalSFPredictionError);
228 atom->set_total_jank_frames_app_buffer_stuffing(layer->jankPayload.totalAppBufferStuffing);
229 atom->set_display_refresh_rate_bucket(layer->displayRefreshRateBucket);
230 atom->set_render_rate_bucket(layer->renderRateBucket);
231 *atom->mutable_set_frame_rate_vote() = frameRateVoteToProto(layer->setFrameRateVote);
232 *atom->mutable_app_deadline_misses() =
233 histogramToProto(layer->deltas["appDeadlineDeltas"].hist,
234 mMaxPulledHistogramBuckets);
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000235 atom->set_game_mode(gameModeToProto(layer->gameMode));
Alec Mouri37384342020-01-02 17:23:37 -0800236 }
Tej Singhe2751772021-04-06 22:05:29 -0700237
238 // Always clear data.
Alec Mouri37384342020-01-02 17:23:37 -0800239 clearLayersLocked();
240
Huihong Luo30aa4372022-10-03 14:54:12 -0700241 pulledData->resize(atomList.ByteSizeLong());
242 return atomList.SerializeToArray(pulledData->data(), atomList.ByteSizeLong());
Alec Mouri37384342020-01-02 17:23:37 -0800243}
244
Tej Singhe2751772021-04-06 22:05:29 -0700245TimeStats::TimeStats() : TimeStats(std::nullopt, std::nullopt) {}
Alec Mouri37384342020-01-02 17:23:37 -0800246
Tej Singhe2751772021-04-06 22:05:29 -0700247TimeStats::TimeStats(std::optional<size_t> maxPulledLayers,
Alec Mouri37384342020-01-02 17:23:37 -0800248 std::optional<size_t> maxPulledHistogramBuckets) {
Alec Mouri37384342020-01-02 17:23:37 -0800249 if (maxPulledLayers) {
250 mMaxPulledLayers = *maxPulledLayers;
251 }
252
253 if (maxPulledHistogramBuckets) {
254 mMaxPulledHistogramBuckets = *maxPulledHistogramBuckets;
255 }
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000256}
257
Huihong Luo30aa4372022-10-03 14:54:12 -0700258bool TimeStats::onPullAtom(const int atomId, std::vector<uint8_t>* pulledData) {
Tej Singhe2751772021-04-06 22:05:29 -0700259 bool success = false;
260 if (atomId == 10062) { // SURFACEFLINGER_STATS_GLOBAL_INFO
261 success = populateGlobalAtom(pulledData);
262 } else if (atomId == 10063) { // SURFACEFLINGER_STATS_LAYER_INFO
263 success = populateLayerAtom(pulledData);
264 }
Alec Mouri3ecd5cd2020-01-29 12:53:07 -0800265
Tej Singhe2751772021-04-06 22:05:29 -0700266 // Enable timestats now. The first full pull for a given build is expected to
267 // have empty or very little stats, as stats are first enabled after the
268 // first pull is completed for either the global or layer stats.
269 enable();
270 return success;
Alec Mourib3885ad2019-09-06 17:08:55 -0700271}
272
Dominik Laskowskic2867142019-01-21 11:33:38 -0800273void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000274 SFTRACE_CALL();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700275
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700276 std::unordered_map<std::string, int32_t> argsMap;
Dominik Laskowskic2867142019-01-21 11:33:38 -0800277 for (size_t index = 0; index < args.size(); ++index) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700278 argsMap[std::string(String8(args[index]).c_str())] = index;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700279 }
280
281 if (argsMap.count("-disable")) {
282 disable();
283 }
284
285 if (argsMap.count("-dump")) {
Yiwei Zhang8a4015c2018-05-08 16:03:47 -0700286 std::optional<uint32_t> maxLayers = std::nullopt;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700287 auto iter = argsMap.find("-maxlayers");
288 if (iter != argsMap.end() && iter->second + 1 < static_cast<int32_t>(args.size())) {
Yiwei Zhang8a4015c2018-05-08 16:03:47 -0700289 int64_t value = strtol(String8(args[iter->second + 1]).c_str(), nullptr, 10);
290 value = std::clamp(value, int64_t(0), int64_t(UINT32_MAX));
291 maxLayers = static_cast<uint32_t>(value);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700292 }
293
Yiwei Zhang8a4015c2018-05-08 16:03:47 -0700294 dump(asProto, maxLayers, result);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700295 }
296
297 if (argsMap.count("-clear")) {
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000298 clearAll();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700299 }
300
301 if (argsMap.count("-enable")) {
302 enable();
303 }
304}
305
Yiwei Zhang7eb58b72019-04-22 19:00:02 -0700306std::string TimeStats::miniDump() {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000307 SFTRACE_CALL();
Yiwei Zhang7eb58b72019-04-22 19:00:02 -0700308
309 std::string result = "TimeStats miniDump:\n";
310 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhange926ab52019-08-14 15:16:00 -0700311 android::base::StringAppendF(&result, "Number of layers currently being tracked is %zu\n",
Yiwei Zhang7eb58b72019-04-22 19:00:02 -0700312 mTimeStatsTracker.size());
Yiwei Zhange926ab52019-08-14 15:16:00 -0700313 android::base::StringAppendF(&result, "Number of layers in the stats pool is %zu\n",
314 mTimeStats.stats.size());
Yiwei Zhang7eb58b72019-04-22 19:00:02 -0700315 return result;
316}
317
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700318void TimeStats::incrementTotalFrames() {
319 if (!mEnabled.load()) return;
320
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000321 SFTRACE_CALL();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700322
323 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800324 mTimeStats.totalFramesLegacy++;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700325}
326
Yiwei Zhang621f9d42018-05-07 10:40:55 -0700327void TimeStats::incrementMissedFrames() {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700328 if (!mEnabled.load()) return;
329
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000330 SFTRACE_CALL();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700331
332 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800333 mTimeStats.missedFramesLegacy++;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700334}
335
Vishnu Nair9cf89262022-02-26 09:17:49 -0800336void TimeStats::pushCompositionStrategyState(const TimeStats::ClientCompositionRecord& record) {
337 if (!mEnabled.load() || !record.hasInterestingData()) {
338 return;
339 }
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700340
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000341 SFTRACE_CALL();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700342
343 std::lock_guard<std::mutex> lock(mMutex);
Vishnu Nair9cf89262022-02-26 09:17:49 -0800344 if (record.changed) mTimeStats.compositionStrategyChangesLegacy++;
345 if (record.hadClientComposition) mTimeStats.clientCompositionFramesLegacy++;
346 if (record.reused) mTimeStats.clientCompositionReusedFramesLegacy++;
347 if (record.predicted) mTimeStats.compositionStrategyPredictedLegacy++;
348 if (record.predictionSucceeded) mTimeStats.compositionStrategyPredictionSucceededLegacy++;
Vishnu Nair9b079a22020-01-21 14:36:08 -0800349}
350
Alec Mouri8de697e2020-03-19 10:52:01 -0700351void TimeStats::incrementRefreshRateSwitches() {
352 if (!mEnabled.load()) return;
353
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000354 SFTRACE_CALL();
Alec Mouri8de697e2020-03-19 10:52:01 -0700355
356 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800357 mTimeStats.refreshRateSwitchesLegacy++;
Alec Mouri8de697e2020-03-19 10:52:01 -0700358}
359
Ady Abraham3e8cc072021-05-11 16:29:54 -0700360static int32_t toMs(nsecs_t nanos) {
361 int64_t millis =
362 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::nanoseconds(nanos))
363 .count();
364 millis = std::clamp(millis, int64_t(INT32_MIN), int64_t(INT32_MAX));
365 return static_cast<int32_t>(millis);
366}
367
Alec Mouri9519bf12019-11-15 16:54:44 -0800368static int32_t msBetween(nsecs_t start, nsecs_t end) {
Ady Abraham3e8cc072021-05-11 16:29:54 -0700369 return toMs(end - start);
Alec Mouri9519bf12019-11-15 16:54:44 -0800370}
371
372void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) {
373 if (!mEnabled.load()) return;
374
375 std::lock_guard<std::mutex> lock(mMutex);
Peiyong Lin65248e02020-04-18 21:15:07 -0700376 if (mPowerTime.powerMode == PowerMode::ON) {
Alec Mouri7d436ec2021-01-27 20:40:50 -0800377 mTimeStats.frameDurationLegacy.insert(msBetween(startTime, endTime));
Alec Mouri9519bf12019-11-15 16:54:44 -0800378 }
379}
380
Alec Mourie4034bb2019-11-19 12:45:54 -0800381void TimeStats::recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) {
382 if (!mEnabled.load()) return;
383
384 std::lock_guard<std::mutex> lock(mMutex);
385 if (mGlobalRecord.renderEngineDurations.size() == MAX_NUM_TIME_RECORDS) {
386 ALOGE("RenderEngineTimes are already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
387 mGlobalRecord.renderEngineDurations.pop_front();
388 }
389 mGlobalRecord.renderEngineDurations.push_back({startTime, endTime});
390}
391
392void TimeStats::recordRenderEngineDuration(nsecs_t startTime,
393 const std::shared_ptr<FenceTime>& endTime) {
394 if (!mEnabled.load()) return;
395
396 std::lock_guard<std::mutex> lock(mMutex);
397 if (mGlobalRecord.renderEngineDurations.size() == MAX_NUM_TIME_RECORDS) {
398 ALOGE("RenderEngineTimes are already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
399 mGlobalRecord.renderEngineDurations.pop_front();
400 }
401 mGlobalRecord.renderEngineDurations.push_back({startTime, endTime});
402}
403
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800404bool TimeStats::recordReadyLocked(int32_t layerId, TimeRecord* timeRecord) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700405 if (!timeRecord->ready) {
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800406 ALOGV("[%d]-[%" PRIu64 "]-presentFence is still not received", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700407 timeRecord->frameTime.frameNumber);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700408 return false;
409 }
410
411 if (timeRecord->acquireFence != nullptr) {
412 if (timeRecord->acquireFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
413 return false;
414 }
415 if (timeRecord->acquireFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700416 timeRecord->frameTime.acquireTime = timeRecord->acquireFence->getSignalTime();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700417 timeRecord->acquireFence = nullptr;
418 } else {
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800419 ALOGV("[%d]-[%" PRIu64 "]-acquireFence signal time is invalid", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700420 timeRecord->frameTime.frameNumber);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700421 }
422 }
423
424 if (timeRecord->presentFence != nullptr) {
425 if (timeRecord->presentFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
426 return false;
427 }
428 if (timeRecord->presentFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700429 timeRecord->frameTime.presentTime = timeRecord->presentFence->getSignalTime();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700430 timeRecord->presentFence = nullptr;
431 } else {
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800432 ALOGV("[%d]-[%" PRIu64 "]-presentFence signal time invalid", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700433 timeRecord->frameTime.frameNumber);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700434 }
435 }
436
437 return true;
438}
439
Ady Abraham3403a3f2021-04-27 16:58:40 -0700440static int32_t clampToNearestBucket(Fps fps, size_t bucketWidth) {
441 return std::round(fps.getValue() / bucketWidth) * bucketWidth;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800442}
443
444void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
Ady Abraham8b9e6122021-01-26 19:11:45 -0800445 std::optional<Fps> renderRate,
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000446 SetFrameRateVote frameRateVote,
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700447 GameMode gameMode) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000448 SFTRACE_CALL();
Ady Abraham8b9e6122021-01-26 19:11:45 -0800449 ALOGV("[%d]-flushAvailableRecordsToStatsLocked", layerId);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700450
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800451 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700452 TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
Alberto Gonzalez9fe14512022-09-29 21:27:34 +0000453 std::optional<int32_t>& prevPresentToPresentMs = layerRecord.prevPresentToPresentMs;
Yiwei Zhangc5f2c452018-05-08 16:31:56 -0700454 std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800455 const int32_t refreshRateBucket =
Ady Abraham3403a3f2021-04-27 16:58:40 -0700456 clampToNearestBucket(displayRefreshRate, REFRESH_RATE_BUCKET_WIDTH);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800457 const int32_t renderRateBucket =
Ady Abraham3403a3f2021-04-27 16:58:40 -0700458 clampToNearestBucket(renderRate ? *renderRate : displayRefreshRate,
459 RENDER_RATE_BUCKET_WIDTH);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700460 while (!timeRecords.empty()) {
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800461 if (!recordReadyLocked(layerId, &timeRecords[0])) break;
462 ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700463 timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700464
465 if (prevTimeRecord.ready) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700466 uid_t uid = layerRecord.uid;
Yiwei Zhangeafa5cc2019-07-26 15:06:25 -0700467 const std::string& layerName = layerRecord.layerName;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800468 TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
469 if (!mTimeStats.stats.count(timelineKey)) {
470 mTimeStats.stats[timelineKey].key = timelineKey;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700471 }
Alec Mouri7d436ec2021-01-27 20:40:50 -0800472
473 TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey];
474
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000475 TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName, gameMode};
Alec Mouri7d436ec2021-01-27 20:40:50 -0800476 if (!displayStats.stats.count(layerKey)) {
477 displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
478 displayStats.stats[layerKey].renderRateBucket = renderRateBucket;
479 displayStats.stats[layerKey].uid = uid;
480 displayStats.stats[layerKey].layerName = layerName;
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000481 displayStats.stats[layerKey].gameMode = gameMode;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800482 }
Ady Abraham8b9e6122021-01-26 19:11:45 -0800483 if (frameRateVote.frameRate > 0.0f) {
484 displayStats.stats[layerKey].setFrameRateVote = frameRateVote;
485 }
Alec Mouri7d436ec2021-01-27 20:40:50 -0800486 TimeStatsHelper::TimeStatsLayer& timeStatsLayer = displayStats.stats[layerKey];
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700487 timeStatsLayer.totalFrames++;
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700488 timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
Alec Mouri91f6df32020-01-30 08:48:58 -0800489 timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames;
490 timeStatsLayer.badDesiredPresentFrames += layerRecord.badDesiredPresentFrames;
491
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700492 layerRecord.droppedFrames = 0;
Alec Mouri91f6df32020-01-30 08:48:58 -0800493 layerRecord.lateAcquireFrames = 0;
494 layerRecord.badDesiredPresentFrames = 0;
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700495
496 const int32_t postToAcquireMs = msBetween(timeRecords[0].frameTime.postTime,
497 timeRecords[0].frameTime.acquireTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800498 ALOGV("[%d]-[%" PRIu64 "]-post2acquire[%d]", layerId,
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700499 timeRecords[0].frameTime.frameNumber, postToAcquireMs);
500 timeStatsLayer.deltas["post2acquire"].insert(postToAcquireMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700501
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700502 const int32_t postToPresentMs = msBetween(timeRecords[0].frameTime.postTime,
503 timeRecords[0].frameTime.presentTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800504 ALOGV("[%d]-[%" PRIu64 "]-post2present[%d]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700505 timeRecords[0].frameTime.frameNumber, postToPresentMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700506 timeStatsLayer.deltas["post2present"].insert(postToPresentMs);
507
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700508 const int32_t acquireToPresentMs = msBetween(timeRecords[0].frameTime.acquireTime,
509 timeRecords[0].frameTime.presentTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800510 ALOGV("[%d]-[%" PRIu64 "]-acquire2present[%d]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700511 timeRecords[0].frameTime.frameNumber, acquireToPresentMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700512 timeStatsLayer.deltas["acquire2present"].insert(acquireToPresentMs);
513
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700514 const int32_t latchToPresentMs = msBetween(timeRecords[0].frameTime.latchTime,
515 timeRecords[0].frameTime.presentTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800516 ALOGV("[%d]-[%" PRIu64 "]-latch2present[%d]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700517 timeRecords[0].frameTime.frameNumber, latchToPresentMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700518 timeStatsLayer.deltas["latch2present"].insert(latchToPresentMs);
519
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700520 const int32_t desiredToPresentMs = msBetween(timeRecords[0].frameTime.desiredTime,
521 timeRecords[0].frameTime.presentTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800522 ALOGV("[%d]-[%" PRIu64 "]-desired2present[%d]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700523 timeRecords[0].frameTime.frameNumber, desiredToPresentMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700524 timeStatsLayer.deltas["desired2present"].insert(desiredToPresentMs);
525
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700526 const int32_t presentToPresentMs = msBetween(prevTimeRecord.frameTime.presentTime,
527 timeRecords[0].frameTime.presentTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800528 ALOGV("[%d]-[%" PRIu64 "]-present2present[%d]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700529 timeRecords[0].frameTime.frameNumber, presentToPresentMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700530 timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
Alberto Gonzalez9fe14512022-09-29 21:27:34 +0000531 if (prevPresentToPresentMs) {
532 const int32_t presentToPresentDeltaMs =
533 std::abs(presentToPresentMs - *prevPresentToPresentMs);
534 timeStatsLayer.deltas["present2presentDelta"].insert(presentToPresentDeltaMs);
535 }
536 prevPresentToPresentMs = presentToPresentMs;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700537 }
538 prevTimeRecord = timeRecords[0];
Yiwei Zhangc5f2c452018-05-08 16:31:56 -0700539 timeRecords.pop_front();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700540 layerRecord.waitData--;
541 }
542}
543
Yiwei Zhang8bec7e82019-10-07 18:08:26 -0700544static constexpr const char* kPopupWindowPrefix = "PopupWindow";
545static const size_t kMinLenLayerName = std::strlen(kPopupWindowPrefix);
Yiwei Zhangbd408322018-10-15 18:31:53 -0700546
Yiwei Zhang8bec7e82019-10-07 18:08:26 -0700547// Avoid tracking the "PopupWindow:<random hash>#<number>" layers
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700548static bool layerNameIsValid(const std::string& layerName) {
Yiwei Zhang8bec7e82019-10-07 18:08:26 -0700549 return layerName.length() >= kMinLenLayerName &&
550 layerName.compare(0, kMinLenLayerName, kPopupWindowPrefix) != 0;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700551}
552
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000553bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName,
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700554 GameMode gameMode) {
Alec Mouri7d436ec2021-01-27 20:40:50 -0800555 uint32_t layerRecords = 0;
556 for (const auto& record : mTimeStats.stats) {
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000557 if (record.second.stats.count({uid, layerName, gameMode}) > 0) {
Alec Mouri7d436ec2021-01-27 20:40:50 -0800558 return true;
559 }
560
561 layerRecords += record.second.stats.size();
562 }
563
Dominik Laskowskib4ba8f52021-09-27 18:20:58 -0700564 return layerRecords < MAX_NUM_LAYER_STATS;
Alec Mouri9a29e672020-09-14 12:39:14 -0700565}
566
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800567void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700568 uid_t uid, nsecs_t postTime, GameMode gameMode) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700569 if (!mEnabled.load()) return;
570
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000571 SFTRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800572 ALOGV("[%d]-[%" PRIu64 "]-[%s]-PostTime[%" PRId64 "]", layerId, frameNumber, layerName.c_str(),
Yiwei Zhang8e8fe522018-11-02 18:34:07 -0700573 postTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700574
575 std::lock_guard<std::mutex> lock(mMutex);
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000576 if (!canAddNewAggregatedStats(uid, layerName, gameMode)) {
Yiwei Zhange926ab52019-08-14 15:16:00 -0700577 return;
578 }
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800579 if (!mTimeStatsTracker.count(layerId) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS &&
Yiwei Zhang7eb58b72019-04-22 19:00:02 -0700580 layerNameIsValid(layerName)) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700581 mTimeStatsTracker[layerId].uid = uid;
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800582 mTimeStatsTracker[layerId].layerName = layerName;
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000583 mTimeStatsTracker[layerId].gameMode = gameMode;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700584 }
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800585 if (!mTimeStatsTracker.count(layerId)) return;
586 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700587 if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
Yiwei Zhangaf8ee942018-11-22 00:15:23 -0800588 ALOGE("[%d]-[%s]-timeRecords is at its maximum size[%zu]. Ignore this when unittesting.",
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800589 layerId, layerRecord.layerName.c_str(), MAX_NUM_TIME_RECORDS);
590 mTimeStatsTracker.erase(layerId);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700591 return;
592 }
593 // For most media content, the acquireFence is invalid because the buffer is
594 // ready at the queueBuffer stage. In this case, acquireTime should be given
595 // a default value as postTime.
596 TimeRecord timeRecord = {
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700597 .frameTime =
598 {
599 .frameNumber = frameNumber,
600 .postTime = postTime,
Yiwei Zhangaf8ee942018-11-22 00:15:23 -0800601 .latchTime = postTime,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700602 .acquireTime = postTime,
Yiwei Zhangaf8ee942018-11-22 00:15:23 -0800603 .desiredTime = postTime,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700604 },
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700605 };
606 layerRecord.timeRecords.push_back(timeRecord);
607 if (layerRecord.waitData < 0 ||
608 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
609 layerRecord.waitData = layerRecord.timeRecords.size() - 1;
610}
611
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800612void TimeStats::setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700613 if (!mEnabled.load()) return;
614
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000615 SFTRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800616 ALOGV("[%d]-[%" PRIu64 "]-LatchTime[%" PRId64 "]", layerId, frameNumber, latchTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700617
618 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800619 if (!mTimeStatsTracker.count(layerId)) return;
620 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700621 if (layerRecord.waitData < 0 ||
622 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
623 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700624 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700625 if (timeRecord.frameTime.frameNumber == frameNumber) {
626 timeRecord.frameTime.latchTime = latchTime;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700627 }
628}
629
Alec Mouri91f6df32020-01-30 08:48:58 -0800630void TimeStats::incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) {
631 if (!mEnabled.load()) return;
632
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000633 SFTRACE_CALL();
Alec Mouri91f6df32020-01-30 08:48:58 -0800634 ALOGV("[%d]-LatchSkipped-Reason[%d]", layerId,
635 static_cast<std::underlying_type<LatchSkipReason>::type>(reason));
636
637 std::lock_guard<std::mutex> lock(mMutex);
638 if (!mTimeStatsTracker.count(layerId)) return;
639 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
640
641 switch (reason) {
642 case LatchSkipReason::LateAcquire:
643 layerRecord.lateAcquireFrames++;
644 break;
645 }
646}
647
648void TimeStats::incrementBadDesiredPresent(int32_t layerId) {
649 if (!mEnabled.load()) return;
650
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000651 SFTRACE_CALL();
Alec Mouri91f6df32020-01-30 08:48:58 -0800652 ALOGV("[%d]-BadDesiredPresent", layerId);
653
654 std::lock_guard<std::mutex> lock(mMutex);
655 if (!mTimeStatsTracker.count(layerId)) return;
656 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
657 layerRecord.badDesiredPresentFrames++;
658}
659
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800660void TimeStats::setDesiredTime(int32_t layerId, uint64_t frameNumber, nsecs_t desiredTime) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700661 if (!mEnabled.load()) return;
662
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000663 SFTRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800664 ALOGV("[%d]-[%" PRIu64 "]-DesiredTime[%" PRId64 "]", layerId, frameNumber, desiredTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700665
666 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800667 if (!mTimeStatsTracker.count(layerId)) return;
668 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700669 if (layerRecord.waitData < 0 ||
670 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
671 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700672 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700673 if (timeRecord.frameTime.frameNumber == frameNumber) {
674 timeRecord.frameTime.desiredTime = desiredTime;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700675 }
676}
677
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800678void TimeStats::setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700679 if (!mEnabled.load()) return;
680
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000681 SFTRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800682 ALOGV("[%d]-[%" PRIu64 "]-AcquireTime[%" PRId64 "]", layerId, frameNumber, acquireTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700683
684 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800685 if (!mTimeStatsTracker.count(layerId)) return;
686 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700687 if (layerRecord.waitData < 0 ||
688 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
689 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700690 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700691 if (timeRecord.frameTime.frameNumber == frameNumber) {
692 timeRecord.frameTime.acquireTime = acquireTime;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700693 }
694}
695
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800696void TimeStats::setAcquireFence(int32_t layerId, uint64_t frameNumber,
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700697 const std::shared_ptr<FenceTime>& acquireFence) {
698 if (!mEnabled.load()) return;
699
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000700 SFTRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800701 ALOGV("[%d]-[%" PRIu64 "]-AcquireFenceTime[%" PRId64 "]", layerId, frameNumber,
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700702 acquireFence->getSignalTime());
703
704 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800705 if (!mTimeStatsTracker.count(layerId)) return;
706 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700707 if (layerRecord.waitData < 0 ||
708 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
709 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700710 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700711 if (timeRecord.frameTime.frameNumber == frameNumber) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700712 timeRecord.acquireFence = acquireFence;
713 }
714}
715
Alec Mouri7d436ec2021-01-27 20:40:50 -0800716void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
Ady Abraham8b9e6122021-01-26 19:11:45 -0800717 Fps displayRefreshRate, std::optional<Fps> renderRate,
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700718 SetFrameRateVote frameRateVote, GameMode gameMode) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700719 if (!mEnabled.load()) return;
720
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000721 SFTRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800722 ALOGV("[%d]-[%" PRIu64 "]-PresentTime[%" PRId64 "]", layerId, frameNumber, presentTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700723
724 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800725 if (!mTimeStatsTracker.count(layerId)) return;
726 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700727 if (layerRecord.waitData < 0 ||
728 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
729 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700730 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700731 if (timeRecord.frameTime.frameNumber == frameNumber) {
732 timeRecord.frameTime.presentTime = presentTime;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700733 timeRecord.ready = true;
734 layerRecord.waitData++;
735 }
736
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000737 flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote,
738 gameMode);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700739}
740
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800741void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
Alec Mouri7d436ec2021-01-27 20:40:50 -0800742 const std::shared_ptr<FenceTime>& presentFence,
Ady Abraham8b9e6122021-01-26 19:11:45 -0800743 Fps displayRefreshRate, std::optional<Fps> renderRate,
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700744 SetFrameRateVote frameRateVote, GameMode gameMode) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700745 if (!mEnabled.load()) return;
746
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000747 SFTRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800748 ALOGV("[%d]-[%" PRIu64 "]-PresentFenceTime[%" PRId64 "]", layerId, frameNumber,
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700749 presentFence->getSignalTime());
750
751 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800752 if (!mTimeStatsTracker.count(layerId)) return;
753 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700754 if (layerRecord.waitData < 0 ||
755 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
756 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700757 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700758 if (timeRecord.frameTime.frameNumber == frameNumber) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700759 timeRecord.presentFence = presentFence;
760 timeRecord.ready = true;
761 layerRecord.waitData++;
762 }
763
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000764 flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote,
765 gameMode);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700766}
767
Adithya Srinivasanead17162021-02-18 02:17:37 +0000768static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL |
769 JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed |
770 JankType::AppDeadlineMissed | JankType::PredictionError |
Adithya Srinivasan53e5c402021-04-16 17:34:30 +0000771 JankType::SurfaceFlingerScheduling;
Alec Mouri363faf02021-01-29 16:34:55 -0800772
Alec Mouri9a29e672020-09-14 12:39:14 -0700773template <class T>
774static void updateJankPayload(T& t, int32_t reasons) {
775 t.jankPayload.totalFrames++;
776
Alec Mouri9a29e672020-09-14 12:39:14 -0700777 if (reasons & kValidJankyReason) {
778 t.jankPayload.totalJankyFrames++;
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800779 if ((reasons & JankType::SurfaceFlingerCpuDeadlineMissed) != 0) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700780 t.jankPayload.totalSFLongCpu++;
781 }
Jorim Jaggi5814ab82020-12-03 20:45:58 +0100782 if ((reasons & JankType::SurfaceFlingerGpuDeadlineMissed) != 0) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700783 t.jankPayload.totalSFLongGpu++;
784 }
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800785 if ((reasons & JankType::DisplayHAL) != 0) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700786 t.jankPayload.totalSFUnattributed++;
787 }
Jorim Jaggi5814ab82020-12-03 20:45:58 +0100788 if ((reasons & JankType::AppDeadlineMissed) != 0) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700789 t.jankPayload.totalAppUnattributed++;
790 }
Adithya Srinivasanead17162021-02-18 02:17:37 +0000791 if ((reasons & JankType::PredictionError) != 0) {
792 t.jankPayload.totalSFPredictionError++;
793 }
794 if ((reasons & JankType::SurfaceFlingerScheduling) != 0) {
795 t.jankPayload.totalSFScheduling++;
796 }
Adithya Srinivasan53e5c402021-04-16 17:34:30 +0000797 }
798
799 // We want to track BufferStuffing separately as it can provide info on latency issues
800 if (reasons & JankType::BufferStuffing) {
801 t.jankPayload.totalAppBufferStuffing++;
Alec Mouri9a29e672020-09-14 12:39:14 -0700802 }
803}
804
Alec Mouri363faf02021-01-29 16:34:55 -0800805void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700806 if (!mEnabled.load()) return;
807
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000808 SFTRACE_CALL();
Alec Mouri9a29e672020-09-14 12:39:14 -0700809 std::lock_guard<std::mutex> lock(mMutex);
810
Alec Mouri542de112020-11-13 12:07:32 -0800811 // Only update layer stats if we're already tracking the layer in TimeStats.
812 // Otherwise, continue tracking the statistic but use a default layer name instead.
Alec Mouri9a29e672020-09-14 12:39:14 -0700813 // As an implementation detail, we do this because this method is expected to be
Alec Mouri542de112020-11-13 12:07:32 -0800814 // called from FrameTimeline, whose jank classification includes transaction jank
815 // that occurs without a buffer. But, in general those layer names are not suitable as
816 // aggregation keys: e.g., it's normal and expected for Window Manager to include the hash code
817 // for an animation leash. So while we can show that jank in dumpsys, aggregating based on the
818 // layer blows up the stats size, so as a workaround drop those stats. This assumes that
819 // TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that
820 // the first jank record is not dropped.
Alec Mouri9a29e672020-09-14 12:39:14 -0700821
Alec Mouri542de112020-11-13 12:07:32 -0800822 static const std::string kDefaultLayerName = "none";
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700823 constexpr GameMode kDefaultGameMode = GameMode::Unsupported;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800824
Alec Mouri363faf02021-01-29 16:34:55 -0800825 const int32_t refreshRateBucket =
Ady Abraham3403a3f2021-04-27 16:58:40 -0700826 clampToNearestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800827 const int32_t renderRateBucket =
Ady Abraham3403a3f2021-04-27 16:58:40 -0700828 clampToNearestBucket(info.renderRate ? *info.renderRate : info.refreshRate,
829 RENDER_RATE_BUCKET_WIDTH);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800830 const TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
831
832 if (!mTimeStats.stats.count(timelineKey)) {
833 mTimeStats.stats[timelineKey].key = timelineKey;
Alec Mouri9a29e672020-09-14 12:39:14 -0700834 }
835
Alec Mouri7d436ec2021-01-27 20:40:50 -0800836 TimeStatsHelper::TimelineStats& timelineStats = mTimeStats.stats[timelineKey];
837
Alec Mouri363faf02021-01-29 16:34:55 -0800838 updateJankPayload<TimeStatsHelper::TimelineStats>(timelineStats, info.reasons);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800839
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000840 TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName, info.gameMode};
Alec Mouri7d436ec2021-01-27 20:40:50 -0800841 if (!timelineStats.stats.count(layerKey)) {
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000842 layerKey = {info.uid, kDefaultLayerName, kDefaultGameMode};
Alec Mouri7d436ec2021-01-27 20:40:50 -0800843 timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
844 timelineStats.stats[layerKey].renderRateBucket = renderRateBucket;
Alec Mouri363faf02021-01-29 16:34:55 -0800845 timelineStats.stats[layerKey].uid = info.uid;
Adithya Srinivasanf427f762021-06-15 19:46:26 +0000846 timelineStats.stats[layerKey].layerName = kDefaultLayerName;
847 timelineStats.stats[layerKey].gameMode = kDefaultGameMode;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800848 }
849
850 TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey];
Alec Mouri363faf02021-01-29 16:34:55 -0800851 updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, info.reasons);
852
853 if (info.reasons & kValidJankyReason) {
854 // TimeStats Histograms only retain positive values, so we don't need to check if these
855 // deadlines were really missed if we know that the frame had jank, since deadlines
856 // that were met will be dropped.
Ady Abraham3e8cc072021-05-11 16:29:54 -0700857 timelineStats.displayDeadlineDeltas.insert(toMs(info.displayDeadlineDelta));
858 timelineStats.displayPresentDeltas.insert(toMs(info.displayPresentJitter));
859 timeStatsLayer.deltas["appDeadlineDeltas"].insert(toMs(info.appDeadlineDelta));
Alec Mouri363faf02021-01-29 16:34:55 -0800860 }
Alec Mouri9a29e672020-09-14 12:39:14 -0700861}
862
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800863void TimeStats::onDestroy(int32_t layerId) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000864 SFTRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800865 ALOGV("[%d]-onDestroy", layerId);
Mikael Pessa90092f42019-08-26 17:22:04 -0700866 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800867 mTimeStatsTracker.erase(layerId);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700868}
869
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800870void TimeStats::removeTimeRecord(int32_t layerId, uint64_t frameNumber) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700871 if (!mEnabled.load()) return;
872
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000873 SFTRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800874 ALOGV("[%d]-[%" PRIu64 "]-removeTimeRecord", layerId, frameNumber);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700875
876 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800877 if (!mTimeStatsTracker.count(layerId)) return;
878 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700879 size_t removeAt = 0;
880 for (const TimeRecord& record : layerRecord.timeRecords) {
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700881 if (record.frameTime.frameNumber == frameNumber) break;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700882 removeAt++;
883 }
884 if (removeAt == layerRecord.timeRecords.size()) return;
885 layerRecord.timeRecords.erase(layerRecord.timeRecords.begin() + removeAt);
886 if (layerRecord.waitData > static_cast<int32_t>(removeAt)) {
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700887 layerRecord.waitData--;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700888 }
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700889 layerRecord.droppedFrames++;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700890}
891
Yiwei Zhang3a226d22018-10-16 09:23:03 -0700892void TimeStats::flushPowerTimeLocked() {
Yiwei Zhange5c49d52018-10-29 00:15:31 -0700893 if (!mEnabled.load()) return;
894
Yiwei Zhang3a226d22018-10-16 09:23:03 -0700895 nsecs_t curTime = systemTime();
896 // elapsedTime is in milliseconds.
897 int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
898
899 switch (mPowerTime.powerMode) {
Peiyong Lin65248e02020-04-18 21:15:07 -0700900 case PowerMode::ON:
Alec Mouri7d436ec2021-01-27 20:40:50 -0800901 mTimeStats.displayOnTimeLegacy += elapsedTime;
Yiwei Zhang3a226d22018-10-16 09:23:03 -0700902 break;
Peiyong Lin65248e02020-04-18 21:15:07 -0700903 case PowerMode::OFF:
904 case PowerMode::DOZE:
905 case PowerMode::DOZE_SUSPEND:
906 case PowerMode::ON_SUSPEND:
Yiwei Zhang3a226d22018-10-16 09:23:03 -0700907 default:
908 break;
909 }
910
911 mPowerTime.prevTime = curTime;
912}
913
Peiyong Lin65248e02020-04-18 21:15:07 -0700914void TimeStats::setPowerMode(PowerMode powerMode) {
Yiwei Zhang3a226d22018-10-16 09:23:03 -0700915 if (!mEnabled.load()) {
916 std::lock_guard<std::mutex> lock(mMutex);
917 mPowerTime.powerMode = powerMode;
918 return;
919 }
920
921 std::lock_guard<std::mutex> lock(mMutex);
922 if (powerMode == mPowerTime.powerMode) return;
923
924 flushPowerTimeLocked();
925 mPowerTime.powerMode = powerMode;
926}
927
Alec Mourifb571ea2019-01-24 18:42:10 -0800928void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
929 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800930 if (mTimeStats.refreshRateStatsLegacy.count(fps)) {
931 mTimeStats.refreshRateStatsLegacy[fps] += duration;
Alec Mourifb571ea2019-01-24 18:42:10 -0800932 } else {
Alec Mouri7d436ec2021-01-27 20:40:50 -0800933 mTimeStats.refreshRateStatsLegacy.insert({fps, duration});
Alec Mourifb571ea2019-01-24 18:42:10 -0800934 }
935}
936
Yiwei Zhangce6ebc02018-10-20 12:42:38 -0700937void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000938 SFTRACE_CALL();
Yiwei Zhangce6ebc02018-10-20 12:42:38 -0700939
940 while (!mGlobalRecord.presentFences.empty()) {
941 const nsecs_t curPresentTime = mGlobalRecord.presentFences.front()->getSignalTime();
942 if (curPresentTime == Fence::SIGNAL_TIME_PENDING) break;
943
944 if (curPresentTime == Fence::SIGNAL_TIME_INVALID) {
945 ALOGE("GlobalPresentFence is invalid!");
946 mGlobalRecord.prevPresentTime = 0;
947 mGlobalRecord.presentFences.pop_front();
948 continue;
949 }
950
951 ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
952 mGlobalRecord.presentFences.front()->getSignalTime());
953
Yiwei Zhange5c49d52018-10-29 00:15:31 -0700954 if (mGlobalRecord.prevPresentTime != 0) {
955 const int32_t presentToPresentMs =
956 msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
957 ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
958 presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800959 mTimeStats.presentToPresentLegacy.insert(presentToPresentMs);
Yiwei Zhange5c49d52018-10-29 00:15:31 -0700960 }
Yiwei Zhangce6ebc02018-10-20 12:42:38 -0700961
Yiwei Zhangce6ebc02018-10-20 12:42:38 -0700962 mGlobalRecord.prevPresentTime = curPresentTime;
963 mGlobalRecord.presentFences.pop_front();
964 }
Alec Mourie4034bb2019-11-19 12:45:54 -0800965 while (!mGlobalRecord.renderEngineDurations.empty()) {
966 const auto duration = mGlobalRecord.renderEngineDurations.front();
967 const auto& endTime = duration.endTime;
968
969 nsecs_t endNs = -1;
970
971 if (auto val = std::get_if<nsecs_t>(&endTime)) {
972 endNs = *val;
973 } else {
974 endNs = std::get<std::shared_ptr<FenceTime>>(endTime)->getSignalTime();
975 }
976
977 if (endNs == Fence::SIGNAL_TIME_PENDING) break;
978
979 if (endNs < 0) {
980 ALOGE("RenderEngineTiming is invalid!");
981 mGlobalRecord.renderEngineDurations.pop_front();
982 continue;
983 }
984
985 const int32_t renderEngineMs = msBetween(duration.startTime, endNs);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800986 mTimeStats.renderEngineTimingLegacy.insert(renderEngineMs);
Alec Mourie4034bb2019-11-19 12:45:54 -0800987
988 mGlobalRecord.renderEngineDurations.pop_front();
989 }
Yiwei Zhangce6ebc02018-10-20 12:42:38 -0700990}
991
992void TimeStats::setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) {
993 if (!mEnabled.load()) return;
994
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000995 SFTRACE_CALL();
Yiwei Zhangce6ebc02018-10-20 12:42:38 -0700996 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhange5c49d52018-10-29 00:15:31 -0700997 if (presentFence == nullptr || !presentFence->isValid()) {
998 mGlobalRecord.prevPresentTime = 0;
999 return;
1000 }
1001
Peiyong Lin65248e02020-04-18 21:15:07 -07001002 if (mPowerTime.powerMode != PowerMode::ON) {
1003 // Try flushing the last present fence on PowerMode::ON.
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001004 flushAvailableGlobalRecordsToStatsLocked();
1005 mGlobalRecord.presentFences.clear();
Yiwei Zhangce6ebc02018-10-20 12:42:38 -07001006 mGlobalRecord.prevPresentTime = 0;
1007 return;
1008 }
1009
1010 if (mGlobalRecord.presentFences.size() == MAX_NUM_TIME_RECORDS) {
1011 // The front presentFence must be trapped in pending status in this
1012 // case. Try dequeuing the front one to recover.
1013 ALOGE("GlobalPresentFences is already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
1014 mGlobalRecord.prevPresentTime = 0;
1015 mGlobalRecord.presentFences.pop_front();
1016 }
1017
1018 mGlobalRecord.presentFences.emplace_back(presentFence);
1019 flushAvailableGlobalRecordsToStatsLocked();
1020}
1021
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001022void TimeStats::enable() {
1023 if (mEnabled.load()) return;
1024
Vishnu Nairbe0ad902024-06-27 23:38:43 +00001025 SFTRACE_CALL();
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001026
1027 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001028 mEnabled.store(true);
Alec Mouri7d436ec2021-01-27 20:40:50 -08001029 mTimeStats.statsStartLegacy = static_cast<int64_t>(std::time(0));
Yiwei Zhang3a226d22018-10-16 09:23:03 -07001030 mPowerTime.prevTime = systemTime();
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001031 ALOGD("Enabled");
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001032}
1033
1034void TimeStats::disable() {
1035 if (!mEnabled.load()) return;
1036
Vishnu Nairbe0ad902024-06-27 23:38:43 +00001037 SFTRACE_CALL();
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001038
1039 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001040 flushPowerTimeLocked();
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001041 mEnabled.store(false);
Alec Mouri7d436ec2021-01-27 20:40:50 -08001042 mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001043 ALOGD("Disabled");
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001044}
1045
Alec Mouri8e2f31b2020-01-16 22:04:35 +00001046void TimeStats::clearAll() {
1047 std::lock_guard<std::mutex> lock(mMutex);
Ady Abraham3403a3f2021-04-27 16:58:40 -07001048 mTimeStats.stats.clear();
Alec Mouri8e2f31b2020-01-16 22:04:35 +00001049 clearGlobalLocked();
1050 clearLayersLocked();
1051}
1052
1053void TimeStats::clearGlobalLocked() {
Vishnu Nairbe0ad902024-06-27 23:38:43 +00001054 SFTRACE_CALL();
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001055
Alec Mouri7d436ec2021-01-27 20:40:50 -08001056 mTimeStats.statsStartLegacy = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
1057 mTimeStats.statsEndLegacy = 0;
1058 mTimeStats.totalFramesLegacy = 0;
1059 mTimeStats.missedFramesLegacy = 0;
1060 mTimeStats.clientCompositionFramesLegacy = 0;
1061 mTimeStats.clientCompositionReusedFramesLegacy = 0;
Robert Carra00eb142022-03-09 13:49:30 -08001062 mTimeStats.compositionStrategyChangesLegacy = 0;
Vishnu Nair9cf89262022-02-26 09:17:49 -08001063 mTimeStats.compositionStrategyPredictedLegacy = 0;
1064 mTimeStats.compositionStrategyPredictionSucceededLegacy = 0;
1065 mTimeStats.refreshRateSwitchesLegacy = 0;
Alec Mouri7d436ec2021-01-27 20:40:50 -08001066 mTimeStats.displayOnTimeLegacy = 0;
1067 mTimeStats.presentToPresentLegacy.hist.clear();
1068 mTimeStats.frameDurationLegacy.hist.clear();
1069 mTimeStats.renderEngineTimingLegacy.hist.clear();
1070 mTimeStats.refreshRateStatsLegacy.clear();
Yiwei Zhang3a226d22018-10-16 09:23:03 -07001071 mPowerTime.prevTime = systemTime();
Alec Mouri56e63852021-03-09 18:17:25 -08001072 for (auto& globalRecord : mTimeStats.stats) {
1073 globalRecord.second.clearGlobals();
1074 }
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001075 mGlobalRecord.prevPresentTime = 0;
1076 mGlobalRecord.presentFences.clear();
Alec Mouri8e2f31b2020-01-16 22:04:35 +00001077 ALOGD("Cleared global stats");
1078}
1079
1080void TimeStats::clearLayersLocked() {
Vishnu Nairbe0ad902024-06-27 23:38:43 +00001081 SFTRACE_CALL();
Alec Mouri8e2f31b2020-01-16 22:04:35 +00001082
1083 mTimeStatsTracker.clear();
Alec Mouri56e63852021-03-09 18:17:25 -08001084
1085 for (auto& globalRecord : mTimeStats.stats) {
1086 globalRecord.second.stats.clear();
1087 }
Alec Mouri8e2f31b2020-01-16 22:04:35 +00001088 ALOGD("Cleared layer stats");
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001089}
1090
1091bool TimeStats::isEnabled() {
1092 return mEnabled.load();
1093}
1094
Yiwei Zhang5434a782018-12-05 18:06:32 -08001095void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +00001096 SFTRACE_CALL();
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001097
1098 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -08001099 if (mTimeStats.statsStartLegacy == 0) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001100 return;
1101 }
1102
Alec Mouri7d436ec2021-01-27 20:40:50 -08001103 mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001104
Yiwei Zhang3a226d22018-10-16 09:23:03 -07001105 flushPowerTimeLocked();
1106
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001107 if (asProto) {
Yiwei Zhang8a4015c2018-05-08 16:03:47 -07001108 ALOGD("Dumping TimeStats as proto");
Yiwei Zhangdc224042018-10-18 15:34:00 -07001109 SFTimeStatsGlobalProto timeStatsProto = mTimeStats.toProto(maxLayers);
Dominik Laskowski46470112019-08-02 13:13:11 -07001110 result.append(timeStatsProto.SerializeAsString());
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001111 } else {
Yiwei Zhang8a4015c2018-05-08 16:03:47 -07001112 ALOGD("Dumping TimeStats as text");
Yiwei Zhang5434a782018-12-05 18:06:32 -08001113 result.append(mTimeStats.toString(maxLayers));
Yiwei Zhang8a4015c2018-05-08 16:03:47 -07001114 result.append("\n");
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001115 }
1116}
1117
Alec Mourifb571ea2019-01-24 18:42:10 -08001118} // namespace impl
1119
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001120} // namespace android