blob: a8fef04863db260a894554b7bcfddcc0e4924438 [file] [log] [blame]
Adithya Srinivasanf279e042020-08-17 14:56:27 -07001/*
2 * Copyright 2020 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 */
16
17#undef LOG_TAG
18#define LOG_TAG "FrameTimeline"
19#define ATRACE_TAG ATRACE_TAG_GRAPHICS
20
21#include "FrameTimeline.h"
22#include <android-base/stringprintf.h>
Ady Abraham7f8a1e62020-09-28 16:09:35 -070023#include <utils/Log.h>
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -070024#include <utils/Trace.h>
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -070025#include <chrono>
Adithya Srinivasanf279e042020-08-17 14:56:27 -070026#include <cinttypes>
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -070027#include <numeric>
Adithya Srinivasanf279e042020-08-17 14:56:27 -070028
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -080029namespace android::frametimeline {
Adithya Srinivasanf279e042020-08-17 14:56:27 -070030
31using base::StringAppendF;
Adithya Srinivasan01189672020-10-20 14:23:05 -070032using FrameTimelineEvent = perfetto::protos::pbzero::FrameTimelineEvent;
Adithya Srinivasanf279e042020-08-17 14:56:27 -070033
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -070034void dumpTable(std::string& result, TimelineItem predictions, TimelineItem actuals,
35 const std::string& indent, PredictionState predictionState, nsecs_t baseTime) {
36 StringAppendF(&result, "%s", indent.c_str());
37 StringAppendF(&result, "\t\t");
38 StringAppendF(&result, " Start time\t\t|");
39 StringAppendF(&result, " End time\t\t|");
40 StringAppendF(&result, " Present time\n");
41 if (predictionState == PredictionState::Valid) {
42 // Dump the Predictions only if they are valid
43 StringAppendF(&result, "%s", indent.c_str());
44 StringAppendF(&result, "Expected\t|");
45 std::chrono::nanoseconds startTime(predictions.startTime - baseTime);
46 std::chrono::nanoseconds endTime(predictions.endTime - baseTime);
47 std::chrono::nanoseconds presentTime(predictions.presentTime - baseTime);
48 StringAppendF(&result, "\t%10.2f\t|\t%10.2f\t|\t%10.2f\n",
49 std::chrono::duration<double, std::milli>(startTime).count(),
50 std::chrono::duration<double, std::milli>(endTime).count(),
51 std::chrono::duration<double, std::milli>(presentTime).count());
52 }
53 StringAppendF(&result, "%s", indent.c_str());
54 StringAppendF(&result, "Actual \t|");
55
56 if (actuals.startTime == 0) {
57 StringAppendF(&result, "\t\tN/A\t|");
58 } else {
59 std::chrono::nanoseconds startTime(std::max<nsecs_t>(0, actuals.startTime - baseTime));
60 StringAppendF(&result, "\t%10.2f\t|",
61 std::chrono::duration<double, std::milli>(startTime).count());
62 }
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -080063 if (actuals.endTime <= 0) {
64 // Animation leashes can send the endTime as -1
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -070065 StringAppendF(&result, "\t\tN/A\t|");
66 } else {
67 std::chrono::nanoseconds endTime(actuals.endTime - baseTime);
68 StringAppendF(&result, "\t%10.2f\t|",
69 std::chrono::duration<double, std::milli>(endTime).count());
70 }
71 if (actuals.presentTime == 0) {
72 StringAppendF(&result, "\t\tN/A\n");
73 } else {
74 std::chrono::nanoseconds presentTime(std::max<nsecs_t>(0, actuals.presentTime - baseTime));
75 StringAppendF(&result, "\t%10.2f\n",
76 std::chrono::duration<double, std::milli>(presentTime).count());
77 }
78
79 StringAppendF(&result, "%s", indent.c_str());
80 StringAppendF(&result, "----------------------");
81 StringAppendF(&result, "----------------------");
82 StringAppendF(&result, "----------------------");
83 StringAppendF(&result, "----------------------\n");
84}
85
86std::string toString(PredictionState predictionState) {
87 switch (predictionState) {
88 case PredictionState::Valid:
89 return "Valid";
90 case PredictionState::Expired:
91 return "Expired";
92 case PredictionState::None:
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -070093 return "None";
94 }
95}
96
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -080097std::string jankTypeBitmaskToString(int32_t jankType) {
98 // TODO(b/175843808): Make this a switch case if jankType becomes an enum class
99 std::vector<std::string> janks;
100 if (jankType == JankType::None) {
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700101 return "None";
102 }
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800103 if (jankType & JankType::DisplayHAL) {
104 janks.emplace_back("Display HAL");
105 }
106 if (jankType & JankType::SurfaceFlingerCpuDeadlineMissed) {
107 janks.emplace_back("SurfaceFlinger CPU Deadline Missed");
108 }
109 if (jankType & JankType::SurfaceFlingerGpuDeadlineMissed) {
110 janks.emplace_back("SurfaceFlinger GPU Deadline Missed");
111 }
112 if (jankType & JankType::AppDeadlineMissed) {
113 janks.emplace_back("App Deadline Missed");
114 }
115 if (jankType & JankType::PredictionError) {
116 janks.emplace_back("Prediction Error");
117 }
118 if (jankType & JankType::SurfaceFlingerScheduling) {
119 janks.emplace_back("SurfaceFlinger Scheduling");
120 }
121 if (jankType & JankType::BufferStuffing) {
122 janks.emplace_back("Buffer Stuffing");
123 }
124 if (jankType & JankType::Unknown) {
125 janks.emplace_back("Unknown jank");
126 }
127 return std::accumulate(janks.begin(), janks.end(), std::string(),
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700128 [](const std::string& l, const std::string& r) {
129 return l.empty() ? r : l + ", " + r;
130 });
131}
132
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800133std::string toString(FramePresentMetadata presentMetadata) {
134 switch (presentMetadata) {
135 case FramePresentMetadata::OnTimePresent:
136 return "On Time Present";
137 case FramePresentMetadata::LatePresent:
138 return "Late Present";
139 case FramePresentMetadata::EarlyPresent:
140 return "Early Present";
141 case FramePresentMetadata::UnknownPresent:
142 return "Unknown Present";
Adithya Srinivasan01189672020-10-20 14:23:05 -0700143 }
Adithya Srinivasan01189672020-10-20 14:23:05 -0700144}
145
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800146std::string toString(FrameReadyMetadata finishMetadata) {
147 switch (finishMetadata) {
148 case FrameReadyMetadata::OnTimeFinish:
149 return "On Time Finish";
150 case FrameReadyMetadata::LateFinish:
151 return "Late Finish";
152 case FrameReadyMetadata::UnknownFinish:
153 return "Unknown Finish";
154 }
155}
156
157std::string toString(FrameStartMetadata startMetadata) {
158 switch (startMetadata) {
159 case FrameStartMetadata::OnTimeStart:
160 return "On Time Start";
161 case FrameStartMetadata::LateStart:
162 return "Late Start";
163 case FrameStartMetadata::EarlyStart:
164 return "Early Start";
165 case FrameStartMetadata::UnknownStart:
166 return "Unknown Start";
167 }
168}
169
170std::string toString(SurfaceFrame::PresentState presentState) {
171 using PresentState = SurfaceFrame::PresentState;
172 switch (presentState) {
173 case PresentState::Presented:
174 return "Presented";
175 case PresentState::Dropped:
176 return "Dropped";
177 case PresentState::Unknown:
178 return "Unknown";
179 }
180}
181
182FrameTimelineEvent::PresentType toProto(FramePresentMetadata presentMetadata) {
183 switch (presentMetadata) {
184 case FramePresentMetadata::EarlyPresent:
185 return FrameTimelineEvent::PRESENT_EARLY;
186 case FramePresentMetadata::LatePresent:
187 return FrameTimelineEvent::PRESENT_LATE;
188 case FramePresentMetadata::OnTimePresent:
189 return FrameTimelineEvent::PRESENT_ON_TIME;
190 case FramePresentMetadata::UnknownPresent:
191 return FrameTimelineEvent::PRESENT_UNSPECIFIED;
192 }
193}
194
195FrameTimelineEvent::JankType jankTypeBitmaskToProto(int32_t jankType) {
196 // TODO(b/175843808): Either make the proto a bitmask or jankType an enum class
Adithya Srinivasan01189672020-10-20 14:23:05 -0700197 switch (jankType) {
Jorim Jaggi5814ab82020-12-03 20:45:58 +0100198 case JankType::None:
Adithya Srinivasan01189672020-10-20 14:23:05 -0700199 return FrameTimelineEvent::JANK_NONE;
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800200 case JankType::DisplayHAL:
Adithya Srinivasan01189672020-10-20 14:23:05 -0700201 return FrameTimelineEvent::JANK_DISPLAY_HAL;
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800202 case JankType::SurfaceFlingerCpuDeadlineMissed:
203 case JankType::SurfaceFlingerGpuDeadlineMissed:
Adithya Srinivasan01189672020-10-20 14:23:05 -0700204 return FrameTimelineEvent::JANK_SF_DEADLINE_MISSED;
Jorim Jaggi5814ab82020-12-03 20:45:58 +0100205 case JankType::AppDeadlineMissed:
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800206 case JankType::PredictionError:
Adithya Srinivasan01189672020-10-20 14:23:05 -0700207 return FrameTimelineEvent::JANK_APP_DEADLINE_MISSED;
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800208 case JankType::SurfaceFlingerScheduling:
209 return FrameTimelineEvent::JANK_SF_SCHEDULING;
210 case JankType::BufferStuffing:
211 return FrameTimelineEvent::JANK_BUFFER_STUFFING;
Adithya Srinivasan01189672020-10-20 14:23:05 -0700212 default:
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800213 // TODO(b/175843808): Remove default if JankType becomes an enum class
Adithya Srinivasan01189672020-10-20 14:23:05 -0700214 return FrameTimelineEvent::JANK_UNKNOWN;
215 }
216}
217
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800218// Returns the smallest timestamp from the set of predictions and actuals.
219nsecs_t getMinTime(PredictionState predictionState, TimelineItem predictions,
220 TimelineItem actuals) {
221 nsecs_t minTime = std::numeric_limits<nsecs_t>::max();
222 if (predictionState == PredictionState::Valid) {
223 // Checking start time for predictions is enough because start time is always lesser than
224 // endTime and presentTime.
225 minTime = std::min(minTime, predictions.startTime);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700226 }
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700227
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800228 // Need to check startTime, endTime and presentTime for actuals because some frames might not
229 // have them set.
230 if (actuals.startTime != 0) {
231 minTime = std::min(minTime, actuals.startTime);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700232 }
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800233 if (actuals.endTime != 0) {
234 minTime = std::min(minTime, actuals.endTime);
235 }
236 if (actuals.presentTime != 0) {
237 minTime = std::min(minTime, actuals.endTime);
238 }
239 return minTime;
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700240}
241
Adithya Srinivasan01189672020-10-20 14:23:05 -0700242SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName,
Adithya Srinivasan9febda82020-10-19 10:49:41 -0700243 std::string debugName, PredictionState predictionState,
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800244 frametimeline::TimelineItem&& predictions,
245 std::shared_ptr<TimeStats> timeStats,
246 JankClassificationThresholds thresholds)
Adithya Srinivasan01189672020-10-20 14:23:05 -0700247 : mToken(token),
248 mOwnerPid(ownerPid),
Adithya Srinivasan9febda82020-10-19 10:49:41 -0700249 mOwnerUid(ownerUid),
Alec Mouri9a29e672020-09-14 12:39:14 -0700250 mLayerName(std::move(layerName)),
251 mDebugName(std::move(debugName)),
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700252 mPresentState(PresentState::Unknown),
253 mPredictionState(predictionState),
254 mPredictions(predictions),
255 mActuals({0, 0, 0}),
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800256 mTimeStats(timeStats),
257 mJankClassificationThresholds(thresholds) {}
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700258
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700259void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) {
260 std::lock_guard<std::mutex> lock(mMutex);
261 mActuals.startTime = actualStartTime;
262}
263
264void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) {
265 std::lock_guard<std::mutex> lock(mMutex);
266 mActualQueueTime = actualQueueTime;
267}
Ady Abraham7f8a1e62020-09-28 16:09:35 -0700268void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700269 std::lock_guard<std::mutex> lock(mMutex);
Ady Abraham7f8a1e62020-09-28 16:09:35 -0700270 mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700271}
272
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800273void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700274 std::lock_guard<std::mutex> lock(mMutex);
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800275 mPresentState = presentState;
276 mLastLatchTime = lastLatchTime;
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700277}
278
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800279std::optional<int32_t> SurfaceFrame::getJankType() const {
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700280 std::lock_guard<std::mutex> lock(mMutex);
Jorim Jaggi9c03b502020-11-24 23:51:31 +0100281 if (mActuals.presentTime == 0) {
282 return std::nullopt;
283 }
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700284 return mJankType;
285}
286
287nsecs_t SurfaceFrame::getBaseTime() const {
288 std::lock_guard<std::mutex> lock(mMutex);
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800289 return getMinTime(mPredictionState, mPredictions, mActuals);
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700290}
291
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800292TimelineItem SurfaceFrame::getActuals() const {
293 std::lock_guard<std::mutex> lock(mMutex);
294 return mActuals;
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700295}
296
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800297SurfaceFrame::PresentState SurfaceFrame::getPresentState() const {
298 std::lock_guard<std::mutex> lock(mMutex);
299 return mPresentState;
300}
301
302FramePresentMetadata SurfaceFrame::getFramePresentMetadata() const {
303 std::lock_guard<std::mutex> lock(mMutex);
304 return mFramePresentMetadata;
305}
306
307FrameReadyMetadata SurfaceFrame::getFrameReadyMetadata() const {
308 std::lock_guard<std::mutex> lock(mMutex);
309 return mFrameReadyMetadata;
310}
311
312void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const {
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700313 std::lock_guard<std::mutex> lock(mMutex);
314 StringAppendF(&result, "%s", indent.c_str());
Alec Mouri9a29e672020-09-14 12:39:14 -0700315 StringAppendF(&result, "Layer - %s", mDebugName.c_str());
Jorim Jaggi5814ab82020-12-03 20:45:58 +0100316 if (mJankType != JankType::None) {
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700317 // Easily identify a janky Surface Frame in the dump
318 StringAppendF(&result, " [*] ");
319 }
320 StringAppendF(&result, "\n");
321 StringAppendF(&result, "%s", indent.c_str());
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800322 StringAppendF(&result, "Token: %" PRId64 "\n", mToken);
323 StringAppendF(&result, "%s", indent.c_str());
Adithya Srinivasan9febda82020-10-19 10:49:41 -0700324 StringAppendF(&result, "Owner Pid : %d\n", mOwnerPid);
325 StringAppendF(&result, "%s", indent.c_str());
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800326 StringAppendF(&result, "Present State : %s\n", toString(mPresentState).c_str());
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700327 StringAppendF(&result, "%s", indent.c_str());
328 StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
329 StringAppendF(&result, "%s", indent.c_str());
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800330 StringAppendF(&result, "Jank Type : %s\n", jankTypeBitmaskToString(mJankType).c_str());
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700331 StringAppendF(&result, "%s", indent.c_str());
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800332 StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
333 StringAppendF(&result, "%s", indent.c_str());
334 StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
335 std::chrono::nanoseconds latchTime(
336 std::max(static_cast<int64_t>(0), mLastLatchTime - baseTime));
337 StringAppendF(&result, "%s", indent.c_str());
338 StringAppendF(&result, "Last latch time: %10f\n",
339 std::chrono::duration<double, std::milli>(latchTime).count());
340 if (mPredictionState == PredictionState::Valid) {
341 nsecs_t presentDelta = mActuals.presentTime - mPredictions.presentTime;
342 std::chrono::nanoseconds presentDeltaNs(std::abs(presentDelta));
343 StringAppendF(&result, "%s", indent.c_str());
344 StringAppendF(&result, "Present delta: %10f\n",
345 std::chrono::duration<double, std::milli>(presentDeltaNs).count());
346 }
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700347 dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700348}
349
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800350void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
351 nsecs_t vsyncPeriod) {
352 std::lock_guard<std::mutex> lock(mMutex);
353 if (mPresentState != PresentState::Presented) {
354 // No need to update dropped buffers
355 return;
356 }
357
358 mActuals.presentTime = presentTime;
359 // Jank Analysis for SurfaceFrame
360 if (mPredictionState == PredictionState::None) {
361 // Cannot do jank classification on frames that don't have a token.
362 return;
363 }
364 if (mPredictionState == PredictionState::Expired) {
365 // We do not know what happened here to classify this correctly. This could
366 // potentially be AppDeadlineMissed but that's assuming no app will request frames
367 // 120ms apart.
368 mJankType = JankType::Unknown;
369 mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
370 mFrameReadyMetadata = FrameReadyMetadata::UnknownFinish;
371 mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
372 return;
373 }
374
375 const nsecs_t presentDelta = mActuals.presentTime - mPredictions.presentTime;
376 const nsecs_t deadlineDelta = mActuals.endTime - mPredictions.endTime;
377 const nsecs_t deltaToVsync = std::abs(presentDelta) % vsyncPeriod;
378
379 if (deadlineDelta > mJankClassificationThresholds.deadlineThreshold) {
380 mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
381 } else {
382 mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish;
383 }
384
385 if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
386 mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
387 : FramePresentMetadata::EarlyPresent;
388 } else {
389 mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
390 }
391
392 if (mFramePresentMetadata == FramePresentMetadata::OnTimePresent) {
393 // Frames presented on time are not janky.
394 mJankType = JankType::None;
395 } else if (mFramePresentMetadata == FramePresentMetadata::EarlyPresent) {
396 if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
397 // Finish on time, Present early
398 if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
399 deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
400 // Delta factor of vsync
401 mJankType = JankType::SurfaceFlingerScheduling;
402 } else {
403 // Delta not a factor of vsync
404 mJankType = JankType::PredictionError;
405 }
406 } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
407 // Finish late, Present early
408 mJankType = JankType::Unknown;
409 }
410 } else {
411 if (mLastLatchTime != 0 && mPredictions.endTime <= mLastLatchTime) {
412 // Buffer Stuffing.
413 mJankType |= JankType::BufferStuffing;
414 }
415 if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
416 // Finish on time, Present late
417 if (displayFrameJankType != JankType::None) {
418 // Propagate displayFrame's jank if it exists
419 mJankType |= displayFrameJankType;
420 } else {
421 if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
422 deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
423 // Delta factor of vsync
424 mJankType |= JankType::SurfaceFlingerScheduling;
425 } else {
426 // Delta not a factor of vsync
427 mJankType |= JankType::PredictionError;
428 }
429 }
430 } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
431 // Finish late, Present late
432 if (displayFrameJankType == JankType::None) {
433 // Display frame is not janky, so purely app's fault
434 mJankType |= JankType::AppDeadlineMissed;
435 } else {
436 // Propagate DisplayFrame's jankType if it is janky
437 mJankType |= displayFrameJankType;
438 }
439 }
440 }
441 mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
442}
443
444void SurfaceFrame::trace(int64_t displayFrameToken) {
445 using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
Adithya Srinivasan01189672020-10-20 14:23:05 -0700446 FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
447 std::lock_guard<std::mutex> lock(mMutex);
448 if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) {
449 ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str());
450 return;
451 } else if (displayFrameToken == ISurfaceComposer::INVALID_VSYNC_ID) {
452 ALOGD("Cannot trace SurfaceFrame - %s with invalid displayFrameToken",
453 mLayerName.c_str());
454 return;
455 }
456 auto packet = ctx.NewTracePacket();
457 packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
458 packet->set_timestamp(static_cast<uint64_t>(systemTime()));
459
460 auto* event = packet->set_frame_timeline_event();
461 auto* surfaceFrameEvent = event->set_surface_frame();
462
463 surfaceFrameEvent->set_token(mToken);
464 surfaceFrameEvent->set_display_frame_token(displayFrameToken);
465
466 if (mPresentState == PresentState::Dropped) {
467 surfaceFrameEvent->set_present_type(FrameTimelineEvent::PRESENT_DROPPED);
468 } else if (mPresentState == PresentState::Unknown) {
469 surfaceFrameEvent->set_present_type(FrameTimelineEvent::PRESENT_UNSPECIFIED);
470 } else {
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800471 surfaceFrameEvent->set_present_type(toProto(mFramePresentMetadata));
Adithya Srinivasan01189672020-10-20 14:23:05 -0700472 }
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800473 surfaceFrameEvent->set_on_time_finish(mFrameReadyMetadata ==
474 FrameReadyMetadata::OnTimeFinish);
475 surfaceFrameEvent->set_gpu_composition(mGpuComposition);
476 surfaceFrameEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
Adithya Srinivasan01189672020-10-20 14:23:05 -0700477
478 surfaceFrameEvent->set_expected_start_ns(mPredictions.startTime);
479 surfaceFrameEvent->set_expected_end_ns(mPredictions.endTime);
480
481 surfaceFrameEvent->set_actual_start_ns(mActuals.startTime);
482 surfaceFrameEvent->set_actual_end_ns(mActuals.endTime);
483
484 surfaceFrameEvent->set_layer_name(mDebugName);
485 surfaceFrameEvent->set_pid(mOwnerPid);
486 });
487}
488
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800489namespace impl {
490
491int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
492 ATRACE_CALL();
493 std::lock_guard<std::mutex> lock(mMutex);
494 const int64_t assignedToken = mCurrentToken++;
495 mPredictions[assignedToken] = {systemTime(), predictions};
496 flushTokens(systemTime());
497 return assignedToken;
498}
499
500std::optional<TimelineItem> TokenManager::getPredictionsForToken(int64_t token) const {
501 std::lock_guard<std::mutex> lock(mMutex);
502 auto predictionsIterator = mPredictions.find(token);
503 if (predictionsIterator != mPredictions.end()) {
504 return predictionsIterator->second.predictions;
505 }
506 return {};
507}
508
509void TokenManager::flushTokens(nsecs_t flushTime) {
510 for (auto it = mPredictions.begin(); it != mPredictions.end();) {
511 if (flushTime - it->second.timestamp >= kMaxRetentionTime) {
512 it = mPredictions.erase(it);
513 } else {
514 // Tokens are ordered by time. If i'th token is within the retention time, then the
515 // i+1'th token will also be within retention time.
516 break;
517 }
518 }
519}
520
521FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
522 JankClassificationThresholds thresholds)
523 : mCurrentDisplayFrame(std::make_shared<DisplayFrame>(timeStats, thresholds)),
Alec Mouri9a29e672020-09-14 12:39:14 -0700524 mMaxDisplayFrames(kDefaultMaxDisplayFrames),
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800525 mTimeStats(std::move(timeStats)),
526 mSurfaceFlingerPid(surfaceFlingerPid),
527 mJankClassificationThresholds(thresholds) {}
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700528
Adithya Srinivasan01189672020-10-20 14:23:05 -0700529void FrameTimeline::onBootFinished() {
530 perfetto::TracingInitArgs args;
531 args.backends = perfetto::kSystemBackend;
532 perfetto::Tracing::Initialize(args);
533 registerDataSource();
534}
535
536void FrameTimeline::registerDataSource() {
537 perfetto::DataSourceDescriptor dsd;
538 dsd.set_name(kFrameTimelineDataSource);
539 FrameTimelineDataSource::Register(dsd);
540}
541
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800542std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
543 std::optional<int64_t> token, pid_t ownerPid, uid_t ownerUid, std::string layerName,
544 std::string debugName) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700545 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700546 if (!token) {
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800547 return std::make_shared<SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid,
548 ownerUid, std::move(layerName), std::move(debugName),
549 PredictionState::None, TimelineItem(), mTimeStats,
550 mJankClassificationThresholds);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700551 }
552 std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
553 if (predictions) {
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800554 return std::make_shared<SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
555 std::move(debugName), PredictionState::Valid,
556 std::move(*predictions), mTimeStats,
557 mJankClassificationThresholds);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700558 }
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800559 return std::make_shared<SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
560 std::move(debugName), PredictionState::Expired,
561 TimelineItem(), mTimeStats,
562 mJankClassificationThresholds);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700563}
564
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800565FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats,
566 JankClassificationThresholds thresholds)
567 : mSurfaceFlingerPredictions(TimelineItem()),
568 mSurfaceFlingerActuals(TimelineItem()),
569 mTimeStats(timeStats),
570 mJankClassificationThresholds(thresholds) {
571 mSurfaceFrames.reserve(kNumSurfaceFramesInitial);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700572}
573
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800574void FrameTimeline::addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700575 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700576 std::lock_guard<std::mutex> lock(mMutex);
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800577 mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame);
578}
579
580void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) {
581 ATRACE_CALL();
582 std::lock_guard<std::mutex> lock(mMutex);
583 mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod,
584 mTokenManager.getPredictionsForToken(token), wakeUpTime);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700585}
586
587void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
588 const std::shared_ptr<FenceTime>& presentFence) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700589 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700590 std::lock_guard<std::mutex> lock(mMutex);
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800591 mCurrentDisplayFrame->setActualEndTime(sfPresentTime);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700592 mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
593 flushPendingPresentFences();
594 finalizeCurrentDisplayFrame();
595}
596
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800597void FrameTimeline::DisplayFrame::addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame) {
598 mSurfaceFrames.push_back(surfaceFrame);
599}
600
601void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod,
602 std::optional<TimelineItem> predictions,
603 nsecs_t wakeUpTime) {
604 mToken = token;
605 mVsyncPeriod = vsyncPeriod;
606 if (!predictions) {
607 mPredictionState = PredictionState::Expired;
608 } else {
609 mPredictionState = PredictionState::Valid;
610 mSurfaceFlingerPredictions = *predictions;
611 }
612 mSurfaceFlingerActuals.startTime = wakeUpTime;
613}
614
615void FrameTimeline::DisplayFrame::setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod) {
616 mToken = token;
617 mVsyncPeriod = vsyncPeriod;
618}
619
620void FrameTimeline::DisplayFrame::setPredictions(PredictionState predictionState,
621 TimelineItem predictions) {
622 mPredictionState = predictionState;
623 mSurfaceFlingerPredictions = predictions;
624}
625
626void FrameTimeline::DisplayFrame::setActualStartTime(nsecs_t actualStartTime) {
627 mSurfaceFlingerActuals.startTime = actualStartTime;
628}
629
630void FrameTimeline::DisplayFrame::setActualEndTime(nsecs_t actualEndTime) {
631 mSurfaceFlingerActuals.endTime = actualEndTime;
632}
633
634void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
635 mSurfaceFlingerActuals.presentTime = signalTime;
636 int32_t totalJankReasons = JankType::None;
637
638 // Delta between the expected present and the actual present
639 const nsecs_t presentDelta =
640 mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
641 // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
642 // was a prediction error or not.
643 nsecs_t deltaToVsync = std::abs(presentDelta) % mVsyncPeriod;
644 if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
645 mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
646 : FramePresentMetadata::EarlyPresent;
647 } else {
648 mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
649 }
650
651 if (mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime >
652 mJankClassificationThresholds.deadlineThreshold) {
653 mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
654 } else {
655 mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish;
656 }
657
658 if (std::abs(mSurfaceFlingerActuals.startTime - mSurfaceFlingerPredictions.startTime) >
659 mJankClassificationThresholds.startThreshold) {
660 mFrameStartMetadata =
661 mSurfaceFlingerActuals.startTime > mSurfaceFlingerPredictions.startTime
662 ? FrameStartMetadata::LateStart
663 : FrameStartMetadata::EarlyStart;
664 }
665
666 if (mFramePresentMetadata != FramePresentMetadata::OnTimePresent) {
667 // Do jank classification only if present is not on time
668 if (mFramePresentMetadata == FramePresentMetadata::EarlyPresent) {
669 if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
670 // Finish on time, Present early
671 if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
672 deltaToVsync >=
673 (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
674 // Delta is a factor of vsync if its within the presentTheshold on either side
675 // of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
676 // of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
677 mJankType = JankType::SurfaceFlingerScheduling;
678 } else {
679 // Delta is not a factor of vsync,
680 mJankType = JankType::PredictionError;
681 }
682 } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
683 // Finish late, Present early
684 mJankType = JankType::SurfaceFlingerScheduling;
685 } else {
686 // Finish time unknown
687 mJankType = JankType::Unknown;
688 }
689 } else if (mFramePresentMetadata == FramePresentMetadata::LatePresent) {
690 if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
691 // Finish on time, Present late
692 if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
693 deltaToVsync >=
694 (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
695 // Delta is a factor of vsync if its within the presentTheshold on either side
696 // of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
697 // of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
698 mJankType = JankType::DisplayHAL;
699 } else {
700 // Delta is not a factor of vsync
701 mJankType = JankType::PredictionError;
702 }
703 } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
704 // Finish late, Present late
705 mJankType = JankType::SurfaceFlingerCpuDeadlineMissed;
706 } else {
707 // Finish time unknown
708 mJankType = JankType::Unknown;
709 }
710 } else {
711 // Present unknown
712 mJankType = JankType::Unknown;
713 }
714 }
715 totalJankReasons |= mJankType;
716
717 for (auto& surfaceFrame : mSurfaceFrames) {
718 surfaceFrame->onPresent(signalTime, mJankType, mVsyncPeriod);
719 auto surfaceFrameJankType = surfaceFrame->getJankType();
720 if (surfaceFrameJankType != std::nullopt) {
721 totalJankReasons |= *surfaceFrameJankType;
722 }
723 }
724 mTimeStats->incrementJankyFrames(totalJankReasons);
725}
726
727void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
728 FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
729 if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) {
730 ALOGD("Cannot trace DisplayFrame with invalid token");
731 return;
732 }
733 auto packet = ctx.NewTracePacket();
734 packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
735 packet->set_timestamp(static_cast<uint64_t>(systemTime()));
736
737 auto* event = packet->set_frame_timeline_event();
738 auto* displayFrameEvent = event->set_display_frame();
739
740 displayFrameEvent->set_token(mToken);
741 displayFrameEvent->set_present_type(toProto(mFramePresentMetadata));
742 displayFrameEvent->set_on_time_finish(mFrameReadyMetadata ==
743 FrameReadyMetadata::OnTimeFinish);
744 displayFrameEvent->set_gpu_composition(mGpuComposition);
745 displayFrameEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
746
747 displayFrameEvent->set_expected_start_ns(mSurfaceFlingerPredictions.startTime);
748 displayFrameEvent->set_expected_end_ns(mSurfaceFlingerPredictions.endTime);
749
750 displayFrameEvent->set_actual_start_ns(mSurfaceFlingerActuals.startTime);
751 displayFrameEvent->set_actual_end_ns(mSurfaceFlingerActuals.endTime);
752
753 displayFrameEvent->set_pid(surfaceFlingerPid);
754 });
755
756 for (auto& surfaceFrame : mSurfaceFrames) {
757 surfaceFrame->trace(mToken);
758 }
759}
760
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700761void FrameTimeline::flushPendingPresentFences() {
762 for (size_t i = 0; i < mPendingPresentFences.size(); i++) {
763 const auto& pendingPresentFence = mPendingPresentFences[i];
764 nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
765 if (pendingPresentFence.first && pendingPresentFence.first->isValid()) {
766 signalTime = pendingPresentFence.first->getSignalTime();
767 if (signalTime == Fence::SIGNAL_TIME_PENDING) {
768 continue;
769 }
770 }
771 if (signalTime != Fence::SIGNAL_TIME_INVALID) {
772 auto& displayFrame = pendingPresentFence.second;
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800773 displayFrame->onPresent(signalTime);
774 displayFrame->trace(mSurfaceFlingerPid);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700775 }
776
777 mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
778 --i;
779 }
780}
781
782void FrameTimeline::finalizeCurrentDisplayFrame() {
Adithya Srinivasan2d736322020-10-01 16:53:48 -0700783 while (mDisplayFrames.size() >= mMaxDisplayFrames) {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700784 // We maintain only a fixed number of frames' data. Pop older frames
785 mDisplayFrames.pop_front();
786 }
787 mDisplayFrames.push_back(mCurrentDisplayFrame);
788 mCurrentDisplayFrame.reset();
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800789 mCurrentDisplayFrame =
790 std::make_shared<DisplayFrame>(mTimeStats, mJankClassificationThresholds);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700791}
792
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800793nsecs_t FrameTimeline::DisplayFrame::getBaseTime() const {
794 nsecs_t baseTime =
795 getMinTime(mPredictionState, mSurfaceFlingerPredictions, mSurfaceFlingerActuals);
796 for (const auto& surfaceFrame : mSurfaceFrames) {
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700797 nsecs_t surfaceFrameBaseTime = surfaceFrame->getBaseTime();
798 if (surfaceFrameBaseTime != 0) {
799 baseTime = std::min(baseTime, surfaceFrameBaseTime);
800 }
801 }
802 return baseTime;
803}
804
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800805void FrameTimeline::DisplayFrame::dumpJank(std::string& result, nsecs_t baseTime,
806 int displayFrameCount) const {
807 if (mJankType == JankType::None) {
808 // Check if any Surface Frame has been janky
809 bool isJanky = false;
810 for (const auto& surfaceFrame : mSurfaceFrames) {
811 if (surfaceFrame->getJankType() != JankType::None) {
812 isJanky = true;
813 break;
814 }
815 }
816 if (!isJanky) {
817 return;
818 }
819 }
820 StringAppendF(&result, "Display Frame %d", displayFrameCount);
821 dump(result, baseTime);
822}
823
824void FrameTimeline::DisplayFrame::dumpAll(std::string& result, nsecs_t baseTime) const {
825 dump(result, baseTime);
826}
827
828void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) const {
829 if (mJankType != JankType::None) {
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700830 // Easily identify a janky Display Frame in the dump
831 StringAppendF(&result, " [*] ");
832 }
833 StringAppendF(&result, "\n");
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800834 StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
835 StringAppendF(&result, "Jank Type : %s\n", jankTypeBitmaskToString(mJankType).c_str());
836 StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
837 StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
838 StringAppendF(&result, "Start Metadata: %s\n", toString(mFrameStartMetadata).c_str());
839 std::chrono::nanoseconds vsyncPeriod(mVsyncPeriod);
840 StringAppendF(&result, "Vsync Period: %10f\n",
841 std::chrono::duration<double, std::milli>(vsyncPeriod).count());
842 nsecs_t presentDelta =
843 mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
844 std::chrono::nanoseconds presentDeltaNs(std::abs(presentDelta));
845 StringAppendF(&result, "Present delta: %10f\n",
846 std::chrono::duration<double, std::milli>(presentDeltaNs).count());
847 std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mVsyncPeriod);
848 StringAppendF(&result, "Present delta %% refreshrate: %10f\n",
849 std::chrono::duration<double, std::milli>(deltaToVsync).count());
850 dumpTable(result, mSurfaceFlingerPredictions, mSurfaceFlingerActuals, "", mPredictionState,
851 baseTime);
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700852 StringAppendF(&result, "\n");
853 std::string indent = " "; // 4 spaces
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800854 for (const auto& surfaceFrame : mSurfaceFrames) {
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700855 surfaceFrame->dump(result, indent, baseTime);
856 }
857 StringAppendF(&result, "\n");
858}
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800859
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700860void FrameTimeline::dumpAll(std::string& result) {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700861 std::lock_guard<std::mutex> lock(mMutex);
862 StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800863 nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime();
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700864 for (size_t i = 0; i < mDisplayFrames.size(); i++) {
865 StringAppendF(&result, "Display Frame %d", static_cast<int>(i));
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800866 mDisplayFrames[i]->dumpAll(result, baseTime);
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700867 }
868}
869
870void FrameTimeline::dumpJank(std::string& result) {
871 std::lock_guard<std::mutex> lock(mMutex);
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800872 nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime();
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700873 for (size_t i = 0; i < mDisplayFrames.size(); i++) {
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800874 mDisplayFrames[i]->dumpJank(result, baseTime, static_cast<int>(i));
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700875 }
876}
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800877
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700878void FrameTimeline::parseArgs(const Vector<String16>& args, std::string& result) {
879 ATRACE_CALL();
880 std::unordered_map<std::string, bool> argsMap;
881 for (size_t i = 0; i < args.size(); i++) {
882 argsMap[std::string(String8(args[i]).c_str())] = true;
883 }
884 if (argsMap.count("-jank")) {
885 dumpJank(result);
886 }
887 if (argsMap.count("-all")) {
888 dumpAll(result);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700889 }
890}
891
Adithya Srinivasan2d736322020-10-01 16:53:48 -0700892void FrameTimeline::setMaxDisplayFrames(uint32_t size) {
893 std::lock_guard<std::mutex> lock(mMutex);
894
895 // The size can either increase or decrease, clear everything, to be consistent
896 mDisplayFrames.clear();
897 mPendingPresentFences.clear();
898 mMaxDisplayFrames = size;
899}
900
901void FrameTimeline::reset() {
902 setMaxDisplayFrames(kDefaultMaxDisplayFrames);
903}
904
Adithya Srinivasan9b2ca3e2020-11-10 10:14:17 -0800905} // namespace impl
906} // namespace android::frametimeline