blob: 22d9d10d18257b0c11aab860b33b602fcdbd668c [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
288FrameTimeline::FrameTimeline() : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()) {}
289
290FrameTimeline::DisplayFrame::DisplayFrame()
291 : surfaceFlingerPredictions(TimelineItem()),
292 surfaceFlingerActuals(TimelineItem()),
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700293 predictionState(PredictionState::None),
294 jankType(JankType::None),
295 jankMetadata(0) {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700296 this->surfaceFrames.reserve(kNumSurfaceFramesInitial);
297}
298
299std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
300 const std::string& layerName, std::optional<int64_t> token) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700301 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700302 if (!token) {
303 return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None,
304 TimelineItem());
305 }
306 std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
307 if (predictions) {
308 return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Valid,
309 std::move(*predictions));
310 }
311 return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Expired,
312 TimelineItem());
313}
314
315void FrameTimeline::addSurfaceFrame(
316 std::unique_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
317 SurfaceFrame::PresentState state) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700318 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700319 surfaceFrame->setPresentState(state);
320 std::unique_ptr<impl::SurfaceFrame> implSurfaceFrame(
321 static_cast<impl::SurfaceFrame*>(surfaceFrame.release()));
322 std::lock_guard<std::mutex> lock(mMutex);
323 mCurrentDisplayFrame->surfaceFrames.push_back(std::move(implSurfaceFrame));
324}
325
326void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700327 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700328 const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token);
329 std::lock_guard<std::mutex> lock(mMutex);
330 if (!prediction) {
331 mCurrentDisplayFrame->predictionState = PredictionState::Expired;
332 } else {
333 mCurrentDisplayFrame->surfaceFlingerPredictions = *prediction;
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700334 mCurrentDisplayFrame->predictionState = PredictionState::Valid;
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700335 }
336 mCurrentDisplayFrame->surfaceFlingerActuals.startTime = wakeUpTime;
337}
338
339void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
340 const std::shared_ptr<FenceTime>& presentFence) {
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700341 ATRACE_CALL();
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700342 std::lock_guard<std::mutex> lock(mMutex);
343 mCurrentDisplayFrame->surfaceFlingerActuals.endTime = sfPresentTime;
344 mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
345 flushPendingPresentFences();
346 finalizeCurrentDisplayFrame();
347}
348
349void FrameTimeline::flushPendingPresentFences() {
350 for (size_t i = 0; i < mPendingPresentFences.size(); i++) {
351 const auto& pendingPresentFence = mPendingPresentFences[i];
352 nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
353 if (pendingPresentFence.first && pendingPresentFence.first->isValid()) {
354 signalTime = pendingPresentFence.first->getSignalTime();
355 if (signalTime == Fence::SIGNAL_TIME_PENDING) {
356 continue;
357 }
358 }
359 if (signalTime != Fence::SIGNAL_TIME_INVALID) {
360 auto& displayFrame = pendingPresentFence.second;
361 displayFrame->surfaceFlingerActuals.presentTime = signalTime;
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700362
363 // Jank Analysis for DisplayFrame
364 const auto& sfActuals = displayFrame->surfaceFlingerActuals;
365 const auto& sfPredictions = displayFrame->surfaceFlingerPredictions;
366 if (std::abs(sfActuals.presentTime - sfPredictions.presentTime) > kPresentThreshold) {
367 displayFrame->jankMetadata |= sfActuals.presentTime > sfPredictions.presentTime
368 ? LatePresent
369 : EarlyPresent;
370 }
371 if (std::abs(sfActuals.endTime - sfPredictions.endTime) > kDeadlineThreshold) {
372 if (sfActuals.endTime > sfPredictions.endTime) {
373 displayFrame->jankMetadata |= LateFinish;
374 } else {
375 displayFrame->jankMetadata |= EarlyFinish;
376 }
377
378 if (displayFrame->jankMetadata & EarlyFinish & EarlyPresent) {
379 displayFrame->jankType = JankType::SurfaceFlingerEarlyLatch;
380 } else if (displayFrame->jankMetadata & LateFinish & LatePresent) {
381 displayFrame->jankType = JankType::SurfaceFlingerDeadlineMissed;
382 } else if (displayFrame->jankMetadata & EarlyPresent ||
383 displayFrame->jankMetadata & LatePresent) {
384 // Cases where SF finished early but frame was presented late and vice versa
385 displayFrame->jankType = JankType::Display;
386 }
387 }
388 if (std::abs(sfActuals.startTime - sfPredictions.startTime) > kSFStartThreshold) {
389 displayFrame->jankMetadata |=
390 sfActuals.startTime > sfPredictions.startTime ? LateStart : EarlyStart;
391 }
392
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700393 for (auto& surfaceFrame : displayFrame->surfaceFrames) {
394 if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
395 // Only presented SurfaceFrames need to be updated
Adithya Srinivasan5f683cf2020-09-15 14:21:04 -0700396 surfaceFrame->setActualPresentTime(signalTime);
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700397
398 // Jank Analysis for SurfaceFrame
399 const auto& predictionState = surfaceFrame->getPredictionState();
400 if (predictionState == PredictionState::Expired) {
401 // Jank analysis cannot be done on apps that don't use predictions
402 surfaceFrame->setJankInfo(JankType::PredictionExpired, 0);
403 continue;
404 } else if (predictionState == PredictionState::Valid) {
405 const auto& actuals = surfaceFrame->getActuals();
406 const auto& predictions = surfaceFrame->getPredictions();
407 int32_t jankMetadata = 0;
408 JankType jankType = JankType::None;
409 if (std::abs(actuals.endTime - predictions.endTime) > kDeadlineThreshold) {
410 jankMetadata |= actuals.endTime > predictions.endTime ? LateFinish
411 : EarlyFinish;
412 }
413 if (std::abs(actuals.presentTime - predictions.presentTime) >
414 kPresentThreshold) {
415 jankMetadata |= actuals.presentTime > predictions.presentTime
416 ? LatePresent
417 : EarlyPresent;
418 }
419 if (jankMetadata & EarlyPresent) {
420 jankType = JankType::SurfaceFlingerEarlyLatch;
421 } else if (jankMetadata & LatePresent) {
422 if (jankMetadata & EarlyFinish) {
423 // TODO(b/169890654): Classify this properly
424 jankType = JankType::Display;
425 } else {
426 jankType = JankType::AppDeadlineMissed;
427 }
428 }
429 surfaceFrame->setJankInfo(jankType, jankMetadata);
430 }
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700431 }
432 }
433 }
434
435 mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
436 --i;
437 }
438}
439
440void FrameTimeline::finalizeCurrentDisplayFrame() {
441 while (mDisplayFrames.size() >= kMaxDisplayFrames) {
442 // We maintain only a fixed number of frames' data. Pop older frames
443 mDisplayFrames.pop_front();
444 }
445 mDisplayFrames.push_back(mCurrentDisplayFrame);
446 mCurrentDisplayFrame.reset();
447 mCurrentDisplayFrame = std::make_shared<DisplayFrame>();
448}
449
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700450nsecs_t FrameTimeline::findBaseTime(const std::shared_ptr<DisplayFrame>& displayFrame) {
451 nsecs_t baseTime = std::numeric_limits<nsecs_t>::max();
452 if (displayFrame->predictionState == PredictionState::Valid) {
453 baseTime = std::min(baseTime, displayFrame->surfaceFlingerPredictions.startTime);
454 }
455 baseTime = std::min(baseTime, displayFrame->surfaceFlingerActuals.startTime);
456 for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
457 nsecs_t surfaceFrameBaseTime = surfaceFrame->getBaseTime();
458 if (surfaceFrameBaseTime != 0) {
459 baseTime = std::min(baseTime, surfaceFrameBaseTime);
460 }
461 }
462 return baseTime;
463}
464
465void FrameTimeline::dumpDisplayFrame(std::string& result,
466 const std::shared_ptr<DisplayFrame>& displayFrame,
467 nsecs_t baseTime) {
468 if (displayFrame->jankType != JankType::None) {
469 // Easily identify a janky Display Frame in the dump
470 StringAppendF(&result, " [*] ");
471 }
472 StringAppendF(&result, "\n");
473 StringAppendF(&result, "Prediction State : %s\n",
474 toString(displayFrame->predictionState).c_str());
475 StringAppendF(&result, "Jank Type : %s\n", toString(displayFrame->jankType).c_str());
476 StringAppendF(&result, "Jank Metadata: %s\n",
477 jankMetadataBitmaskToString(displayFrame->jankMetadata).c_str());
478 dumpTable(result, displayFrame->surfaceFlingerPredictions, displayFrame->surfaceFlingerActuals,
479 "", displayFrame->predictionState, baseTime);
480 StringAppendF(&result, "\n");
481 std::string indent = " "; // 4 spaces
482 for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
483 surfaceFrame->dump(result, indent, baseTime);
484 }
485 StringAppendF(&result, "\n");
486}
487void FrameTimeline::dumpAll(std::string& result) {
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700488 std::lock_guard<std::mutex> lock(mMutex);
489 StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700490 nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
491 for (size_t i = 0; i < mDisplayFrames.size(); i++) {
492 StringAppendF(&result, "Display Frame %d", static_cast<int>(i));
493 dumpDisplayFrame(result, mDisplayFrames[i], baseTime);
494 }
495}
496
497void FrameTimeline::dumpJank(std::string& result) {
498 std::lock_guard<std::mutex> lock(mMutex);
499 nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
500 for (size_t i = 0; i < mDisplayFrames.size(); i++) {
501 const auto& displayFrame = mDisplayFrames[i];
502 if (displayFrame->jankType == JankType::None) {
503 // Check if any Surface Frame has been janky
504 bool isJanky = false;
505 for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
506 if (surfaceFrame->getJankType() != JankType::None) {
507 isJanky = true;
508 break;
509 }
510 }
511 if (!isJanky) {
512 continue;
513 }
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700514 }
Adithya Srinivasan8fc601d2020-09-25 13:51:09 -0700515 StringAppendF(&result, "Display Frame %d", static_cast<int>(i));
516 dumpDisplayFrame(result, displayFrame, baseTime);
517 }
518}
519void FrameTimeline::parseArgs(const Vector<String16>& args, std::string& result) {
520 ATRACE_CALL();
521 std::unordered_map<std::string, bool> argsMap;
522 for (size_t i = 0; i < args.size(); i++) {
523 argsMap[std::string(String8(args[i]).c_str())] = true;
524 }
525 if (argsMap.count("-jank")) {
526 dumpJank(result);
527 }
528 if (argsMap.count("-all")) {
529 dumpAll(result);
Adithya Srinivasanf279e042020-08-17 14:56:27 -0700530 }
531}
532
533} // namespace android::frametimeline::impl