Loading services/surfaceflinger/FrameTimeline/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -14,5 +14,8 @@ cc_library_static { "libui", "libutils", ], static_libs: [ "libperfetto_client_experimental", ], export_include_dirs: ["."], } services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +124 −12 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ namespace android::frametimeline::impl { using base::StringAppendF; using FrameTimelineEvent = perfetto::protos::pbzero::FrameTimelineEvent; void dumpTable(std::string& result, TimelineItem predictions, TimelineItem actuals, const std::string& indent, PredictionState predictionState, nsecs_t baseTime) { Loading Loading @@ -143,6 +144,32 @@ std::string jankMetadataBitmaskToString(int32_t jankMetadata) { }); } FrameTimelineEvent::PresentType presentTypeToProto(int32_t jankMetadata) { if (jankMetadata & EarlyPresent) { return FrameTimelineEvent::PRESENT_EARLY; } if (jankMetadata & LatePresent) { return FrameTimelineEvent::PRESENT_LATE; } return FrameTimelineEvent::PRESENT_ON_TIME; } FrameTimelineEvent::JankType JankTypeToProto(TimeStats::JankType jankType) { switch (jankType) { case TimeStats::None: return FrameTimelineEvent::JANK_NONE; case TimeStats::Display: return FrameTimelineEvent::JANK_DISPLAY_HAL; case TimeStats::SurfaceFlingerDeadlineMissed: return FrameTimelineEvent::JANK_SF_DEADLINE_MISSED; case TimeStats::AppDeadlineMissed: case TimeStats::PredictionExpired: return FrameTimelineEvent::JANK_APP_DEADLINE_MISSED; default: return FrameTimelineEvent::JANK_UNKNOWN; } } int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); Loading Loading @@ -177,10 +204,11 @@ void TokenManager::flushTokens(nsecs_t flushTime) { } } SurfaceFrame::SurfaceFrame(pid_t ownerPid, uid_t ownerUid, std::string layerName, SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName, PredictionState predictionState, frametimeline::TimelineItem&& predictions) : mOwnerPid(ownerPid), : mToken(token), mOwnerPid(ownerPid), mOwnerUid(ownerUid), mLayerName(std::move(layerName)), mDebugName(std::move(debugName)), Loading Loading @@ -291,17 +319,70 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime); } void SurfaceFrame::traceSurfaceFrame(int64_t displayFrameToken) { using FrameTimelineDataSource = FrameTimeline::FrameTimelineDataSource; FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { std::lock_guard<std::mutex> lock(mMutex); if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) { ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str()); return; } else if (displayFrameToken == ISurfaceComposer::INVALID_VSYNC_ID) { ALOGD("Cannot trace SurfaceFrame - %s with invalid displayFrameToken", mLayerName.c_str()); return; } auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(static_cast<uint64_t>(systemTime())); auto* event = packet->set_frame_timeline_event(); auto* surfaceFrameEvent = event->set_surface_frame(); surfaceFrameEvent->set_token(mToken); surfaceFrameEvent->set_display_frame_token(displayFrameToken); if (mPresentState == PresentState::Dropped) { surfaceFrameEvent->set_present_type(FrameTimelineEvent::PRESENT_DROPPED); } else if (mPresentState == PresentState::Unknown) { surfaceFrameEvent->set_present_type(FrameTimelineEvent::PRESENT_UNSPECIFIED); } else { surfaceFrameEvent->set_present_type(presentTypeToProto(mJankMetadata)); } surfaceFrameEvent->set_on_time_finish(!(mJankMetadata & LateFinish)); surfaceFrameEvent->set_gpu_composition(mJankMetadata & GpuComposition); surfaceFrameEvent->set_jank_type(JankTypeToProto(mJankType)); surfaceFrameEvent->set_expected_start_ns(mPredictions.startTime); surfaceFrameEvent->set_expected_end_ns(mPredictions.endTime); surfaceFrameEvent->set_actual_start_ns(mActuals.startTime); surfaceFrameEvent->set_actual_end_ns(mActuals.endTime); surfaceFrameEvent->set_layer_name(mDebugName); surfaceFrameEvent->set_pid(mOwnerPid); }); } FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats) : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()), mMaxDisplayFrames(kDefaultMaxDisplayFrames), mTimeStats(std::move(timeStats)) {} void FrameTimeline::onBootFinished() { perfetto::TracingInitArgs args; args.backends = perfetto::kSystemBackend; perfetto::Tracing::Initialize(args); registerDataSource(); } void FrameTimeline::registerDataSource() { perfetto::DataSourceDescriptor dsd; dsd.set_name(kFrameTimelineDataSource); FrameTimelineDataSource::Register(dsd); } FrameTimeline::DisplayFrame::DisplayFrame() : surfaceFlingerPredictions(TimelineItem()), surfaceFlingerActuals(TimelineItem()), predictionState(PredictionState::None), jankType(TimeStats::JankType::None), jankMetadata(0) { : surfaceFlingerPredictions(TimelineItem()), surfaceFlingerActuals(TimelineItem()) { this->surfaceFrames.reserve(kNumSurfaceFramesInitial); } Loading @@ -310,17 +391,19 @@ std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfa std::optional<int64_t> token) { ATRACE_CALL(); if (!token) { return std::make_unique<impl::SurfaceFrame>(ownerPid, ownerUid, std::move(layerName), return std::make_unique<impl::SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid, ownerUid, std::move(layerName), std::move(debugName), PredictionState::None, TimelineItem()); } std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token); if (predictions) { return std::make_unique<impl::SurfaceFrame>(ownerPid, ownerUid, std::move(layerName), std::move(debugName), PredictionState::Valid, return std::make_unique<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName), std::move(debugName), PredictionState::Valid, std::move(*predictions)); } return std::make_unique<impl::SurfaceFrame>(ownerPid, ownerUid, std::move(layerName), return std::make_unique<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName), std::move(debugName), PredictionState::Expired, TimelineItem()); } Loading @@ -340,6 +423,7 @@ void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) { ATRACE_CALL(); const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token); std::lock_guard<std::mutex> lock(mMutex); mCurrentDisplayFrame->token = token; if (!prediction) { mCurrentDisplayFrame->predictionState = PredictionState::Expired; } else { Loading Loading @@ -408,6 +492,7 @@ void FrameTimeline::flushPendingPresentFences() { } totalJankReasons |= displayFrame->jankType; traceDisplayFrame(*displayFrame); for (auto& surfaceFrame : displayFrame->surfaceFrames) { if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) { Loading @@ -419,7 +504,6 @@ void FrameTimeline::flushPendingPresentFences() { if (predictionState == PredictionState::Expired) { // Jank analysis cannot be done on apps that don't use predictions surfaceFrame->setJankInfo(TimeStats::JankType::PredictionExpired, 0); continue; } else if (predictionState == PredictionState::Valid) { const auto& actuals = surfaceFrame->getActuals(); const auto& predictions = surfaceFrame->getPredictions(); Loading Loading @@ -453,6 +537,7 @@ void FrameTimeline::flushPendingPresentFences() { surfaceFrame->setJankInfo(jankType, jankMetadata); } } surfaceFrame->traceSurfaceFrame(displayFrame->token); } mTimeStats->incrementJankyFrames(totalJankReasons); Loading Loading @@ -569,4 +654,31 @@ void FrameTimeline::reset() { setMaxDisplayFrames(kDefaultMaxDisplayFrames); } void FrameTimeline::traceDisplayFrame(const DisplayFrame& displayFrame) { FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { if (displayFrame.token == ISurfaceComposer::INVALID_VSYNC_ID) { ALOGD("Cannot trace DisplayFrame with invalid token"); return; } auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(static_cast<uint64_t>(systemTime())); auto* event = packet->set_frame_timeline_event(); auto* displayFrameEvent = event->set_display_frame(); displayFrameEvent->set_token(displayFrame.token); displayFrameEvent->set_present_type(presentTypeToProto(displayFrame.jankMetadata)); displayFrameEvent->set_on_time_finish(!(displayFrame.jankMetadata & LateFinish)); displayFrameEvent->set_gpu_composition(displayFrame.jankMetadata & GpuComposition); displayFrameEvent->set_jank_type(JankTypeToProto(displayFrame.jankType)); displayFrameEvent->set_expected_start_ns(displayFrame.surfaceFlingerPredictions.startTime); displayFrameEvent->set_expected_end_ns(displayFrame.surfaceFlingerPredictions.endTime); displayFrameEvent->set_actual_start_ns(displayFrame.surfaceFlingerActuals.startTime); displayFrameEvent->set_actual_end_ns(displayFrame.surfaceFlingerActuals.endTime); }); } } // namespace android::frametimeline::impl services/surfaceflinger/FrameTimeline/FrameTimeline.h +42 −8 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ #include <../TimeStats/TimeStats.h> #include <gui/ISurfaceComposer.h> #include <perfetto/trace/android/frame_timeline_event.pbzero.h> #include <perfetto/tracing.h> #include <ui/FenceTime.h> #include <utils/RefBase.h> #include <utils/String16.h> Loading Loading @@ -128,6 +130,10 @@ public: virtual ~FrameTimeline() = default; virtual TokenManager* getTokenManager() = 0; // Initializes the Perfetto DataSource that emits DisplayFrame and SurfaceFrame events. Test // classes can avoid double registration by mocking this function. virtual void onBootFinished() = 0; // Create a new surface frame, set the predictions based on a token and return it to the caller. // Sets the PredictionState of SurfaceFrame. // Debug name is the human-readable debugging string for dumpsys. Loading Loading @@ -191,8 +197,9 @@ private: class SurfaceFrame : public android::frametimeline::SurfaceFrame { public: SurfaceFrame(pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName, PredictionState predictionState, TimelineItem&& predictions); SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName, PredictionState predictionState, TimelineItem&& predictions); ~SurfaceFrame() = default; TimelineItem getPredictions() const override { return mPredictions; }; Loading @@ -202,6 +209,7 @@ public: PredictionState getPredictionState() const override { return mPredictionState; }; pid_t getOwnerPid() const override { return mOwnerPid; }; TimeStats::JankType getJankType() const; int64_t getToken() const { return mToken; }; nsecs_t getBaseTime() const; uid_t getOwnerUid() const { return mOwnerUid; }; const std::string& getName() const { return mLayerName; }; Loading @@ -216,7 +224,13 @@ public: // All the timestamps are dumped relative to the baseTime void dump(std::string& result, const std::string& indent, nsecs_t baseTime); // Emits a packet for perfetto tracing. The function body will be executed only if tracing is // enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding // DisplayFrame at the trace processor side. void traceSurfaceFrame(int64_t displayFrameToken); private: const int64_t mToken; const pid_t mOwnerPid; const uid_t mOwnerUid; const std::string mLayerName; Loading @@ -233,6 +247,12 @@ private: class FrameTimeline : public android::frametimeline::FrameTimeline { public: class FrameTimelineDataSource : public perfetto::DataSource<FrameTimelineDataSource> { void OnSetup(const SetupArgs&) override{}; void OnStart(const StartArgs&) override{}; void OnStop(const StopArgs&) override{}; }; FrameTimeline(std::shared_ptr<TimeStats> timeStats); ~FrameTimeline() = default; Loading @@ -249,6 +269,14 @@ public: void setMaxDisplayFrames(uint32_t size) override; void reset() override; // Sets up the perfetto tracing backend and data source. void onBootFinished() override; // Registers the data source with the perfetto backend. Called as part of onBootFinished() // and should not be called manually outside of tests. void registerDataSource(); static constexpr char kFrameTimelineDataSource[] = "android.surfaceflinger.frametimeline"; private: // Friend class for testing friend class android::frametimeline::FrameTimelineTest; Loading @@ -259,6 +287,8 @@ private: struct DisplayFrame { DisplayFrame(); int64_t token = ISurfaceComposer::INVALID_VSYNC_ID; /* Usage of TimelineItem w.r.t SurfaceFlinger * startTime Time when SurfaceFlinger wakes up to handle transactions and buffer updates * endTime Time when SurfaceFlinger sends a composited frame to Display Loading @@ -270,7 +300,7 @@ private: // Collection of predictions and actual values sent over by Layers std::vector<std::unique_ptr<SurfaceFrame>> surfaceFrames; PredictionState predictionState; PredictionState predictionState = PredictionState::None; TimeStats::JankType jankType = TimeStats::JankType::None; // Enum for the type of jank int32_t jankMetadata = 0x0; // Additional details about the jank }; Loading @@ -285,6 +315,10 @@ private: void dumpAll(std::string& result); void dumpJank(std::string& result); // Emits a packet for perfetto tracing. The function body will be executed only if tracing is // enabled. void traceDisplayFrame(const DisplayFrame& displayFrame) REQUIRES(mMutex); // Sliding window of display frames. TODO(b/168072834): compare perf with fixed size array std::deque<std::shared_ptr<DisplayFrame>> mDisplayFrames GUARDED_BY(mMutex); std::vector<std::pair<std::shared_ptr<FenceTime>, std::shared_ptr<DisplayFrame>>> Loading @@ -295,10 +329,10 @@ private: uint32_t mMaxDisplayFrames; std::shared_ptr<TimeStats> mTimeStats; static constexpr uint32_t kDefaultMaxDisplayFrames = 64; // The initial container size for the vector<SurfaceFrames> inside display frame. Although this // number doesn't represent any bounds on the number of surface frames that can go in a display // frame, this is a good starting size for the vector so that we can avoid the internal vector // resizing that happens with push_back. // The initial container size for the vector<SurfaceFrames> inside display frame. Although // this number doesn't represent any bounds on the number of surface frames that can go in a // display frame, this is a good starting size for the vector so that we can avoid the // internal vector resizing that happens with push_back. static constexpr uint32_t kNumSurfaceFramesInitial = 10; // The various thresholds for App and SF. If the actual timestamp falls within the threshold // compared to prediction, we don't treat it as a jank. Loading services/surfaceflinger/SurfaceFlinger.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -331,7 +331,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mInterceptor(mFactory.createSurfaceInterceptor()), mTimeStats(std::make_shared<impl::TimeStats>()), mFrameTracer(mFactory.createFrameTracer()), mFrameTimeline(std::make_unique<frametimeline::impl::FrameTimeline>(mTimeStats)), mFrameTimeline(mFactory.createFrameTimeline(mTimeStats)), mEventQueue(mFactory.createMessageQueue()), mCompositionEngine(mFactory.createCompositionEngine()), mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)), Loading Loading @@ -621,6 +621,7 @@ void SurfaceFlinger::bootFinished() { mFrameTracer->initialize(); mTimeStats->onBootFinished(); mFrameTimeline->onBootFinished(); // wait patiently for the window manager death const String16 name("window"); Loading services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -134,6 +134,12 @@ sp<EffectLayer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) std::unique_ptr<FrameTracer> DefaultFactory::createFrameTracer() { return std::make_unique<FrameTracer>(); } std::unique_ptr<frametimeline::FrameTimeline> DefaultFactory::createFrameTimeline( std::shared_ptr<TimeStats> timeStats) { return std::make_unique<frametimeline::impl::FrameTimeline>(timeStats); } } // namespace android::surfaceflinger // TODO(b/129481165): remove the #pragma below and fix conversion issues Loading Loading
services/surfaceflinger/FrameTimeline/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -14,5 +14,8 @@ cc_library_static { "libui", "libutils", ], static_libs: [ "libperfetto_client_experimental", ], export_include_dirs: ["."], }
services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +124 −12 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ namespace android::frametimeline::impl { using base::StringAppendF; using FrameTimelineEvent = perfetto::protos::pbzero::FrameTimelineEvent; void dumpTable(std::string& result, TimelineItem predictions, TimelineItem actuals, const std::string& indent, PredictionState predictionState, nsecs_t baseTime) { Loading Loading @@ -143,6 +144,32 @@ std::string jankMetadataBitmaskToString(int32_t jankMetadata) { }); } FrameTimelineEvent::PresentType presentTypeToProto(int32_t jankMetadata) { if (jankMetadata & EarlyPresent) { return FrameTimelineEvent::PRESENT_EARLY; } if (jankMetadata & LatePresent) { return FrameTimelineEvent::PRESENT_LATE; } return FrameTimelineEvent::PRESENT_ON_TIME; } FrameTimelineEvent::JankType JankTypeToProto(TimeStats::JankType jankType) { switch (jankType) { case TimeStats::None: return FrameTimelineEvent::JANK_NONE; case TimeStats::Display: return FrameTimelineEvent::JANK_DISPLAY_HAL; case TimeStats::SurfaceFlingerDeadlineMissed: return FrameTimelineEvent::JANK_SF_DEADLINE_MISSED; case TimeStats::AppDeadlineMissed: case TimeStats::PredictionExpired: return FrameTimelineEvent::JANK_APP_DEADLINE_MISSED; default: return FrameTimelineEvent::JANK_UNKNOWN; } } int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); Loading Loading @@ -177,10 +204,11 @@ void TokenManager::flushTokens(nsecs_t flushTime) { } } SurfaceFrame::SurfaceFrame(pid_t ownerPid, uid_t ownerUid, std::string layerName, SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName, PredictionState predictionState, frametimeline::TimelineItem&& predictions) : mOwnerPid(ownerPid), : mToken(token), mOwnerPid(ownerPid), mOwnerUid(ownerUid), mLayerName(std::move(layerName)), mDebugName(std::move(debugName)), Loading Loading @@ -291,17 +319,70 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime); } void SurfaceFrame::traceSurfaceFrame(int64_t displayFrameToken) { using FrameTimelineDataSource = FrameTimeline::FrameTimelineDataSource; FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { std::lock_guard<std::mutex> lock(mMutex); if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) { ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str()); return; } else if (displayFrameToken == ISurfaceComposer::INVALID_VSYNC_ID) { ALOGD("Cannot trace SurfaceFrame - %s with invalid displayFrameToken", mLayerName.c_str()); return; } auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(static_cast<uint64_t>(systemTime())); auto* event = packet->set_frame_timeline_event(); auto* surfaceFrameEvent = event->set_surface_frame(); surfaceFrameEvent->set_token(mToken); surfaceFrameEvent->set_display_frame_token(displayFrameToken); if (mPresentState == PresentState::Dropped) { surfaceFrameEvent->set_present_type(FrameTimelineEvent::PRESENT_DROPPED); } else if (mPresentState == PresentState::Unknown) { surfaceFrameEvent->set_present_type(FrameTimelineEvent::PRESENT_UNSPECIFIED); } else { surfaceFrameEvent->set_present_type(presentTypeToProto(mJankMetadata)); } surfaceFrameEvent->set_on_time_finish(!(mJankMetadata & LateFinish)); surfaceFrameEvent->set_gpu_composition(mJankMetadata & GpuComposition); surfaceFrameEvent->set_jank_type(JankTypeToProto(mJankType)); surfaceFrameEvent->set_expected_start_ns(mPredictions.startTime); surfaceFrameEvent->set_expected_end_ns(mPredictions.endTime); surfaceFrameEvent->set_actual_start_ns(mActuals.startTime); surfaceFrameEvent->set_actual_end_ns(mActuals.endTime); surfaceFrameEvent->set_layer_name(mDebugName); surfaceFrameEvent->set_pid(mOwnerPid); }); } FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats) : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()), mMaxDisplayFrames(kDefaultMaxDisplayFrames), mTimeStats(std::move(timeStats)) {} void FrameTimeline::onBootFinished() { perfetto::TracingInitArgs args; args.backends = perfetto::kSystemBackend; perfetto::Tracing::Initialize(args); registerDataSource(); } void FrameTimeline::registerDataSource() { perfetto::DataSourceDescriptor dsd; dsd.set_name(kFrameTimelineDataSource); FrameTimelineDataSource::Register(dsd); } FrameTimeline::DisplayFrame::DisplayFrame() : surfaceFlingerPredictions(TimelineItem()), surfaceFlingerActuals(TimelineItem()), predictionState(PredictionState::None), jankType(TimeStats::JankType::None), jankMetadata(0) { : surfaceFlingerPredictions(TimelineItem()), surfaceFlingerActuals(TimelineItem()) { this->surfaceFrames.reserve(kNumSurfaceFramesInitial); } Loading @@ -310,17 +391,19 @@ std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfa std::optional<int64_t> token) { ATRACE_CALL(); if (!token) { return std::make_unique<impl::SurfaceFrame>(ownerPid, ownerUid, std::move(layerName), return std::make_unique<impl::SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid, ownerUid, std::move(layerName), std::move(debugName), PredictionState::None, TimelineItem()); } std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token); if (predictions) { return std::make_unique<impl::SurfaceFrame>(ownerPid, ownerUid, std::move(layerName), std::move(debugName), PredictionState::Valid, return std::make_unique<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName), std::move(debugName), PredictionState::Valid, std::move(*predictions)); } return std::make_unique<impl::SurfaceFrame>(ownerPid, ownerUid, std::move(layerName), return std::make_unique<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName), std::move(debugName), PredictionState::Expired, TimelineItem()); } Loading @@ -340,6 +423,7 @@ void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) { ATRACE_CALL(); const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token); std::lock_guard<std::mutex> lock(mMutex); mCurrentDisplayFrame->token = token; if (!prediction) { mCurrentDisplayFrame->predictionState = PredictionState::Expired; } else { Loading Loading @@ -408,6 +492,7 @@ void FrameTimeline::flushPendingPresentFences() { } totalJankReasons |= displayFrame->jankType; traceDisplayFrame(*displayFrame); for (auto& surfaceFrame : displayFrame->surfaceFrames) { if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) { Loading @@ -419,7 +504,6 @@ void FrameTimeline::flushPendingPresentFences() { if (predictionState == PredictionState::Expired) { // Jank analysis cannot be done on apps that don't use predictions surfaceFrame->setJankInfo(TimeStats::JankType::PredictionExpired, 0); continue; } else if (predictionState == PredictionState::Valid) { const auto& actuals = surfaceFrame->getActuals(); const auto& predictions = surfaceFrame->getPredictions(); Loading Loading @@ -453,6 +537,7 @@ void FrameTimeline::flushPendingPresentFences() { surfaceFrame->setJankInfo(jankType, jankMetadata); } } surfaceFrame->traceSurfaceFrame(displayFrame->token); } mTimeStats->incrementJankyFrames(totalJankReasons); Loading Loading @@ -569,4 +654,31 @@ void FrameTimeline::reset() { setMaxDisplayFrames(kDefaultMaxDisplayFrames); } void FrameTimeline::traceDisplayFrame(const DisplayFrame& displayFrame) { FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { if (displayFrame.token == ISurfaceComposer::INVALID_VSYNC_ID) { ALOGD("Cannot trace DisplayFrame with invalid token"); return; } auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(static_cast<uint64_t>(systemTime())); auto* event = packet->set_frame_timeline_event(); auto* displayFrameEvent = event->set_display_frame(); displayFrameEvent->set_token(displayFrame.token); displayFrameEvent->set_present_type(presentTypeToProto(displayFrame.jankMetadata)); displayFrameEvent->set_on_time_finish(!(displayFrame.jankMetadata & LateFinish)); displayFrameEvent->set_gpu_composition(displayFrame.jankMetadata & GpuComposition); displayFrameEvent->set_jank_type(JankTypeToProto(displayFrame.jankType)); displayFrameEvent->set_expected_start_ns(displayFrame.surfaceFlingerPredictions.startTime); displayFrameEvent->set_expected_end_ns(displayFrame.surfaceFlingerPredictions.endTime); displayFrameEvent->set_actual_start_ns(displayFrame.surfaceFlingerActuals.startTime); displayFrameEvent->set_actual_end_ns(displayFrame.surfaceFlingerActuals.endTime); }); } } // namespace android::frametimeline::impl
services/surfaceflinger/FrameTimeline/FrameTimeline.h +42 −8 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ #include <../TimeStats/TimeStats.h> #include <gui/ISurfaceComposer.h> #include <perfetto/trace/android/frame_timeline_event.pbzero.h> #include <perfetto/tracing.h> #include <ui/FenceTime.h> #include <utils/RefBase.h> #include <utils/String16.h> Loading Loading @@ -128,6 +130,10 @@ public: virtual ~FrameTimeline() = default; virtual TokenManager* getTokenManager() = 0; // Initializes the Perfetto DataSource that emits DisplayFrame and SurfaceFrame events. Test // classes can avoid double registration by mocking this function. virtual void onBootFinished() = 0; // Create a new surface frame, set the predictions based on a token and return it to the caller. // Sets the PredictionState of SurfaceFrame. // Debug name is the human-readable debugging string for dumpsys. Loading Loading @@ -191,8 +197,9 @@ private: class SurfaceFrame : public android::frametimeline::SurfaceFrame { public: SurfaceFrame(pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName, PredictionState predictionState, TimelineItem&& predictions); SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName, PredictionState predictionState, TimelineItem&& predictions); ~SurfaceFrame() = default; TimelineItem getPredictions() const override { return mPredictions; }; Loading @@ -202,6 +209,7 @@ public: PredictionState getPredictionState() const override { return mPredictionState; }; pid_t getOwnerPid() const override { return mOwnerPid; }; TimeStats::JankType getJankType() const; int64_t getToken() const { return mToken; }; nsecs_t getBaseTime() const; uid_t getOwnerUid() const { return mOwnerUid; }; const std::string& getName() const { return mLayerName; }; Loading @@ -216,7 +224,13 @@ public: // All the timestamps are dumped relative to the baseTime void dump(std::string& result, const std::string& indent, nsecs_t baseTime); // Emits a packet for perfetto tracing. The function body will be executed only if tracing is // enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding // DisplayFrame at the trace processor side. void traceSurfaceFrame(int64_t displayFrameToken); private: const int64_t mToken; const pid_t mOwnerPid; const uid_t mOwnerUid; const std::string mLayerName; Loading @@ -233,6 +247,12 @@ private: class FrameTimeline : public android::frametimeline::FrameTimeline { public: class FrameTimelineDataSource : public perfetto::DataSource<FrameTimelineDataSource> { void OnSetup(const SetupArgs&) override{}; void OnStart(const StartArgs&) override{}; void OnStop(const StopArgs&) override{}; }; FrameTimeline(std::shared_ptr<TimeStats> timeStats); ~FrameTimeline() = default; Loading @@ -249,6 +269,14 @@ public: void setMaxDisplayFrames(uint32_t size) override; void reset() override; // Sets up the perfetto tracing backend and data source. void onBootFinished() override; // Registers the data source with the perfetto backend. Called as part of onBootFinished() // and should not be called manually outside of tests. void registerDataSource(); static constexpr char kFrameTimelineDataSource[] = "android.surfaceflinger.frametimeline"; private: // Friend class for testing friend class android::frametimeline::FrameTimelineTest; Loading @@ -259,6 +287,8 @@ private: struct DisplayFrame { DisplayFrame(); int64_t token = ISurfaceComposer::INVALID_VSYNC_ID; /* Usage of TimelineItem w.r.t SurfaceFlinger * startTime Time when SurfaceFlinger wakes up to handle transactions and buffer updates * endTime Time when SurfaceFlinger sends a composited frame to Display Loading @@ -270,7 +300,7 @@ private: // Collection of predictions and actual values sent over by Layers std::vector<std::unique_ptr<SurfaceFrame>> surfaceFrames; PredictionState predictionState; PredictionState predictionState = PredictionState::None; TimeStats::JankType jankType = TimeStats::JankType::None; // Enum for the type of jank int32_t jankMetadata = 0x0; // Additional details about the jank }; Loading @@ -285,6 +315,10 @@ private: void dumpAll(std::string& result); void dumpJank(std::string& result); // Emits a packet for perfetto tracing. The function body will be executed only if tracing is // enabled. void traceDisplayFrame(const DisplayFrame& displayFrame) REQUIRES(mMutex); // Sliding window of display frames. TODO(b/168072834): compare perf with fixed size array std::deque<std::shared_ptr<DisplayFrame>> mDisplayFrames GUARDED_BY(mMutex); std::vector<std::pair<std::shared_ptr<FenceTime>, std::shared_ptr<DisplayFrame>>> Loading @@ -295,10 +329,10 @@ private: uint32_t mMaxDisplayFrames; std::shared_ptr<TimeStats> mTimeStats; static constexpr uint32_t kDefaultMaxDisplayFrames = 64; // The initial container size for the vector<SurfaceFrames> inside display frame. Although this // number doesn't represent any bounds on the number of surface frames that can go in a display // frame, this is a good starting size for the vector so that we can avoid the internal vector // resizing that happens with push_back. // The initial container size for the vector<SurfaceFrames> inside display frame. Although // this number doesn't represent any bounds on the number of surface frames that can go in a // display frame, this is a good starting size for the vector so that we can avoid the // internal vector resizing that happens with push_back. static constexpr uint32_t kNumSurfaceFramesInitial = 10; // The various thresholds for App and SF. If the actual timestamp falls within the threshold // compared to prediction, we don't treat it as a jank. Loading
services/surfaceflinger/SurfaceFlinger.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -331,7 +331,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mInterceptor(mFactory.createSurfaceInterceptor()), mTimeStats(std::make_shared<impl::TimeStats>()), mFrameTracer(mFactory.createFrameTracer()), mFrameTimeline(std::make_unique<frametimeline::impl::FrameTimeline>(mTimeStats)), mFrameTimeline(mFactory.createFrameTimeline(mTimeStats)), mEventQueue(mFactory.createMessageQueue()), mCompositionEngine(mFactory.createCompositionEngine()), mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)), Loading Loading @@ -621,6 +621,7 @@ void SurfaceFlinger::bootFinished() { mFrameTracer->initialize(); mTimeStats->onBootFinished(); mFrameTimeline->onBootFinished(); // wait patiently for the window manager death const String16 name("window"); Loading
services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -134,6 +134,12 @@ sp<EffectLayer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) std::unique_ptr<FrameTracer> DefaultFactory::createFrameTracer() { return std::make_unique<FrameTracer>(); } std::unique_ptr<frametimeline::FrameTimeline> DefaultFactory::createFrameTimeline( std::shared_ptr<TimeStats> timeStats) { return std::make_unique<frametimeline::impl::FrameTimeline>(timeStats); } } // namespace android::surfaceflinger // TODO(b/129481165): remove the #pragma below and fix conversion issues Loading