blob: c8eef462f1952207efeb510de051d02b5ff7f015 [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>
Yiwei Zhang0102ad22018-05-02 17:37:17 -070022#include <log/log.h>
Tej Singhe2751772021-04-06 22:05:29 -070023#include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h>
Yiwei Zhang0102ad22018-05-02 17:37:17 -070024#include <utils/String8.h>
Yiwei Zhang3a226d22018-10-16 09:23:03 -070025#include <utils/Timers.h>
Yiwei Zhang0102ad22018-05-02 17:37:17 -070026#include <utils/Trace.h>
27
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;
72 default:
73 return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSPECIFIED;
74 }
75}
76
Tej Singhe2751772021-04-06 22:05:29 -070077SurfaceflingerStatsLayerInfo_SetFrameRateVote frameRateVoteToProto(
78 const TimeStats::SetFrameRateVote& setFrameRateVote) {
79 using FrameRateCompatibilityEnum =
80 SurfaceflingerStatsLayerInfo::SetFrameRateVote::FrameRateCompatibility;
81 using SeamlessnessEnum = SurfaceflingerStatsLayerInfo::SetFrameRateVote::Seamlessness;
Alec Mouri75de8f22021-01-20 14:53:44 -080082
Tej Singhe2751772021-04-06 22:05:29 -070083 SurfaceflingerStatsLayerInfo_SetFrameRateVote proto;
84 proto.set_frame_rate(setFrameRateVote.frameRate);
85 proto.set_frame_rate_compatibility(
86 static_cast<FrameRateCompatibilityEnum>(setFrameRateVote.frameRateCompatibility));
87 proto.set_seamlessness(static_cast<SeamlessnessEnum>(setFrameRateVote.seamlessness));
88 return proto;
Alec Mouri75de8f22021-01-20 14:53:44 -080089}
Alec Mouri37384342020-01-02 17:23:37 -080090} // namespace
91
Tej Singhe2751772021-04-06 22:05:29 -070092bool TimeStats::populateGlobalAtom(std::string* pulledData) {
Alec Mouridfad9002020-02-12 17:49:09 -080093 std::lock_guard<std::mutex> lock(mMutex);
94
Alec Mouri7d436ec2021-01-27 20:40:50 -080095 if (mTimeStats.statsStartLegacy == 0) {
Tej Singhe2751772021-04-06 22:05:29 -070096 return false;
Alec Mouridfad9002020-02-12 17:49:09 -080097 }
98 flushPowerTimeLocked();
Tej Singhe2751772021-04-06 22:05:29 -070099 SurfaceflingerStatsGlobalInfoWrapper atomList;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800100 for (const auto& globalSlice : mTimeStats.stats) {
Tej Singhe2751772021-04-06 22:05:29 -0700101 SurfaceflingerStatsGlobalInfo* atom = atomList.add_atom();
102 atom->set_total_frames(mTimeStats.totalFramesLegacy);
103 atom->set_missed_frames(mTimeStats.missedFramesLegacy);
104 atom->set_client_composition_frames(mTimeStats.clientCompositionFramesLegacy);
105 atom->set_display_on_millis(mTimeStats.displayOnTimeLegacy);
106 atom->set_animation_millis(mTimeStats.presentToPresentLegacy.totalTime());
107 atom->set_event_connection_count(mTimeStats.displayEventConnectionsCountLegacy);
108 *atom->mutable_frame_duration() =
109 histogramToProto(mTimeStats.frameDurationLegacy.hist, mMaxPulledHistogramBuckets);
110 *atom->mutable_render_engine_timing() =
111 histogramToProto(mTimeStats.renderEngineTimingLegacy.hist,
112 mMaxPulledHistogramBuckets);
113 atom->set_total_timeline_frames(globalSlice.second.jankPayload.totalFrames);
114 atom->set_total_janky_frames(globalSlice.second.jankPayload.totalJankyFrames);
115 atom->set_total_janky_frames_with_long_cpu(globalSlice.second.jankPayload.totalSFLongCpu);
116 atom->set_total_janky_frames_with_long_gpu(globalSlice.second.jankPayload.totalSFLongGpu);
117 atom->set_total_janky_frames_sf_unattributed(
118 globalSlice.second.jankPayload.totalSFUnattributed);
119 atom->set_total_janky_frames_app_unattributed(
120 globalSlice.second.jankPayload.totalAppUnattributed);
121 atom->set_total_janky_frames_sf_scheduling(
122 globalSlice.second.jankPayload.totalSFScheduling);
123 atom->set_total_jank_frames_sf_prediction_error(
124 globalSlice.second.jankPayload.totalSFPredictionError);
125 atom->set_total_jank_frames_app_buffer_stuffing(
126 globalSlice.second.jankPayload.totalAppBufferStuffing);
127 atom->set_display_refresh_rate_bucket(globalSlice.first.displayRefreshRateBucket);
128 *atom->mutable_sf_deadline_misses() =
129 histogramToProto(globalSlice.second.displayDeadlineDeltas.hist,
130 mMaxPulledHistogramBuckets);
131 *atom->mutable_sf_prediction_errors() =
132 histogramToProto(globalSlice.second.displayPresentDeltas.hist,
133 mMaxPulledHistogramBuckets);
134 atom->set_render_rate_bucket(globalSlice.first.renderRateBucket);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800135 }
136
Tej Singhe2751772021-04-06 22:05:29 -0700137 // Always clear data.
Alec Mouridfad9002020-02-12 17:49:09 -0800138 clearGlobalLocked();
139
Tej Singhe2751772021-04-06 22:05:29 -0700140 return atomList.SerializeToString(pulledData);
Alec Mouridfad9002020-02-12 17:49:09 -0800141}
142
Tej Singhe2751772021-04-06 22:05:29 -0700143bool TimeStats::populateLayerAtom(std::string* pulledData) {
Alec Mouri37384342020-01-02 17:23:37 -0800144 std::lock_guard<std::mutex> lock(mMutex);
145
Alec Mouri363faf02021-01-29 16:34:55 -0800146 std::vector<TimeStatsHelper::TimeStatsLayer*> dumpStats;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800147 uint32_t numLayers = 0;
148 for (const auto& globalSlice : mTimeStats.stats) {
149 numLayers += globalSlice.second.stats.size();
150 }
151
152 dumpStats.reserve(numLayers);
153
Alec Mouri363faf02021-01-29 16:34:55 -0800154 for (auto& globalSlice : mTimeStats.stats) {
155 for (auto& layerSlice : globalSlice.second.stats) {
Alec Mouri7d436ec2021-01-27 20:40:50 -0800156 dumpStats.push_back(&layerSlice.second);
157 }
Alec Mouri37384342020-01-02 17:23:37 -0800158 }
159
160 std::sort(dumpStats.begin(), dumpStats.end(),
161 [](TimeStatsHelper::TimeStatsLayer const* l,
162 TimeStatsHelper::TimeStatsLayer const* r) {
163 return l->totalFrames > r->totalFrames;
164 });
165
166 if (mMaxPulledLayers < dumpStats.size()) {
167 dumpStats.resize(mMaxPulledLayers);
168 }
169
Tej Singhe2751772021-04-06 22:05:29 -0700170 SurfaceflingerStatsLayerInfoWrapper atomList;
Alec Mouri363faf02021-01-29 16:34:55 -0800171 for (auto& layer : dumpStats) {
Tej Singhe2751772021-04-06 22:05:29 -0700172 SurfaceflingerStatsLayerInfo* atom = atomList.add_atom();
173 atom->set_layer_name(layer->layerName);
174 atom->set_total_frames(layer->totalFrames);
175 atom->set_dropped_frames(layer->droppedFrames);
176 const auto& present2PresentHist = layer->deltas.find("present2present");
177 if (present2PresentHist != layer->deltas.cend()) {
178 *atom->mutable_present_to_present() =
179 histogramToProto(present2PresentHist->second.hist, mMaxPulledHistogramBuckets);
180 }
Alberto Gonzalez9fe14512022-09-29 21:27:34 +0000181 const auto& present2PresentDeltaHist = layer->deltas.find("present2presentDelta");
182 if (present2PresentDeltaHist != layer->deltas.cend()) {
183 *atom->mutable_present_to_present_delta() =
184 histogramToProto(present2PresentDeltaHist->second.hist,
185 mMaxPulledHistogramBuckets);
186 }
Tej Singhe2751772021-04-06 22:05:29 -0700187 const auto& post2presentHist = layer->deltas.find("post2present");
188 if (post2presentHist != layer->deltas.cend()) {
189 *atom->mutable_post_to_present() =
190 histogramToProto(post2presentHist->second.hist, mMaxPulledHistogramBuckets);
191 }
192 const auto& acquire2presentHist = layer->deltas.find("acquire2present");
193 if (acquire2presentHist != layer->deltas.cend()) {
194 *atom->mutable_acquire_to_present() =
195 histogramToProto(acquire2presentHist->second.hist, mMaxPulledHistogramBuckets);
196 }
197 const auto& latch2presentHist = layer->deltas.find("latch2present");
198 if (latch2presentHist != layer->deltas.cend()) {
199 *atom->mutable_latch_to_present() =
200 histogramToProto(latch2presentHist->second.hist, mMaxPulledHistogramBuckets);
201 }
202 const auto& desired2presentHist = layer->deltas.find("desired2present");
203 if (desired2presentHist != layer->deltas.cend()) {
204 *atom->mutable_desired_to_present() =
205 histogramToProto(desired2presentHist->second.hist, mMaxPulledHistogramBuckets);
206 }
207 const auto& post2acquireHist = layer->deltas.find("post2acquire");
208 if (post2acquireHist != layer->deltas.cend()) {
209 *atom->mutable_post_to_acquire() =
210 histogramToProto(post2acquireHist->second.hist, mMaxPulledHistogramBuckets);
Alec Mouri37384342020-01-02 17:23:37 -0800211 }
212
Tej Singhe2751772021-04-06 22:05:29 -0700213 atom->set_late_acquire_frames(layer->lateAcquireFrames);
214 atom->set_bad_desired_present_frames(layer->badDesiredPresentFrames);
215 atom->set_uid(layer->uid);
216 atom->set_total_timeline_frames(layer->jankPayload.totalFrames);
217 atom->set_total_janky_frames(layer->jankPayload.totalJankyFrames);
218 atom->set_total_janky_frames_with_long_cpu(layer->jankPayload.totalSFLongCpu);
219 atom->set_total_janky_frames_with_long_gpu(layer->jankPayload.totalSFLongGpu);
220 atom->set_total_janky_frames_sf_unattributed(layer->jankPayload.totalSFUnattributed);
221 atom->set_total_janky_frames_app_unattributed(layer->jankPayload.totalAppUnattributed);
222 atom->set_total_janky_frames_sf_scheduling(layer->jankPayload.totalSFScheduling);
223 atom->set_total_jank_frames_sf_prediction_error(layer->jankPayload.totalSFPredictionError);
224 atom->set_total_jank_frames_app_buffer_stuffing(layer->jankPayload.totalAppBufferStuffing);
225 atom->set_display_refresh_rate_bucket(layer->displayRefreshRateBucket);
226 atom->set_render_rate_bucket(layer->renderRateBucket);
227 *atom->mutable_set_frame_rate_vote() = frameRateVoteToProto(layer->setFrameRateVote);
228 *atom->mutable_app_deadline_misses() =
229 histogramToProto(layer->deltas["appDeadlineDeltas"].hist,
230 mMaxPulledHistogramBuckets);
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000231 atom->set_game_mode(gameModeToProto(layer->gameMode));
Alec Mouri37384342020-01-02 17:23:37 -0800232 }
Tej Singhe2751772021-04-06 22:05:29 -0700233
234 // Always clear data.
Alec Mouri37384342020-01-02 17:23:37 -0800235 clearLayersLocked();
236
Tej Singhe2751772021-04-06 22:05:29 -0700237 return atomList.SerializeToString(pulledData);
Alec Mouri37384342020-01-02 17:23:37 -0800238}
239
Tej Singhe2751772021-04-06 22:05:29 -0700240TimeStats::TimeStats() : TimeStats(std::nullopt, std::nullopt) {}
Alec Mouri37384342020-01-02 17:23:37 -0800241
Tej Singhe2751772021-04-06 22:05:29 -0700242TimeStats::TimeStats(std::optional<size_t> maxPulledLayers,
Alec Mouri37384342020-01-02 17:23:37 -0800243 std::optional<size_t> maxPulledHistogramBuckets) {
Alec Mouri37384342020-01-02 17:23:37 -0800244 if (maxPulledLayers) {
245 mMaxPulledLayers = *maxPulledLayers;
246 }
247
248 if (maxPulledHistogramBuckets) {
249 mMaxPulledHistogramBuckets = *maxPulledHistogramBuckets;
250 }
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000251}
252
Tej Singhe2751772021-04-06 22:05:29 -0700253bool TimeStats::onPullAtom(const int atomId, std::string* pulledData) {
254 bool success = false;
255 if (atomId == 10062) { // SURFACEFLINGER_STATS_GLOBAL_INFO
256 success = populateGlobalAtom(pulledData);
257 } else if (atomId == 10063) { // SURFACEFLINGER_STATS_LAYER_INFO
258 success = populateLayerAtom(pulledData);
259 }
Alec Mouri3ecd5cd2020-01-29 12:53:07 -0800260
Tej Singhe2751772021-04-06 22:05:29 -0700261 // Enable timestats now. The first full pull for a given build is expected to
262 // have empty or very little stats, as stats are first enabled after the
263 // first pull is completed for either the global or layer stats.
264 enable();
265 return success;
Alec Mourib3885ad2019-09-06 17:08:55 -0700266}
267
Dominik Laskowskic2867142019-01-21 11:33:38 -0800268void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700269 ATRACE_CALL();
270
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700271 std::unordered_map<std::string, int32_t> argsMap;
Dominik Laskowskic2867142019-01-21 11:33:38 -0800272 for (size_t index = 0; index < args.size(); ++index) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700273 argsMap[std::string(String8(args[index]).c_str())] = index;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700274 }
275
276 if (argsMap.count("-disable")) {
277 disable();
278 }
279
280 if (argsMap.count("-dump")) {
Yiwei Zhang8a4015c2018-05-08 16:03:47 -0700281 std::optional<uint32_t> maxLayers = std::nullopt;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700282 auto iter = argsMap.find("-maxlayers");
283 if (iter != argsMap.end() && iter->second + 1 < static_cast<int32_t>(args.size())) {
Yiwei Zhang8a4015c2018-05-08 16:03:47 -0700284 int64_t value = strtol(String8(args[iter->second + 1]).c_str(), nullptr, 10);
285 value = std::clamp(value, int64_t(0), int64_t(UINT32_MAX));
286 maxLayers = static_cast<uint32_t>(value);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700287 }
288
Yiwei Zhang8a4015c2018-05-08 16:03:47 -0700289 dump(asProto, maxLayers, result);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700290 }
291
292 if (argsMap.count("-clear")) {
Alec Mouri8e2f31b2020-01-16 22:04:35 +0000293 clearAll();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700294 }
295
296 if (argsMap.count("-enable")) {
297 enable();
298 }
299}
300
Yiwei Zhang7eb58b72019-04-22 19:00:02 -0700301std::string TimeStats::miniDump() {
302 ATRACE_CALL();
303
304 std::string result = "TimeStats miniDump:\n";
305 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhange926ab52019-08-14 15:16:00 -0700306 android::base::StringAppendF(&result, "Number of layers currently being tracked is %zu\n",
Yiwei Zhang7eb58b72019-04-22 19:00:02 -0700307 mTimeStatsTracker.size());
Yiwei Zhange926ab52019-08-14 15:16:00 -0700308 android::base::StringAppendF(&result, "Number of layers in the stats pool is %zu\n",
309 mTimeStats.stats.size());
Yiwei Zhang7eb58b72019-04-22 19:00:02 -0700310 return result;
311}
312
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700313void TimeStats::incrementTotalFrames() {
314 if (!mEnabled.load()) return;
315
316 ATRACE_CALL();
317
318 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800319 mTimeStats.totalFramesLegacy++;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700320}
321
Yiwei Zhang621f9d42018-05-07 10:40:55 -0700322void TimeStats::incrementMissedFrames() {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700323 if (!mEnabled.load()) return;
324
325 ATRACE_CALL();
326
327 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800328 mTimeStats.missedFramesLegacy++;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700329}
330
Vishnu Nair9cf89262022-02-26 09:17:49 -0800331void TimeStats::pushCompositionStrategyState(const TimeStats::ClientCompositionRecord& record) {
332 if (!mEnabled.load() || !record.hasInterestingData()) {
333 return;
334 }
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700335
336 ATRACE_CALL();
337
338 std::lock_guard<std::mutex> lock(mMutex);
Vishnu Nair9cf89262022-02-26 09:17:49 -0800339 if (record.changed) mTimeStats.compositionStrategyChangesLegacy++;
340 if (record.hadClientComposition) mTimeStats.clientCompositionFramesLegacy++;
341 if (record.reused) mTimeStats.clientCompositionReusedFramesLegacy++;
342 if (record.predicted) mTimeStats.compositionStrategyPredictedLegacy++;
343 if (record.predictionSucceeded) mTimeStats.compositionStrategyPredictionSucceededLegacy++;
Vishnu Nair9b079a22020-01-21 14:36:08 -0800344}
345
Alec Mouri8de697e2020-03-19 10:52:01 -0700346void TimeStats::incrementRefreshRateSwitches() {
347 if (!mEnabled.load()) return;
348
349 ATRACE_CALL();
350
351 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800352 mTimeStats.refreshRateSwitchesLegacy++;
Alec Mouri8de697e2020-03-19 10:52:01 -0700353}
354
Alec Mouri717bcb62020-02-10 17:07:19 -0800355void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
356 if (!mEnabled.load()) return;
357
358 ATRACE_CALL();
359
360 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800361 mTimeStats.displayEventConnectionsCountLegacy =
362 std::max(mTimeStats.displayEventConnectionsCountLegacy, count);
Alec Mouri717bcb62020-02-10 17:07:19 -0800363}
364
Ady Abraham3e8cc072021-05-11 16:29:54 -0700365static int32_t toMs(nsecs_t nanos) {
366 int64_t millis =
367 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::nanoseconds(nanos))
368 .count();
369 millis = std::clamp(millis, int64_t(INT32_MIN), int64_t(INT32_MAX));
370 return static_cast<int32_t>(millis);
371}
372
Alec Mouri9519bf12019-11-15 16:54:44 -0800373static int32_t msBetween(nsecs_t start, nsecs_t end) {
Ady Abraham3e8cc072021-05-11 16:29:54 -0700374 return toMs(end - start);
Alec Mouri9519bf12019-11-15 16:54:44 -0800375}
376
377void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) {
378 if (!mEnabled.load()) return;
379
380 std::lock_guard<std::mutex> lock(mMutex);
Peiyong Lin65248e02020-04-18 21:15:07 -0700381 if (mPowerTime.powerMode == PowerMode::ON) {
Alec Mouri7d436ec2021-01-27 20:40:50 -0800382 mTimeStats.frameDurationLegacy.insert(msBetween(startTime, endTime));
Alec Mouri9519bf12019-11-15 16:54:44 -0800383 }
384}
385
Alec Mourie4034bb2019-11-19 12:45:54 -0800386void TimeStats::recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) {
387 if (!mEnabled.load()) return;
388
389 std::lock_guard<std::mutex> lock(mMutex);
390 if (mGlobalRecord.renderEngineDurations.size() == MAX_NUM_TIME_RECORDS) {
391 ALOGE("RenderEngineTimes are already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
392 mGlobalRecord.renderEngineDurations.pop_front();
393 }
394 mGlobalRecord.renderEngineDurations.push_back({startTime, endTime});
395}
396
397void TimeStats::recordRenderEngineDuration(nsecs_t startTime,
398 const std::shared_ptr<FenceTime>& endTime) {
399 if (!mEnabled.load()) return;
400
401 std::lock_guard<std::mutex> lock(mMutex);
402 if (mGlobalRecord.renderEngineDurations.size() == MAX_NUM_TIME_RECORDS) {
403 ALOGE("RenderEngineTimes are already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
404 mGlobalRecord.renderEngineDurations.pop_front();
405 }
406 mGlobalRecord.renderEngineDurations.push_back({startTime, endTime});
407}
408
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800409bool TimeStats::recordReadyLocked(int32_t layerId, TimeRecord* timeRecord) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700410 if (!timeRecord->ready) {
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800411 ALOGV("[%d]-[%" PRIu64 "]-presentFence is still not received", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700412 timeRecord->frameTime.frameNumber);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700413 return false;
414 }
415
416 if (timeRecord->acquireFence != nullptr) {
417 if (timeRecord->acquireFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
418 return false;
419 }
420 if (timeRecord->acquireFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700421 timeRecord->frameTime.acquireTime = timeRecord->acquireFence->getSignalTime();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700422 timeRecord->acquireFence = nullptr;
423 } else {
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800424 ALOGV("[%d]-[%" PRIu64 "]-acquireFence signal time is invalid", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700425 timeRecord->frameTime.frameNumber);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700426 }
427 }
428
429 if (timeRecord->presentFence != nullptr) {
430 if (timeRecord->presentFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
431 return false;
432 }
433 if (timeRecord->presentFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700434 timeRecord->frameTime.presentTime = timeRecord->presentFence->getSignalTime();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700435 timeRecord->presentFence = nullptr;
436 } else {
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800437 ALOGV("[%d]-[%" PRIu64 "]-presentFence signal time invalid", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700438 timeRecord->frameTime.frameNumber);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700439 }
440 }
441
442 return true;
443}
444
Ady Abraham3403a3f2021-04-27 16:58:40 -0700445static int32_t clampToNearestBucket(Fps fps, size_t bucketWidth) {
446 return std::round(fps.getValue() / bucketWidth) * bucketWidth;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800447}
448
449void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
Ady Abraham8b9e6122021-01-26 19:11:45 -0800450 std::optional<Fps> renderRate,
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000451 SetFrameRateVote frameRateVote,
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700452 GameMode gameMode) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700453 ATRACE_CALL();
Ady Abraham8b9e6122021-01-26 19:11:45 -0800454 ALOGV("[%d]-flushAvailableRecordsToStatsLocked", layerId);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700455
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800456 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700457 TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
Alberto Gonzalez9fe14512022-09-29 21:27:34 +0000458 std::optional<int32_t>& prevPresentToPresentMs = layerRecord.prevPresentToPresentMs;
Yiwei Zhangc5f2c452018-05-08 16:31:56 -0700459 std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800460 const int32_t refreshRateBucket =
Ady Abraham3403a3f2021-04-27 16:58:40 -0700461 clampToNearestBucket(displayRefreshRate, REFRESH_RATE_BUCKET_WIDTH);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800462 const int32_t renderRateBucket =
Ady Abraham3403a3f2021-04-27 16:58:40 -0700463 clampToNearestBucket(renderRate ? *renderRate : displayRefreshRate,
464 RENDER_RATE_BUCKET_WIDTH);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700465 while (!timeRecords.empty()) {
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800466 if (!recordReadyLocked(layerId, &timeRecords[0])) break;
467 ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700468 timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700469
470 if (prevTimeRecord.ready) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700471 uid_t uid = layerRecord.uid;
Yiwei Zhangeafa5cc2019-07-26 15:06:25 -0700472 const std::string& layerName = layerRecord.layerName;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800473 TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
474 if (!mTimeStats.stats.count(timelineKey)) {
475 mTimeStats.stats[timelineKey].key = timelineKey;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700476 }
Alec Mouri7d436ec2021-01-27 20:40:50 -0800477
478 TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey];
479
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000480 TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName, gameMode};
Alec Mouri7d436ec2021-01-27 20:40:50 -0800481 if (!displayStats.stats.count(layerKey)) {
482 displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
483 displayStats.stats[layerKey].renderRateBucket = renderRateBucket;
484 displayStats.stats[layerKey].uid = uid;
485 displayStats.stats[layerKey].layerName = layerName;
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000486 displayStats.stats[layerKey].gameMode = gameMode;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800487 }
Ady Abraham8b9e6122021-01-26 19:11:45 -0800488 if (frameRateVote.frameRate > 0.0f) {
489 displayStats.stats[layerKey].setFrameRateVote = frameRateVote;
490 }
Alec Mouri7d436ec2021-01-27 20:40:50 -0800491 TimeStatsHelper::TimeStatsLayer& timeStatsLayer = displayStats.stats[layerKey];
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700492 timeStatsLayer.totalFrames++;
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700493 timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
Alec Mouri91f6df32020-01-30 08:48:58 -0800494 timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames;
495 timeStatsLayer.badDesiredPresentFrames += layerRecord.badDesiredPresentFrames;
496
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700497 layerRecord.droppedFrames = 0;
Alec Mouri91f6df32020-01-30 08:48:58 -0800498 layerRecord.lateAcquireFrames = 0;
499 layerRecord.badDesiredPresentFrames = 0;
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700500
501 const int32_t postToAcquireMs = msBetween(timeRecords[0].frameTime.postTime,
502 timeRecords[0].frameTime.acquireTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800503 ALOGV("[%d]-[%" PRIu64 "]-post2acquire[%d]", layerId,
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700504 timeRecords[0].frameTime.frameNumber, postToAcquireMs);
505 timeStatsLayer.deltas["post2acquire"].insert(postToAcquireMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700506
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700507 const int32_t postToPresentMs = msBetween(timeRecords[0].frameTime.postTime,
508 timeRecords[0].frameTime.presentTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800509 ALOGV("[%d]-[%" PRIu64 "]-post2present[%d]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700510 timeRecords[0].frameTime.frameNumber, postToPresentMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700511 timeStatsLayer.deltas["post2present"].insert(postToPresentMs);
512
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700513 const int32_t acquireToPresentMs = msBetween(timeRecords[0].frameTime.acquireTime,
514 timeRecords[0].frameTime.presentTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800515 ALOGV("[%d]-[%" PRIu64 "]-acquire2present[%d]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700516 timeRecords[0].frameTime.frameNumber, acquireToPresentMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700517 timeStatsLayer.deltas["acquire2present"].insert(acquireToPresentMs);
518
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700519 const int32_t latchToPresentMs = msBetween(timeRecords[0].frameTime.latchTime,
520 timeRecords[0].frameTime.presentTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800521 ALOGV("[%d]-[%" PRIu64 "]-latch2present[%d]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700522 timeRecords[0].frameTime.frameNumber, latchToPresentMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700523 timeStatsLayer.deltas["latch2present"].insert(latchToPresentMs);
524
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700525 const int32_t desiredToPresentMs = msBetween(timeRecords[0].frameTime.desiredTime,
526 timeRecords[0].frameTime.presentTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800527 ALOGV("[%d]-[%" PRIu64 "]-desired2present[%d]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700528 timeRecords[0].frameTime.frameNumber, desiredToPresentMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700529 timeStatsLayer.deltas["desired2present"].insert(desiredToPresentMs);
530
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700531 const int32_t presentToPresentMs = msBetween(prevTimeRecord.frameTime.presentTime,
532 timeRecords[0].frameTime.presentTime);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800533 ALOGV("[%d]-[%" PRIu64 "]-present2present[%d]", layerId,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700534 timeRecords[0].frameTime.frameNumber, presentToPresentMs);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700535 timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
Alberto Gonzalez9fe14512022-09-29 21:27:34 +0000536 if (prevPresentToPresentMs) {
537 const int32_t presentToPresentDeltaMs =
538 std::abs(presentToPresentMs - *prevPresentToPresentMs);
539 timeStatsLayer.deltas["present2presentDelta"].insert(presentToPresentDeltaMs);
540 }
541 prevPresentToPresentMs = presentToPresentMs;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700542 }
543 prevTimeRecord = timeRecords[0];
Yiwei Zhangc5f2c452018-05-08 16:31:56 -0700544 timeRecords.pop_front();
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700545 layerRecord.waitData--;
546 }
547}
548
Yiwei Zhang8bec7e82019-10-07 18:08:26 -0700549static constexpr const char* kPopupWindowPrefix = "PopupWindow";
550static const size_t kMinLenLayerName = std::strlen(kPopupWindowPrefix);
Yiwei Zhangbd408322018-10-15 18:31:53 -0700551
Yiwei Zhang8bec7e82019-10-07 18:08:26 -0700552// Avoid tracking the "PopupWindow:<random hash>#<number>" layers
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700553static bool layerNameIsValid(const std::string& layerName) {
Yiwei Zhang8bec7e82019-10-07 18:08:26 -0700554 return layerName.length() >= kMinLenLayerName &&
555 layerName.compare(0, kMinLenLayerName, kPopupWindowPrefix) != 0;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700556}
557
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000558bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName,
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700559 GameMode gameMode) {
Alec Mouri7d436ec2021-01-27 20:40:50 -0800560 uint32_t layerRecords = 0;
561 for (const auto& record : mTimeStats.stats) {
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000562 if (record.second.stats.count({uid, layerName, gameMode}) > 0) {
Alec Mouri7d436ec2021-01-27 20:40:50 -0800563 return true;
564 }
565
566 layerRecords += record.second.stats.size();
567 }
568
Dominik Laskowskib4ba8f52021-09-27 18:20:58 -0700569 return layerRecords < MAX_NUM_LAYER_STATS;
Alec Mouri9a29e672020-09-14 12:39:14 -0700570}
571
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800572void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700573 uid_t uid, nsecs_t postTime, GameMode gameMode) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700574 if (!mEnabled.load()) return;
575
576 ATRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800577 ALOGV("[%d]-[%" PRIu64 "]-[%s]-PostTime[%" PRId64 "]", layerId, frameNumber, layerName.c_str(),
Yiwei Zhang8e8fe522018-11-02 18:34:07 -0700578 postTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700579
580 std::lock_guard<std::mutex> lock(mMutex);
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000581 if (!canAddNewAggregatedStats(uid, layerName, gameMode)) {
Yiwei Zhange926ab52019-08-14 15:16:00 -0700582 return;
583 }
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800584 if (!mTimeStatsTracker.count(layerId) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS &&
Yiwei Zhang7eb58b72019-04-22 19:00:02 -0700585 layerNameIsValid(layerName)) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700586 mTimeStatsTracker[layerId].uid = uid;
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800587 mTimeStatsTracker[layerId].layerName = layerName;
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000588 mTimeStatsTracker[layerId].gameMode = gameMode;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700589 }
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800590 if (!mTimeStatsTracker.count(layerId)) return;
591 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700592 if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
Yiwei Zhangaf8ee942018-11-22 00:15:23 -0800593 ALOGE("[%d]-[%s]-timeRecords is at its maximum size[%zu]. Ignore this when unittesting.",
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800594 layerId, layerRecord.layerName.c_str(), MAX_NUM_TIME_RECORDS);
595 mTimeStatsTracker.erase(layerId);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700596 return;
597 }
598 // For most media content, the acquireFence is invalid because the buffer is
599 // ready at the queueBuffer stage. In this case, acquireTime should be given
600 // a default value as postTime.
601 TimeRecord timeRecord = {
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700602 .frameTime =
603 {
604 .frameNumber = frameNumber,
605 .postTime = postTime,
Yiwei Zhangaf8ee942018-11-22 00:15:23 -0800606 .latchTime = postTime,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700607 .acquireTime = postTime,
Yiwei Zhangaf8ee942018-11-22 00:15:23 -0800608 .desiredTime = postTime,
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700609 },
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700610 };
611 layerRecord.timeRecords.push_back(timeRecord);
612 if (layerRecord.waitData < 0 ||
613 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
614 layerRecord.waitData = layerRecord.timeRecords.size() - 1;
615}
616
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800617void TimeStats::setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700618 if (!mEnabled.load()) return;
619
620 ATRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800621 ALOGV("[%d]-[%" PRIu64 "]-LatchTime[%" PRId64 "]", layerId, frameNumber, latchTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700622
623 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800624 if (!mTimeStatsTracker.count(layerId)) return;
625 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700626 if (layerRecord.waitData < 0 ||
627 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
628 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700629 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700630 if (timeRecord.frameTime.frameNumber == frameNumber) {
631 timeRecord.frameTime.latchTime = latchTime;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700632 }
633}
634
Alec Mouri91f6df32020-01-30 08:48:58 -0800635void TimeStats::incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) {
636 if (!mEnabled.load()) return;
637
638 ATRACE_CALL();
639 ALOGV("[%d]-LatchSkipped-Reason[%d]", layerId,
640 static_cast<std::underlying_type<LatchSkipReason>::type>(reason));
641
642 std::lock_guard<std::mutex> lock(mMutex);
643 if (!mTimeStatsTracker.count(layerId)) return;
644 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
645
646 switch (reason) {
647 case LatchSkipReason::LateAcquire:
648 layerRecord.lateAcquireFrames++;
649 break;
650 }
651}
652
653void TimeStats::incrementBadDesiredPresent(int32_t layerId) {
654 if (!mEnabled.load()) return;
655
656 ATRACE_CALL();
657 ALOGV("[%d]-BadDesiredPresent", layerId);
658
659 std::lock_guard<std::mutex> lock(mMutex);
660 if (!mTimeStatsTracker.count(layerId)) return;
661 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
662 layerRecord.badDesiredPresentFrames++;
663}
664
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800665void TimeStats::setDesiredTime(int32_t layerId, uint64_t frameNumber, nsecs_t desiredTime) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700666 if (!mEnabled.load()) return;
667
668 ATRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800669 ALOGV("[%d]-[%" PRIu64 "]-DesiredTime[%" PRId64 "]", layerId, frameNumber, desiredTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700670
671 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800672 if (!mTimeStatsTracker.count(layerId)) return;
673 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700674 if (layerRecord.waitData < 0 ||
675 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
676 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700677 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700678 if (timeRecord.frameTime.frameNumber == frameNumber) {
679 timeRecord.frameTime.desiredTime = desiredTime;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700680 }
681}
682
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800683void TimeStats::setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700684 if (!mEnabled.load()) return;
685
686 ATRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800687 ALOGV("[%d]-[%" PRIu64 "]-AcquireTime[%" PRId64 "]", layerId, frameNumber, acquireTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700688
689 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800690 if (!mTimeStatsTracker.count(layerId)) return;
691 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700692 if (layerRecord.waitData < 0 ||
693 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
694 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700695 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700696 if (timeRecord.frameTime.frameNumber == frameNumber) {
697 timeRecord.frameTime.acquireTime = acquireTime;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700698 }
699}
700
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800701void TimeStats::setAcquireFence(int32_t layerId, uint64_t frameNumber,
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700702 const std::shared_ptr<FenceTime>& acquireFence) {
703 if (!mEnabled.load()) return;
704
705 ATRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800706 ALOGV("[%d]-[%" PRIu64 "]-AcquireFenceTime[%" PRId64 "]", layerId, frameNumber,
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700707 acquireFence->getSignalTime());
708
709 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800710 if (!mTimeStatsTracker.count(layerId)) return;
711 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700712 if (layerRecord.waitData < 0 ||
713 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
714 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700715 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700716 if (timeRecord.frameTime.frameNumber == frameNumber) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700717 timeRecord.acquireFence = acquireFence;
718 }
719}
720
Alec Mouri7d436ec2021-01-27 20:40:50 -0800721void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
Ady Abraham8b9e6122021-01-26 19:11:45 -0800722 Fps displayRefreshRate, std::optional<Fps> renderRate,
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700723 SetFrameRateVote frameRateVote, GameMode gameMode) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700724 if (!mEnabled.load()) return;
725
726 ATRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800727 ALOGV("[%d]-[%" PRIu64 "]-PresentTime[%" PRId64 "]", layerId, frameNumber, presentTime);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700728
729 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800730 if (!mTimeStatsTracker.count(layerId)) return;
731 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700732 if (layerRecord.waitData < 0 ||
733 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
734 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700735 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700736 if (timeRecord.frameTime.frameNumber == frameNumber) {
737 timeRecord.frameTime.presentTime = presentTime;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700738 timeRecord.ready = true;
739 layerRecord.waitData++;
740 }
741
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000742 flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote,
743 gameMode);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700744}
745
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800746void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
Alec Mouri7d436ec2021-01-27 20:40:50 -0800747 const std::shared_ptr<FenceTime>& presentFence,
Ady Abraham8b9e6122021-01-26 19:11:45 -0800748 Fps displayRefreshRate, std::optional<Fps> renderRate,
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700749 SetFrameRateVote frameRateVote, GameMode gameMode) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700750 if (!mEnabled.load()) return;
751
752 ATRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800753 ALOGV("[%d]-[%" PRIu64 "]-PresentFenceTime[%" PRId64 "]", layerId, frameNumber,
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700754 presentFence->getSignalTime());
755
756 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800757 if (!mTimeStatsTracker.count(layerId)) return;
758 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhangcb7dd002019-04-16 11:03:01 -0700759 if (layerRecord.waitData < 0 ||
760 layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
761 return;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700762 TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700763 if (timeRecord.frameTime.frameNumber == frameNumber) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700764 timeRecord.presentFence = presentFence;
765 timeRecord.ready = true;
766 layerRecord.waitData++;
767 }
768
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000769 flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote,
770 gameMode);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700771}
772
Adithya Srinivasanead17162021-02-18 02:17:37 +0000773static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL |
774 JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed |
775 JankType::AppDeadlineMissed | JankType::PredictionError |
Adithya Srinivasan53e5c402021-04-16 17:34:30 +0000776 JankType::SurfaceFlingerScheduling;
Alec Mouri363faf02021-01-29 16:34:55 -0800777
Alec Mouri9a29e672020-09-14 12:39:14 -0700778template <class T>
779static void updateJankPayload(T& t, int32_t reasons) {
780 t.jankPayload.totalFrames++;
781
Alec Mouri9a29e672020-09-14 12:39:14 -0700782 if (reasons & kValidJankyReason) {
783 t.jankPayload.totalJankyFrames++;
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800784 if ((reasons & JankType::SurfaceFlingerCpuDeadlineMissed) != 0) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700785 t.jankPayload.totalSFLongCpu++;
786 }
Jorim Jaggi5814ab82020-12-03 20:45:58 +0100787 if ((reasons & JankType::SurfaceFlingerGpuDeadlineMissed) != 0) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700788 t.jankPayload.totalSFLongGpu++;
789 }
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800790 if ((reasons & JankType::DisplayHAL) != 0) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700791 t.jankPayload.totalSFUnattributed++;
792 }
Jorim Jaggi5814ab82020-12-03 20:45:58 +0100793 if ((reasons & JankType::AppDeadlineMissed) != 0) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700794 t.jankPayload.totalAppUnattributed++;
795 }
Adithya Srinivasanead17162021-02-18 02:17:37 +0000796 if ((reasons & JankType::PredictionError) != 0) {
797 t.jankPayload.totalSFPredictionError++;
798 }
799 if ((reasons & JankType::SurfaceFlingerScheduling) != 0) {
800 t.jankPayload.totalSFScheduling++;
801 }
Adithya Srinivasan53e5c402021-04-16 17:34:30 +0000802 }
803
804 // We want to track BufferStuffing separately as it can provide info on latency issues
805 if (reasons & JankType::BufferStuffing) {
806 t.jankPayload.totalAppBufferStuffing++;
Alec Mouri9a29e672020-09-14 12:39:14 -0700807 }
808}
809
Alec Mouri363faf02021-01-29 16:34:55 -0800810void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) {
Alec Mouri9a29e672020-09-14 12:39:14 -0700811 if (!mEnabled.load()) return;
812
813 ATRACE_CALL();
814 std::lock_guard<std::mutex> lock(mMutex);
815
Alec Mouri542de112020-11-13 12:07:32 -0800816 // Only update layer stats if we're already tracking the layer in TimeStats.
817 // Otherwise, continue tracking the statistic but use a default layer name instead.
Alec Mouri9a29e672020-09-14 12:39:14 -0700818 // As an implementation detail, we do this because this method is expected to be
Alec Mouri542de112020-11-13 12:07:32 -0800819 // called from FrameTimeline, whose jank classification includes transaction jank
820 // that occurs without a buffer. But, in general those layer names are not suitable as
821 // aggregation keys: e.g., it's normal and expected for Window Manager to include the hash code
822 // for an animation leash. So while we can show that jank in dumpsys, aggregating based on the
823 // layer blows up the stats size, so as a workaround drop those stats. This assumes that
824 // TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that
825 // the first jank record is not dropped.
Alec Mouri9a29e672020-09-14 12:39:14 -0700826
Alec Mouri542de112020-11-13 12:07:32 -0800827 static const std::string kDefaultLayerName = "none";
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700828 constexpr GameMode kDefaultGameMode = GameMode::Unsupported;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800829
Alec Mouri363faf02021-01-29 16:34:55 -0800830 const int32_t refreshRateBucket =
Ady Abraham3403a3f2021-04-27 16:58:40 -0700831 clampToNearestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800832 const int32_t renderRateBucket =
Ady Abraham3403a3f2021-04-27 16:58:40 -0700833 clampToNearestBucket(info.renderRate ? *info.renderRate : info.refreshRate,
834 RENDER_RATE_BUCKET_WIDTH);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800835 const TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
836
837 if (!mTimeStats.stats.count(timelineKey)) {
838 mTimeStats.stats[timelineKey].key = timelineKey;
Alec Mouri9a29e672020-09-14 12:39:14 -0700839 }
840
Alec Mouri7d436ec2021-01-27 20:40:50 -0800841 TimeStatsHelper::TimelineStats& timelineStats = mTimeStats.stats[timelineKey];
842
Alec Mouri363faf02021-01-29 16:34:55 -0800843 updateJankPayload<TimeStatsHelper::TimelineStats>(timelineStats, info.reasons);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800844
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000845 TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName, info.gameMode};
Alec Mouri7d436ec2021-01-27 20:40:50 -0800846 if (!timelineStats.stats.count(layerKey)) {
Adithya Srinivasan58069dc2021-06-04 20:37:02 +0000847 layerKey = {info.uid, kDefaultLayerName, kDefaultGameMode};
Alec Mouri7d436ec2021-01-27 20:40:50 -0800848 timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
849 timelineStats.stats[layerKey].renderRateBucket = renderRateBucket;
Alec Mouri363faf02021-01-29 16:34:55 -0800850 timelineStats.stats[layerKey].uid = info.uid;
Adithya Srinivasanf427f762021-06-15 19:46:26 +0000851 timelineStats.stats[layerKey].layerName = kDefaultLayerName;
852 timelineStats.stats[layerKey].gameMode = kDefaultGameMode;
Alec Mouri7d436ec2021-01-27 20:40:50 -0800853 }
854
855 TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey];
Alec Mouri363faf02021-01-29 16:34:55 -0800856 updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, info.reasons);
857
858 if (info.reasons & kValidJankyReason) {
859 // TimeStats Histograms only retain positive values, so we don't need to check if these
860 // deadlines were really missed if we know that the frame had jank, since deadlines
861 // that were met will be dropped.
Ady Abraham3e8cc072021-05-11 16:29:54 -0700862 timelineStats.displayDeadlineDeltas.insert(toMs(info.displayDeadlineDelta));
863 timelineStats.displayPresentDeltas.insert(toMs(info.displayPresentJitter));
864 timeStatsLayer.deltas["appDeadlineDeltas"].insert(toMs(info.appDeadlineDelta));
Alec Mouri363faf02021-01-29 16:34:55 -0800865 }
Alec Mouri9a29e672020-09-14 12:39:14 -0700866}
867
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800868void TimeStats::onDestroy(int32_t layerId) {
Yiwei Zhangdc224042018-10-18 15:34:00 -0700869 ATRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800870 ALOGV("[%d]-onDestroy", layerId);
Mikael Pessa90092f42019-08-26 17:22:04 -0700871 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800872 mTimeStatsTracker.erase(layerId);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700873}
874
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800875void TimeStats::removeTimeRecord(int32_t layerId, uint64_t frameNumber) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700876 if (!mEnabled.load()) return;
877
878 ATRACE_CALL();
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800879 ALOGV("[%d]-[%" PRIu64 "]-removeTimeRecord", layerId, frameNumber);
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700880
881 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang1a88c402019-11-18 10:43:58 -0800882 if (!mTimeStatsTracker.count(layerId)) return;
883 LayerRecord& layerRecord = mTimeStatsTracker[layerId];
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700884 size_t removeAt = 0;
885 for (const TimeRecord& record : layerRecord.timeRecords) {
Yiwei Zhangcf50ab92018-06-14 10:50:12 -0700886 if (record.frameTime.frameNumber == frameNumber) break;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700887 removeAt++;
888 }
889 if (removeAt == layerRecord.timeRecords.size()) return;
890 layerRecord.timeRecords.erase(layerRecord.timeRecords.begin() + removeAt);
891 if (layerRecord.waitData > static_cast<int32_t>(removeAt)) {
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700892 layerRecord.waitData--;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700893 }
Yiwei Zhangeaeea062018-06-28 14:46:51 -0700894 layerRecord.droppedFrames++;
Yiwei Zhang0102ad22018-05-02 17:37:17 -0700895}
896
Yiwei Zhang3a226d22018-10-16 09:23:03 -0700897void TimeStats::flushPowerTimeLocked() {
Yiwei Zhange5c49d52018-10-29 00:15:31 -0700898 if (!mEnabled.load()) return;
899
Yiwei Zhang3a226d22018-10-16 09:23:03 -0700900 nsecs_t curTime = systemTime();
901 // elapsedTime is in milliseconds.
902 int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
903
904 switch (mPowerTime.powerMode) {
Peiyong Lin65248e02020-04-18 21:15:07 -0700905 case PowerMode::ON:
Alec Mouri7d436ec2021-01-27 20:40:50 -0800906 mTimeStats.displayOnTimeLegacy += elapsedTime;
Yiwei Zhang3a226d22018-10-16 09:23:03 -0700907 break;
Peiyong Lin65248e02020-04-18 21:15:07 -0700908 case PowerMode::OFF:
909 case PowerMode::DOZE:
910 case PowerMode::DOZE_SUSPEND:
911 case PowerMode::ON_SUSPEND:
Yiwei Zhang3a226d22018-10-16 09:23:03 -0700912 default:
913 break;
914 }
915
916 mPowerTime.prevTime = curTime;
917}
918
Peiyong Lin65248e02020-04-18 21:15:07 -0700919void TimeStats::setPowerMode(PowerMode powerMode) {
Yiwei Zhang3a226d22018-10-16 09:23:03 -0700920 if (!mEnabled.load()) {
921 std::lock_guard<std::mutex> lock(mMutex);
922 mPowerTime.powerMode = powerMode;
923 return;
924 }
925
926 std::lock_guard<std::mutex> lock(mMutex);
927 if (powerMode == mPowerTime.powerMode) return;
928
929 flushPowerTimeLocked();
930 mPowerTime.powerMode = powerMode;
931}
932
Alec Mourifb571ea2019-01-24 18:42:10 -0800933void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
934 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800935 if (mTimeStats.refreshRateStatsLegacy.count(fps)) {
936 mTimeStats.refreshRateStatsLegacy[fps] += duration;
Alec Mourifb571ea2019-01-24 18:42:10 -0800937 } else {
Alec Mouri7d436ec2021-01-27 20:40:50 -0800938 mTimeStats.refreshRateStatsLegacy.insert({fps, duration});
Alec Mourifb571ea2019-01-24 18:42:10 -0800939 }
940}
941
Yiwei Zhangce6ebc02018-10-20 12:42:38 -0700942void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
943 ATRACE_CALL();
944
945 while (!mGlobalRecord.presentFences.empty()) {
946 const nsecs_t curPresentTime = mGlobalRecord.presentFences.front()->getSignalTime();
947 if (curPresentTime == Fence::SIGNAL_TIME_PENDING) break;
948
949 if (curPresentTime == Fence::SIGNAL_TIME_INVALID) {
950 ALOGE("GlobalPresentFence is invalid!");
951 mGlobalRecord.prevPresentTime = 0;
952 mGlobalRecord.presentFences.pop_front();
953 continue;
954 }
955
956 ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
957 mGlobalRecord.presentFences.front()->getSignalTime());
958
Yiwei Zhange5c49d52018-10-29 00:15:31 -0700959 if (mGlobalRecord.prevPresentTime != 0) {
960 const int32_t presentToPresentMs =
961 msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
962 ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
963 presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800964 mTimeStats.presentToPresentLegacy.insert(presentToPresentMs);
Yiwei Zhange5c49d52018-10-29 00:15:31 -0700965 }
Yiwei Zhangce6ebc02018-10-20 12:42:38 -0700966
Yiwei Zhangce6ebc02018-10-20 12:42:38 -0700967 mGlobalRecord.prevPresentTime = curPresentTime;
968 mGlobalRecord.presentFences.pop_front();
969 }
Alec Mourie4034bb2019-11-19 12:45:54 -0800970 while (!mGlobalRecord.renderEngineDurations.empty()) {
971 const auto duration = mGlobalRecord.renderEngineDurations.front();
972 const auto& endTime = duration.endTime;
973
974 nsecs_t endNs = -1;
975
976 if (auto val = std::get_if<nsecs_t>(&endTime)) {
977 endNs = *val;
978 } else {
979 endNs = std::get<std::shared_ptr<FenceTime>>(endTime)->getSignalTime();
980 }
981
982 if (endNs == Fence::SIGNAL_TIME_PENDING) break;
983
984 if (endNs < 0) {
985 ALOGE("RenderEngineTiming is invalid!");
986 mGlobalRecord.renderEngineDurations.pop_front();
987 continue;
988 }
989
990 const int32_t renderEngineMs = msBetween(duration.startTime, endNs);
Alec Mouri7d436ec2021-01-27 20:40:50 -0800991 mTimeStats.renderEngineTimingLegacy.insert(renderEngineMs);
Alec Mourie4034bb2019-11-19 12:45:54 -0800992
993 mGlobalRecord.renderEngineDurations.pop_front();
994 }
Yiwei Zhangce6ebc02018-10-20 12:42:38 -0700995}
996
997void TimeStats::setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) {
998 if (!mEnabled.load()) return;
999
1000 ATRACE_CALL();
1001 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001002 if (presentFence == nullptr || !presentFence->isValid()) {
1003 mGlobalRecord.prevPresentTime = 0;
1004 return;
1005 }
1006
Peiyong Lin65248e02020-04-18 21:15:07 -07001007 if (mPowerTime.powerMode != PowerMode::ON) {
1008 // Try flushing the last present fence on PowerMode::ON.
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001009 flushAvailableGlobalRecordsToStatsLocked();
1010 mGlobalRecord.presentFences.clear();
Yiwei Zhangce6ebc02018-10-20 12:42:38 -07001011 mGlobalRecord.prevPresentTime = 0;
1012 return;
1013 }
1014
1015 if (mGlobalRecord.presentFences.size() == MAX_NUM_TIME_RECORDS) {
1016 // The front presentFence must be trapped in pending status in this
1017 // case. Try dequeuing the front one to recover.
1018 ALOGE("GlobalPresentFences is already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
1019 mGlobalRecord.prevPresentTime = 0;
1020 mGlobalRecord.presentFences.pop_front();
1021 }
1022
1023 mGlobalRecord.presentFences.emplace_back(presentFence);
1024 flushAvailableGlobalRecordsToStatsLocked();
1025}
1026
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001027void TimeStats::enable() {
1028 if (mEnabled.load()) return;
1029
1030 ATRACE_CALL();
1031
1032 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001033 mEnabled.store(true);
Alec Mouri7d436ec2021-01-27 20:40:50 -08001034 mTimeStats.statsStartLegacy = static_cast<int64_t>(std::time(0));
Yiwei Zhang3a226d22018-10-16 09:23:03 -07001035 mPowerTime.prevTime = systemTime();
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001036 ALOGD("Enabled");
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001037}
1038
1039void TimeStats::disable() {
1040 if (!mEnabled.load()) return;
1041
1042 ATRACE_CALL();
1043
1044 std::lock_guard<std::mutex> lock(mMutex);
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001045 flushPowerTimeLocked();
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001046 mEnabled.store(false);
Alec Mouri7d436ec2021-01-27 20:40:50 -08001047 mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001048 ALOGD("Disabled");
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001049}
1050
Alec Mouri8e2f31b2020-01-16 22:04:35 +00001051void TimeStats::clearAll() {
1052 std::lock_guard<std::mutex> lock(mMutex);
Ady Abraham3403a3f2021-04-27 16:58:40 -07001053 mTimeStats.stats.clear();
Alec Mouri8e2f31b2020-01-16 22:04:35 +00001054 clearGlobalLocked();
1055 clearLayersLocked();
1056}
1057
1058void TimeStats::clearGlobalLocked() {
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001059 ATRACE_CALL();
1060
Alec Mouri7d436ec2021-01-27 20:40:50 -08001061 mTimeStats.statsStartLegacy = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
1062 mTimeStats.statsEndLegacy = 0;
1063 mTimeStats.totalFramesLegacy = 0;
1064 mTimeStats.missedFramesLegacy = 0;
1065 mTimeStats.clientCompositionFramesLegacy = 0;
1066 mTimeStats.clientCompositionReusedFramesLegacy = 0;
Robert Carra00eb142022-03-09 13:49:30 -08001067 mTimeStats.compositionStrategyChangesLegacy = 0;
Vishnu Nair9cf89262022-02-26 09:17:49 -08001068 mTimeStats.compositionStrategyPredictedLegacy = 0;
1069 mTimeStats.compositionStrategyPredictionSucceededLegacy = 0;
1070 mTimeStats.refreshRateSwitchesLegacy = 0;
Alec Mouri7d436ec2021-01-27 20:40:50 -08001071 mTimeStats.displayEventConnectionsCountLegacy = 0;
1072 mTimeStats.displayOnTimeLegacy = 0;
1073 mTimeStats.presentToPresentLegacy.hist.clear();
1074 mTimeStats.frameDurationLegacy.hist.clear();
1075 mTimeStats.renderEngineTimingLegacy.hist.clear();
1076 mTimeStats.refreshRateStatsLegacy.clear();
Yiwei Zhang3a226d22018-10-16 09:23:03 -07001077 mPowerTime.prevTime = systemTime();
Alec Mouri56e63852021-03-09 18:17:25 -08001078 for (auto& globalRecord : mTimeStats.stats) {
1079 globalRecord.second.clearGlobals();
1080 }
Yiwei Zhange5c49d52018-10-29 00:15:31 -07001081 mGlobalRecord.prevPresentTime = 0;
1082 mGlobalRecord.presentFences.clear();
Alec Mouri8e2f31b2020-01-16 22:04:35 +00001083 ALOGD("Cleared global stats");
1084}
1085
1086void TimeStats::clearLayersLocked() {
1087 ATRACE_CALL();
1088
1089 mTimeStatsTracker.clear();
Alec Mouri56e63852021-03-09 18:17:25 -08001090
1091 for (auto& globalRecord : mTimeStats.stats) {
1092 globalRecord.second.stats.clear();
1093 }
Alec Mouri8e2f31b2020-01-16 22:04:35 +00001094 ALOGD("Cleared layer stats");
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001095}
1096
1097bool TimeStats::isEnabled() {
1098 return mEnabled.load();
1099}
1100
Yiwei Zhang5434a782018-12-05 18:06:32 -08001101void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001102 ATRACE_CALL();
1103
1104 std::lock_guard<std::mutex> lock(mMutex);
Alec Mouri7d436ec2021-01-27 20:40:50 -08001105 if (mTimeStats.statsStartLegacy == 0) {
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001106 return;
1107 }
1108
Alec Mouri7d436ec2021-01-27 20:40:50 -08001109 mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001110
Yiwei Zhang3a226d22018-10-16 09:23:03 -07001111 flushPowerTimeLocked();
1112
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001113 if (asProto) {
Yiwei Zhang8a4015c2018-05-08 16:03:47 -07001114 ALOGD("Dumping TimeStats as proto");
Yiwei Zhangdc224042018-10-18 15:34:00 -07001115 SFTimeStatsGlobalProto timeStatsProto = mTimeStats.toProto(maxLayers);
Dominik Laskowski46470112019-08-02 13:13:11 -07001116 result.append(timeStatsProto.SerializeAsString());
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001117 } else {
Yiwei Zhang8a4015c2018-05-08 16:03:47 -07001118 ALOGD("Dumping TimeStats as text");
Yiwei Zhang5434a782018-12-05 18:06:32 -08001119 result.append(mTimeStats.toString(maxLayers));
Yiwei Zhang8a4015c2018-05-08 16:03:47 -07001120 result.append("\n");
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001121 }
1122}
1123
Alec Mourifb571ea2019-01-24 18:42:10 -08001124} // namespace impl
1125
Yiwei Zhang0102ad22018-05-02 17:37:17 -07001126} // namespace android