Expose shared timeline counters into telemetry:
* Add UID into both shared timeline and timestats tracking: due to BLAST
APIs, layer name is insufficient for identifying applications
* Plumb through jank counters from shared timeline into timestats and WW
* Fixed bug where SurfaceflingerDeadlineMissed was not being tracked.
One caveat is that transactions are tracked in shared timeline, so as
a consequence timestats will start tracking them as well.
Bug: 171309796
Test: builds, boots
Test: statsd_testdrive
Test: libsurfacefinger_unittest
Test: dumpsys SurfaceFlinger --timestats -dump
Change-Id: I71057c0976ce81bbb605e126cb30b9d6f06c5873
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 43176a3..996479c 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -93,19 +93,19 @@
}
}
-std::string toString(JankType jankType) {
+std::string toString(TimeStats::JankType jankType) {
switch (jankType) {
- case JankType::None:
+ case TimeStats::JankType::None:
return "None";
- case JankType::Display:
+ case TimeStats::JankType::Display:
return "Composer/Display - outside SF and App";
- case JankType::SurfaceFlingerDeadlineMissed:
+ case TimeStats::JankType::SurfaceFlingerDeadlineMissed:
return "SurfaceFlinger Deadline Missed";
- case JankType::AppDeadlineMissed:
+ case TimeStats::JankType::AppDeadlineMissed:
return "App Deadline Missed";
- case JankType::PredictionExpired:
+ case TimeStats::JankType::PredictionExpired:
return "Prediction Expired";
- case JankType::SurfaceFlingerEarlyLatch:
+ case TimeStats::JankType::SurfaceFlingerEarlyLatch:
return "SurfaceFlinger Early Latch";
default:
return "Unclassified";
@@ -177,15 +177,18 @@
}
}
-SurfaceFrame::SurfaceFrame(const std::string& layerName, PredictionState predictionState,
+SurfaceFrame::SurfaceFrame(uid_t ownerUid, std::string layerName, std::string debugName,
+ PredictionState predictionState,
frametimeline::TimelineItem&& predictions)
- : mLayerName(layerName),
+ : mOwnerUid(ownerUid),
+ mLayerName(std::move(layerName)),
+ mDebugName(std::move(debugName)),
mPresentState(PresentState::Unknown),
mPredictionState(predictionState),
mPredictions(predictions),
mActuals({0, 0, 0}),
mActualQueueTime(0),
- mJankType(JankType::None),
+ mJankType(TimeStats::JankType::None),
mJankMetadata(0) {}
void SurfaceFrame::setPresentState(PresentState state) {
@@ -227,17 +230,25 @@
mActuals.presentTime = presentTime;
}
-void SurfaceFrame::setJankInfo(JankType jankType, int32_t jankMetadata) {
+void SurfaceFrame::setJankInfo(TimeStats::JankType jankType, int32_t jankMetadata) {
std::lock_guard<std::mutex> lock(mMutex);
mJankType = jankType;
mJankMetadata = jankMetadata;
}
-JankType SurfaceFrame::getJankType() const {
+TimeStats::JankType SurfaceFrame::getJankType() const {
std::lock_guard<std::mutex> lock(mMutex);
return mJankType;
}
+uid_t SurfaceFrame::getOwnerUid() const {
+ return mOwnerUid;
+}
+
+const std::string& SurfaceFrame::getName() const {
+ return mLayerName;
+}
+
nsecs_t SurfaceFrame::getBaseTime() const {
std::lock_guard<std::mutex> lock(mMutex);
nsecs_t baseTime = std::numeric_limits<nsecs_t>::max();
@@ -267,8 +278,8 @@
void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) {
std::lock_guard<std::mutex> lock(mMutex);
StringAppendF(&result, "%s", indent.c_str());
- StringAppendF(&result, "Layer - %s", mLayerName.c_str());
- if (mJankType != JankType::None) {
+ StringAppendF(&result, "Layer - %s", mDebugName.c_str());
+ if (mJankType != TimeStats::JankType::None) {
// Easily identify a janky Surface Frame in the dump
StringAppendF(&result, " [*] ");
}
@@ -285,33 +296,35 @@
dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
}
-FrameTimeline::FrameTimeline()
+FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats)
: mCurrentDisplayFrame(std::make_shared<DisplayFrame>()),
- mMaxDisplayFrames(kDefaultMaxDisplayFrames) {}
+ mMaxDisplayFrames(kDefaultMaxDisplayFrames),
+ mTimeStats(std::move(timeStats)) {}
FrameTimeline::DisplayFrame::DisplayFrame()
: surfaceFlingerPredictions(TimelineItem()),
surfaceFlingerActuals(TimelineItem()),
predictionState(PredictionState::None),
- jankType(JankType::None),
+ jankType(TimeStats::JankType::None),
jankMetadata(0) {
this->surfaceFrames.reserve(kNumSurfaceFramesInitial);
}
std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
- const std::string& layerName, std::optional<int64_t> token) {
+ uid_t uid, std::string layerName, std::string debugName, std::optional<int64_t> token) {
ATRACE_CALL();
if (!token) {
- return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None,
- TimelineItem());
+ return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName),
+ PredictionState::None, TimelineItem());
}
std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
if (predictions) {
- return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Valid,
+ return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName),
+ PredictionState::Valid,
std::move(*predictions));
}
- return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Expired,
- TimelineItem());
+ return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName),
+ PredictionState::Expired, TimelineItem());
}
void FrameTimeline::addSurfaceFrame(
@@ -359,6 +372,7 @@
}
}
if (signalTime != Fence::SIGNAL_TIME_INVALID) {
+ int32_t totalJankReasons = TimeStats::JankType::None;
auto& displayFrame = pendingPresentFence.second;
displayFrame->surfaceFlingerActuals.presentTime = signalTime;
@@ -377,21 +391,26 @@
displayFrame->jankMetadata |= EarlyFinish;
}
- if (displayFrame->jankMetadata & EarlyFinish & EarlyPresent) {
- displayFrame->jankType = JankType::SurfaceFlingerEarlyLatch;
- } else if (displayFrame->jankMetadata & LateFinish & LatePresent) {
- displayFrame->jankType = JankType::SurfaceFlingerDeadlineMissed;
+ if ((displayFrame->jankMetadata & EarlyFinish) &&
+ (displayFrame->jankMetadata & EarlyPresent)) {
+ displayFrame->jankType = TimeStats::JankType::SurfaceFlingerEarlyLatch;
+ } else if ((displayFrame->jankMetadata & LateFinish) &&
+ (displayFrame->jankMetadata & LatePresent)) {
+ displayFrame->jankType = TimeStats::JankType::SurfaceFlingerDeadlineMissed;
} else if (displayFrame->jankMetadata & EarlyPresent ||
displayFrame->jankMetadata & LatePresent) {
// Cases where SF finished early but frame was presented late and vice versa
- displayFrame->jankType = JankType::Display;
+ displayFrame->jankType = TimeStats::JankType::Display;
}
}
+
if (std::abs(sfActuals.startTime - sfPredictions.startTime) > kSFStartThreshold) {
displayFrame->jankMetadata |=
sfActuals.startTime > sfPredictions.startTime ? LateStart : EarlyStart;
}
+ totalJankReasons |= displayFrame->jankType;
+
for (auto& surfaceFrame : displayFrame->surfaceFrames) {
if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
// Only presented SurfaceFrames need to be updated
@@ -401,13 +420,13 @@
const auto& predictionState = surfaceFrame->getPredictionState();
if (predictionState == PredictionState::Expired) {
// Jank analysis cannot be done on apps that don't use predictions
- surfaceFrame->setJankInfo(JankType::PredictionExpired, 0);
+ surfaceFrame->setJankInfo(TimeStats::JankType::PredictionExpired, 0);
continue;
} else if (predictionState == PredictionState::Valid) {
const auto& actuals = surfaceFrame->getActuals();
const auto& predictions = surfaceFrame->getPredictions();
int32_t jankMetadata = 0;
- JankType jankType = JankType::None;
+ TimeStats::JankType jankType = TimeStats::JankType::None;
if (std::abs(actuals.endTime - predictions.endTime) > kDeadlineThreshold) {
jankMetadata |= actuals.endTime > predictions.endTime ? LateFinish
: EarlyFinish;
@@ -419,19 +438,26 @@
: EarlyPresent;
}
if (jankMetadata & EarlyPresent) {
- jankType = JankType::SurfaceFlingerEarlyLatch;
+ jankType = TimeStats::JankType::SurfaceFlingerEarlyLatch;
} else if (jankMetadata & LatePresent) {
if (jankMetadata & EarlyFinish) {
// TODO(b/169890654): Classify this properly
- jankType = JankType::Display;
+ jankType = TimeStats::JankType::Display;
} else {
- jankType = JankType::AppDeadlineMissed;
+ jankType = TimeStats::JankType::AppDeadlineMissed;
}
}
+
+ totalJankReasons |= jankType;
+ mTimeStats->incrementJankyFrames(surfaceFrame->getOwnerUid(),
+ surfaceFrame->getName(),
+ jankType | displayFrame->jankType);
surfaceFrame->setJankInfo(jankType, jankMetadata);
}
}
}
+
+ mTimeStats->incrementJankyFrames(totalJankReasons);
}
mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
@@ -467,7 +493,7 @@
void FrameTimeline::dumpDisplayFrame(std::string& result,
const std::shared_ptr<DisplayFrame>& displayFrame,
nsecs_t baseTime) {
- if (displayFrame->jankType != JankType::None) {
+ if (displayFrame->jankType != TimeStats::JankType::None) {
// Easily identify a janky Display Frame in the dump
StringAppendF(&result, " [*] ");
}
@@ -501,11 +527,11 @@
nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
for (size_t i = 0; i < mDisplayFrames.size(); i++) {
const auto& displayFrame = mDisplayFrames[i];
- if (displayFrame->jankType == JankType::None) {
+ if (displayFrame->jankType == TimeStats::JankType::None) {
// Check if any Surface Frame has been janky
bool isJanky = false;
for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
- if (surfaceFrame->getJankType() != JankType::None) {
+ if (surfaceFrame->getJankType() != TimeStats::JankType::None) {
isJanky = true;
break;
}