blob: 43176a3f10986a05e0fc1440fd3b3ffcfba66d67 [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
29namespace android::frametimeline::impl {
30
31using base::StringAppendF;
32
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -070033void dumpTable(std::string& result, TimelineItem predictions, TimelineItem actuals,
34 const std::string& indent, PredictionState predictionState, nsecs_t baseTime) {
35 StringAppendF(&result, "%s", indent.c_str());
36 StringAppendF(&result, "\t\t");
37 StringAppendF(&result, " Start time\t\t|");
38 StringAppendF(&result, " End time\t\t|");
39 StringAppendF(&result, " Present time\n");
40 if (predictionState == PredictionState::Valid) {
41 // Dump the Predictions only if they are valid
42 StringAppendF(&result, "%s", indent.c_str());
43 StringAppendF(&result, "Expected\t|");
44 std::chrono::nanoseconds startTime(predictions.startTime - baseTime);
45 std::chrono::nanoseconds endTime(predictions.endTime - baseTime);
46 std::chrono::nanoseconds presentTime(predictions.presentTime - baseTime);
47 StringAppendF(&result, "\t%10.2f\t|\t%10.2f\t|\t%10.2f\n",
48 std::chrono::duration<double, std::milli>(startTime).count(),
49 std::chrono::duration<double, std::milli>(endTime).count(),
50 std::chrono::duration<double, std::milli>(presentTime).count());
51 }
52 StringAppendF(&result, "%s", indent.c_str());
53 StringAppendF(&result, "Actual \t|");
54
55 if (actuals.startTime == 0) {
56 StringAppendF(&result, "\t\tN/A\t|");
57 } else {
58 std::chrono::nanoseconds startTime(std::max<nsecs_t>(0, actuals.startTime - baseTime));
59 StringAppendF(&result, "\t%10.2f\t|",
60 std::chrono::duration<double, std::milli>(startTime).count());
61 }
62 if (actuals.endTime == 0) {
63 StringAppendF(&result, "\t\tN/A\t|");
64 } else {
65 std::chrono::nanoseconds endTime(actuals.endTime - baseTime);
66 StringAppendF(&result, "\t%10.2f\t|",
67 std::chrono::duration<double, std::milli>(endTime).count());
68 }
69 if (actuals.presentTime == 0) {
70 StringAppendF(&result, "\t\tN/A\n");
71 } else {
72 std::chrono::nanoseconds presentTime(std::max<nsecs_t>(0, actuals.presentTime - baseTime));
73 StringAppendF(&result, "\t%10.2f\n",
74 std::chrono::duration<double, std::milli>(presentTime).count());
75 }
76
77 StringAppendF(&result, "%s", indent.c_str());
78 StringAppendF(&result, "----------------------");
79 StringAppendF(&result, "----------------------");
80 StringAppendF(&result, "----------------------");
81 StringAppendF(&result, "----------------------\n");
82}
83
84std::string toString(PredictionState predictionState) {
85 switch (predictionState) {
86 case PredictionState::Valid:
87 return "Valid";
88 case PredictionState::Expired:
89 return "Expired";
90 case PredictionState::None:
91 default:
92 return "None";
93 }
94}
95
96std::string toString(JankType jankType) {
97 switch (jankType) {
98 case JankType::None:
99 return "None";
100 case JankType::Display:
101 return "Composer/Display - outside SF and App";
102 case JankType::SurfaceFlingerDeadlineMissed:
103 return "SurfaceFlinger Deadline Missed";
104 case JankType::AppDeadlineMissed:
105 return "App Deadline Missed";
106 case JankType::PredictionExpired:
107 return "Prediction Expired";
108 case JankType::SurfaceFlingerEarlyLatch:
109 return "SurfaceFlinger Early Latch";
110 default:
111 return "Unclassified";
112 }
113}
114
115std::string jankMetadataBitmaskToString(int32_t jankMetadata) {
116 std::vector<std::string> jankInfo;
117
118 if (jankMetadata & EarlyStart) {
119 jankInfo.emplace_back("Early Start");
120 } else if (jankMetadata & LateStart) {
121 jankInfo.emplace_back("Late Start");
122 }
123
124 if (jankMetadata & EarlyFinish) {
125 jankInfo.emplace_back("Early Finish");
126 } else if (jankMetadata & LateFinish) {
127 jankInfo.emplace_back("Late Finish");
128 }
129
130 if (jankMetadata & EarlyPresent) {
131 jankInfo.emplace_back("Early Present");
132 } else if (jankMetadata & LatePresent) {
133 jankInfo.emplace_back("Late Present");
134 }
135 // TODO(b/169876734): add GPU composition metadata here
136
137 if (jankInfo.empty()) {
138 return "None";
139 }
140 return std::accumulate(jankInfo.begin(), jankInfo.end(), std::string(),
141 [](const std::string& l, const std::string& r) {
142 return l.empty() ? r : l + ", " + r;
143 });
144}
145
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700146int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700147 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700148 std::lock_guard<std::mutex> lock(mMutex);
149 const int64_t assignedToken = mCurrentToken++;
150 mPredictions[assignedToken] = predictions;
151 mTokens.emplace_back(std::make_pair(assignedToken, systemTime()));
152 flushTokens(systemTime());
153 return assignedToken;
154}
155
156std::optional<TimelineItem> TokenManager::getPredictionsForToken(int64_t token) {
157 std::lock_guard<std::mutex> lock(mMutex);
158 flushTokens(systemTime());
159 auto predictionsIterator = mPredictions.find(token);
160 if (predictionsIterator != mPredictions.end()) {
161 return predictionsIterator->second;
162 }
163 return {};
164}
165
166void TokenManager::flushTokens(nsecs_t flushTime) {
167 for (size_t i = 0; i < mTokens.size(); i++) {
168 if (flushTime - mTokens[i].second >= kMaxRetentionTime) {
169 mPredictions.erase(mTokens[i].first);
170 mTokens.erase(mTokens.begin() + static_cast<int>(i));
171 --i;
172 } else {
173 // Tokens are ordered by time. If i'th token is within the retention time, then the
174 // i+1'th token will also be within retention time.
175 break;
176 }
177 }
178}
179
180SurfaceFrame::SurfaceFrame(const std::string& layerName, PredictionState predictionState,
181 frametimeline::TimelineItem&& predictions)
182 : mLayerName(layerName),
183 mPresentState(PresentState::Unknown),
184 mPredictionState(predictionState),
185 mPredictions(predictions),
186 mActuals({0, 0, 0}),
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700187 mActualQueueTime(0),
188 mJankType(JankType::None),
189 mJankMetadata(0) {}
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700190
191void SurfaceFrame::setPresentState(PresentState state) {
192 std::lock_guard<std::mutex> lock(mMutex);
193 mPresentState = state;
194}
195
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700196SurfaceFrame::PresentState SurfaceFrame::getPresentState() const {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700197 std::lock_guard<std::mutex> lock(mMutex);
198 return mPresentState;
199}
200
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700201TimelineItem SurfaceFrame::getActuals() const {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700202 std::lock_guard<std::mutex> lock(mMutex);
203 return mActuals;
204}
205
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700206nsecs_t SurfaceFrame::getActualQueueTime() const {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700207 std::lock_guard<std::mutex> lock(mMutex);
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700208 return mActualQueueTime;
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700209}
210
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700211void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) {
212 std::lock_guard<std::mutex> lock(mMutex);
213 mActuals.startTime = actualStartTime;
214}
215
216void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) {
217 std::lock_guard<std::mutex> lock(mMutex);
218 mActualQueueTime = actualQueueTime;
219}
Ady Abraham7f8a1e62020-09-28 16:09:35 -0700220void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700221 std::lock_guard<std::mutex> lock(mMutex);
Ady Abraham7f8a1e62020-09-28 16:09:35 -0700222 mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700223}
224
225void SurfaceFrame::setActualPresentTime(nsecs_t presentTime) {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700226 std::lock_guard<std::mutex> lock(mMutex);
227 mActuals.presentTime = presentTime;
228}
229
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700230void SurfaceFrame::setJankInfo(JankType jankType, int32_t jankMetadata) {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700231 std::lock_guard<std::mutex> lock(mMutex);
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700232 mJankType = jankType;
233 mJankMetadata = jankMetadata;
234}
235
236JankType SurfaceFrame::getJankType() const {
237 std::lock_guard<std::mutex> lock(mMutex);
238 return mJankType;
239}
240
241nsecs_t SurfaceFrame::getBaseTime() const {
242 std::lock_guard<std::mutex> lock(mMutex);
243 nsecs_t baseTime = std::numeric_limits<nsecs_t>::max();
244 if (mPredictionState == PredictionState::Valid) {
245 baseTime = std::min(baseTime, mPredictions.startTime);
246 }
247 if (mActuals.startTime != 0) {
248 baseTime = std::min(baseTime, mActuals.startTime);
249 }
250 baseTime = std::min(baseTime, mActuals.endTime);
251 return baseTime;
252}
253
254std::string presentStateToString(SurfaceFrame::PresentState presentState) {
255 using PresentState = SurfaceFrame::PresentState;
256 switch (presentState) {
257 case PresentState::Presented:
258 return "Presented";
259 case PresentState::Dropped:
260 return "Dropped";
261 case PresentState::Unknown:
262 default:
263 return "Unknown";
264 }
265}
266
267void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) {
268 std::lock_guard<std::mutex> lock(mMutex);
269 StringAppendF(&result, "%s", indent.c_str());
270 StringAppendF(&result, "Layer - %s", mLayerName.c_str());
271 if (mJankType != JankType::None) {
272 // Easily identify a janky Surface Frame in the dump
273 StringAppendF(&result, " [*] ");
274 }
275 StringAppendF(&result, "\n");
276 StringAppendF(&result, "%s", indent.c_str());
277 StringAppendF(&result, "Present State : %s\n", presentStateToString(mPresentState).c_str());
278 StringAppendF(&result, "%s", indent.c_str());
279 StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
280 StringAppendF(&result, "%s", indent.c_str());
281 StringAppendF(&result, "Jank Type : %s\n", toString(mJankType).c_str());
282 StringAppendF(&result, "%s", indent.c_str());
283 StringAppendF(&result, "Jank Metadata: %s\n",
284 jankMetadataBitmaskToString(mJankMetadata).c_str());
285 dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700286}
287
Adithya Srinivasan2d736322020-10-01 16:53:48 -0700288FrameTimeline::FrameTimeline()
289 : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()),
290 mMaxDisplayFrames(kDefaultMaxDisplayFrames) {}
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700291
292FrameTimeline::DisplayFrame::DisplayFrame()
293 : surfaceFlingerPredictions(TimelineItem()),
294 surfaceFlingerActuals(TimelineItem()),
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700295 predictionState(PredictionState::None),
296 jankType(JankType::None),
297 jankMetadata(0) {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700298 this->surfaceFrames.reserve(kNumSurfaceFramesInitial);
299}
300
301std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
302 const std::string& layerName, std::optional<int64_t> token) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700303 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700304 if (!token) {
305 return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None,
306 TimelineItem());
307 }
308 std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
309 if (predictions) {
310 return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Valid,
311 std::move(*predictions));
312 }
313 return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Expired,
314 TimelineItem());
315}
316
317void FrameTimeline::addSurfaceFrame(
318 std::unique_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
319 SurfaceFrame::PresentState state) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700320 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700321 surfaceFrame->setPresentState(state);
322 std::unique_ptr<impl::SurfaceFrame> implSurfaceFrame(
323 static_cast<impl::SurfaceFrame*>(surfaceFrame.release()));
324 std::lock_guard<std::mutex> lock(mMutex);
325 mCurrentDisplayFrame->surfaceFrames.push_back(std::move(implSurfaceFrame));
326}
327
328void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700329 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700330 const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token);
331 std::lock_guard<std::mutex> lock(mMutex);
332 if (!prediction) {
333 mCurrentDisplayFrame->predictionState = PredictionState::Expired;
334 } else {
335 mCurrentDisplayFrame->surfaceFlingerPredictions = *prediction;
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700336 mCurrentDisplayFrame->predictionState = PredictionState::Valid;
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700337 }
338 mCurrentDisplayFrame->surfaceFlingerActuals.startTime = wakeUpTime;
339}
340
341void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
342 const std::shared_ptr<FenceTime>& presentFence) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700343 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700344 std::lock_guard<std::mutex> lock(mMutex);
345 mCurrentDisplayFrame->surfaceFlingerActuals.endTime = sfPresentTime;
346 mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
347 flushPendingPresentFences();
348 finalizeCurrentDisplayFrame();
349}
350
351void FrameTimeline::flushPendingPresentFences() {
352 for (size_t i = 0; i < mPendingPresentFences.size(); i++) {
353 const auto& pendingPresentFence = mPendingPresentFences[i];
354 nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
355 if (pendingPresentFence.first && pendingPresentFence.first->isValid()) {
356 signalTime = pendingPresentFence.first->getSignalTime();
357 if (signalTime == Fence::SIGNAL_TIME_PENDING) {
358 continue;
359 }
360 }
361 if (signalTime != Fence::SIGNAL_TIME_INVALID) {
362 auto& displayFrame = pendingPresentFence.second;
363 displayFrame->surfaceFlingerActuals.presentTime = signalTime;
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700364
365 // Jank Analysis for DisplayFrame
366 const auto& sfActuals = displayFrame->surfaceFlingerActuals;
367 const auto& sfPredictions = displayFrame->surfaceFlingerPredictions;
368 if (std::abs(sfActuals.presentTime - sfPredictions.presentTime) > kPresentThreshold) {
369 displayFrame->jankMetadata |= sfActuals.presentTime > sfPredictions.presentTime
370 ? LatePresent
371 : EarlyPresent;
372 }
373 if (std::abs(sfActuals.endTime - sfPredictions.endTime) > kDeadlineThreshold) {
374 if (sfActuals.endTime > sfPredictions.endTime) {
375 displayFrame->jankMetadata |= LateFinish;
376 } else {
377 displayFrame->jankMetadata |= EarlyFinish;
378 }
379
380 if (displayFrame->jankMetadata & EarlyFinish & EarlyPresent) {
381 displayFrame->jankType = JankType::SurfaceFlingerEarlyLatch;
382 } else if (displayFrame->jankMetadata & LateFinish & LatePresent) {
383 displayFrame->jankType = JankType::SurfaceFlingerDeadlineMissed;
384 } else if (displayFrame->jankMetadata & EarlyPresent ||
385 displayFrame->jankMetadata & LatePresent) {
386 // Cases where SF finished early but frame was presented late and vice versa
387 displayFrame->jankType = JankType::Display;
388 }
389 }
390 if (std::abs(sfActuals.startTime - sfPredictions.startTime) > kSFStartThreshold) {
391 displayFrame->jankMetadata |=
392 sfActuals.startTime > sfPredictions.startTime ? LateStart : EarlyStart;
393 }
394
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700395 for (auto& surfaceFrame : displayFrame->surfaceFrames) {
396 if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
397 // Only presented SurfaceFrames need to be updated
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700398 surfaceFrame->setActualPresentTime(signalTime);
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700399
400 // Jank Analysis for SurfaceFrame
401 const auto& predictionState = surfaceFrame->getPredictionState();
402 if (predictionState == PredictionState::Expired) {
403 // Jank analysis cannot be done on apps that don't use predictions
404 surfaceFrame->setJankInfo(JankType::PredictionExpired, 0);
405 continue;
406 } else if (predictionState == PredictionState::Valid) {
407 const auto& actuals = surfaceFrame->getActuals();
408 const auto& predictions = surfaceFrame->getPredictions();
409 int32_t jankMetadata = 0;
410 JankType jankType = JankType::None;
411 if (std::abs(actuals.endTime - predictions.endTime) > kDeadlineThreshold) {
412 jankMetadata |= actuals.endTime > predictions.endTime ? LateFinish
413 : EarlyFinish;
414 }
415 if (std::abs(actuals.presentTime - predictions.presentTime) >
416 kPresentThreshold) {
417 jankMetadata |= actuals.presentTime > predictions.presentTime
418 ? LatePresent
419 : EarlyPresent;
420 }
421 if (jankMetadata & EarlyPresent) {
422 jankType = JankType::SurfaceFlingerEarlyLatch;
423 } else if (jankMetadata & LatePresent) {
424 if (jankMetadata & EarlyFinish) {
425 // TODO(b/169890654): Classify this properly
426 jankType = JankType::Display;
427 } else {
428 jankType = JankType::AppDeadlineMissed;
429 }
430 }
431 surfaceFrame->setJankInfo(jankType, jankMetadata);
432 }
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700433 }
434 }
435 }
436
437 mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
438 --i;
439 }
440}
441
442void FrameTimeline::finalizeCurrentDisplayFrame() {
Adithya Srinivasan2d736322020-10-01 16:53:48 -0700443 while (mDisplayFrames.size() >= mMaxDisplayFrames) {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700444 // We maintain only a fixed number of frames' data. Pop older frames
445 mDisplayFrames.pop_front();
446 }
447 mDisplayFrames.push_back(mCurrentDisplayFrame);
448 mCurrentDisplayFrame.reset();
449 mCurrentDisplayFrame = std::make_shared<DisplayFrame>();
450}
451
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700452nsecs_t FrameTimeline::findBaseTime(const std::shared_ptr<DisplayFrame>& displayFrame) {
453 nsecs_t baseTime = std::numeric_limits<nsecs_t>::max();
454 if (displayFrame->predictionState == PredictionState::Valid) {
455 baseTime = std::min(baseTime, displayFrame->surfaceFlingerPredictions.startTime);
456 }
457 baseTime = std::min(baseTime, displayFrame->surfaceFlingerActuals.startTime);
458 for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
459 nsecs_t surfaceFrameBaseTime = surfaceFrame->getBaseTime();
460 if (surfaceFrameBaseTime != 0) {
461 baseTime = std::min(baseTime, surfaceFrameBaseTime);
462 }
463 }
464 return baseTime;
465}
466
467void FrameTimeline::dumpDisplayFrame(std::string& result,
468 const std::shared_ptr<DisplayFrame>& displayFrame,
469 nsecs_t baseTime) {
470 if (displayFrame->jankType != JankType::None) {
471 // Easily identify a janky Display Frame in the dump
472 StringAppendF(&result, " [*] ");
473 }
474 StringAppendF(&result, "\n");
475 StringAppendF(&result, "Prediction State : %s\n",
476 toString(displayFrame->predictionState).c_str());
477 StringAppendF(&result, "Jank Type : %s\n", toString(displayFrame->jankType).c_str());
478 StringAppendF(&result, "Jank Metadata: %s\n",
479 jankMetadataBitmaskToString(displayFrame->jankMetadata).c_str());
480 dumpTable(result, displayFrame->surfaceFlingerPredictions, displayFrame->surfaceFlingerActuals,
481 "", displayFrame->predictionState, baseTime);
482 StringAppendF(&result, "\n");
483 std::string indent = " "; // 4 spaces
484 for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
485 surfaceFrame->dump(result, indent, baseTime);
486 }
487 StringAppendF(&result, "\n");
488}
489void FrameTimeline::dumpAll(std::string& result) {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700490 std::lock_guard<std::mutex> lock(mMutex);
491 StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700492 nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
493 for (size_t i = 0; i < mDisplayFrames.size(); i++) {
494 StringAppendF(&result, "Display Frame %d", static_cast<int>(i));
495 dumpDisplayFrame(result, mDisplayFrames[i], baseTime);
496 }
497}
498
499void FrameTimeline::dumpJank(std::string& result) {
500 std::lock_guard<std::mutex> lock(mMutex);
501 nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
502 for (size_t i = 0; i < mDisplayFrames.size(); i++) {
503 const auto& displayFrame = mDisplayFrames[i];
504 if (displayFrame->jankType == JankType::None) {
505 // Check if any Surface Frame has been janky
506 bool isJanky = false;
507 for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
508 if (surfaceFrame->getJankType() != JankType::None) {
509 isJanky = true;
510 break;
511 }
512 }
513 if (!isJanky) {
514 continue;
515 }
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700516 }
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700517 StringAppendF(&result, "Display Frame %d", static_cast<int>(i));
518 dumpDisplayFrame(result, displayFrame, baseTime);
519 }
520}
521void FrameTimeline::parseArgs(const Vector<String16>& args, std::string& result) {
522 ATRACE_CALL();
523 std::unordered_map<std::string, bool> argsMap;
524 for (size_t i = 0; i < args.size(); i++) {
525 argsMap[std::string(String8(args[i]).c_str())] = true;
526 }
527 if (argsMap.count("-jank")) {
528 dumpJank(result);
529 }
530 if (argsMap.count("-all")) {
531 dumpAll(result);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700532 }
533}
534
Adithya Srinivasan2d736322020-10-01 16:53:48 -0700535void FrameTimeline::setMaxDisplayFrames(uint32_t size) {
536 std::lock_guard<std::mutex> lock(mMutex);
537
538 // The size can either increase or decrease, clear everything, to be consistent
539 mDisplayFrames.clear();
540 mPendingPresentFences.clear();
541 mMaxDisplayFrames = size;
542}
543
544void FrameTimeline::reset() {
545 setMaxDisplayFrames(kDefaultMaxDisplayFrames);
546}
547
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700548} // namespace android::frametimeline::impl