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

Commit 542de11c authored by Alec Mouri's avatar Alec Mouri
Browse files

[TimeStats] reduce aggregated stats size for shared timeline-based stats

Shared timeline tracks transaction-level jank, where a transaction is
not necessarily associated with a buffer. But, in general transactions
have debugging names that are not intended to be aggregated if there was
no buffer. E.g., they include things like hash codes, and systemui
generates a lot of different layer names (e.g., there is a separate
animation leash used per app on app launch).

As a workaround, to avoid needing to impose a restriction on all
transaction callers on layer names, we'll do the following:
* Layers that do not have buffers associated with them are collected
into a generic bucket keyed by the app uid, with a layer name == "none".
Because we enforce a minimum layer name, this is suitable as a default
choice for a layer name. This way we can continue to collect
transaction-level jank associated with things like animation leashes.
* Layers that already associated with buffers are collected as normal,
so as to preserve existing data fidelity.

Bug: 173018067
Bug: 171309796
Test: adb shell dumpsys SurfaceFlinger --timestats -enable
Test: adb shell dumpsys SurfaceFlinger --timestats -dump
Change-Id: I8fa57ac99de14f17464d6b5d6bb4d719bd7ad9a3
parent 7c3b12f1
Loading
Loading
Loading
Loading
+17 −13
Original line number Diff line number Diff line
@@ -716,23 +716,27 @@ void TimeStats::incrementJankyFrames(uid_t uid, const std::string& layerName, in
    ATRACE_CALL();
    std::lock_guard<std::mutex> lock(mMutex);

    // Only update layer stats if we're allowed to do so.
    // Only update layer stats if we're already tracking the layer in TimeStats.
    // Otherwise, continue tracking the statistic but use a default layer name instead.
    // As an implementation detail, we do this because this method is expected to be
    // called from FrameTimeline, which is allowed to do jank analysis well after a frame is
    // presented. This means that we can't rely on TimeStats to flush layer records over to the
    // aggregated stats.
    if (!canAddNewAggregatedStats(uid, layerName)) {
        return;
    }

    // Defensively initialize the stats in case FrameTimeline flushes its signaled present fences
    // before TimeStats does.
    // called from FrameTimeline, whose jank classification includes transaction jank
    // that occurs without a buffer. But, in general those layer names are not suitable as
    // aggregation keys: e.g., it's normal and expected for Window Manager to include the hash code
    // for an animation leash. So while we can show that jank in dumpsys, aggregating based on the
    // layer blows up the stats size, so as a workaround drop those stats. This assumes that
    // TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that
    // the first jank record is not dropped.

    bool useDefaultLayerKey = false;
    static const std::string kDefaultLayerName = "none";
    if (!mTimeStats.stats.count({uid, layerName})) {
        mTimeStats.stats[{uid, layerName}].uid = uid;
        mTimeStats.stats[{uid, layerName}].layerName = layerName;
        mTimeStats.stats[{uid, kDefaultLayerName}].uid = uid;
        mTimeStats.stats[{uid, kDefaultLayerName}].layerName = kDefaultLayerName;
        useDefaultLayerKey = true;
    }

    TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[{uid, layerName}];
    TimeStatsHelper::TimeStatsLayer& timeStatsLayer =
            mTimeStats.stats[{uid, useDefaultLayerKey ? kDefaultLayerName : layerName}];
    updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, reasons);
}