Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01189678 authored by Adithya Srinivasan's avatar Adithya Srinivasan
Browse files

Frame Timeline Perfetto producer

This change adds a Perfetto Producer inside FrameTimeline that emits
DisplayFrame and SurfaceFrame as TracePackets as per the proto defined
in frame_timeline_event.proto
This change also adds a MockFrameTimeline to be used in unittests as a
part of TestableSurfaceFlinger. Due to perfetto capability, running
production FrameTimeline in TestableSurfaceFlinger has caused issues and
its best to isolate them.

Bug: 170914689
Test: libsurfaceflinger_unittest (whole test suite without filter)

Change-Id: Iabd5521629d16ded6ba3f165229caa74b1cb8eb7
parent 6df72d72
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -14,5 +14,8 @@ cc_library_static {
        "libui",
        "libutils",
    ],
    static_libs: [
        "libperfetto_client_experimental",
    ],
    export_include_dirs: ["."],
}
+124 −12
Original line number Diff line number Diff line
@@ -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) {
@@ -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);
@@ -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)),
@@ -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);
}

@@ -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());
}
@@ -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 {
@@ -408,6 +492,7 @@ void FrameTimeline::flushPendingPresentFences() {
            }

            totalJankReasons |= displayFrame->jankType;
            traceDisplayFrame(*displayFrame);

            for (auto& surfaceFrame : displayFrame->surfaceFrames) {
                if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
@@ -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();
@@ -453,6 +537,7 @@ void FrameTimeline::flushPendingPresentFences() {
                        surfaceFrame->setJankInfo(jankType, jankMetadata);
                    }
                }
                surfaceFrame->traceSurfaceFrame(displayFrame->token);
            }

            mTimeStats->incrementJankyFrames(totalJankReasons);
@@ -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
+42 −8
Original line number Diff line number Diff line
@@ -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>
@@ -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.
@@ -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; };
@@ -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; };
@@ -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;
@@ -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;

@@ -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;
@@ -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
@@ -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
    };
@@ -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>>>
@@ -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.
+2 −1
Original line number Diff line number Diff line
@@ -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)),
@@ -621,6 +621,7 @@ void SurfaceFlinger::bootFinished() {

    mFrameTracer->initialize();
    mTimeStats->onBootFinished();
    mFrameTimeline->onBootFinished();

    // wait patiently for the window manager death
    const String16 name("window");
+6 −0
Original line number Diff line number Diff line
@@ -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