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

Commit 75785929 authored by Alberto Gonzalez's avatar Alberto Gonzalez Committed by Android (Google) Code Review
Browse files

Merge "Record rendering stability histogram."

parents a473b272 9fe1451f
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include <algorithm>
#include <chrono>
#include <cmath>
#include <unordered_map>

#include "TimeStats.h"
@@ -180,6 +181,12 @@ bool TimeStats::populateLayerAtom(std::vector<uint8_t>* pulledData) {
            *atom->mutable_present_to_present() =
                    histogramToProto(present2PresentHist->second.hist, mMaxPulledHistogramBuckets);
        }
        const auto& present2PresentDeltaHist = layer->deltas.find("present2presentDelta");
        if (present2PresentDeltaHist != layer->deltas.cend()) {
            *atom->mutable_present_to_present_delta() =
                    histogramToProto(present2PresentDeltaHist->second.hist,
                                     mMaxPulledHistogramBuckets);
        }
        const auto& post2presentHist = layer->deltas.find("post2present");
        if (post2presentHist != layer->deltas.cend()) {
            *atom->mutable_post_to_present() =
@@ -452,6 +459,7 @@ void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayR

    LayerRecord& layerRecord = mTimeStatsTracker[layerId];
    TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
    std::optional<int32_t>& prevPresentToPresentMs = layerRecord.prevPresentToPresentMs;
    std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
    const int32_t refreshRateBucket =
            clampToNearestBucket(displayRefreshRate, REFRESH_RATE_BUCKET_WIDTH);
@@ -529,6 +537,12 @@ void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayR
            ALOGV("[%d]-[%" PRIu64 "]-present2present[%d]", layerId,
                  timeRecords[0].frameTime.frameNumber, presentToPresentMs);
            timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
            if (prevPresentToPresentMs) {
                const int32_t presentToPresentDeltaMs =
                        std::abs(presentToPresentMs - *prevPresentToPresentMs);
                timeStatsLayer.deltas["present2presentDelta"].insert(presentToPresentDeltaMs);
            }
            prevPresentToPresentMs = presentToPresentMs;
        }
        prevTimeRecord = timeRecords[0];
        timeRecords.pop_front();
+1 −0
Original line number Diff line number Diff line
@@ -219,6 +219,7 @@ class TimeStats : public android::TimeStats {
        uint32_t lateAcquireFrames = 0;
        uint32_t badDesiredPresentFrames = 0;
        TimeRecord prevTimeRecord;
        std::optional<int32_t> prevPresentToPresentMs;
        std::deque<TimeRecord> timeRecords;
    };

+5 −1
Original line number Diff line number Diff line
@@ -289,7 +289,11 @@ message SurfaceflingerStatsLayerInfo {
    // Introduced in Android 12.
    optional FrameTimingHistogram app_deadline_misses = 25;

    // Next ID: 27
    // Variability histogram of present_to_present timings.
    // Introduced in Android 14.
    optional FrameTimingHistogram present_to_present_delta = 27;

    // Next ID: 28
}

/**
+45 −2
Original line number Diff line number Diff line
@@ -44,11 +44,14 @@ namespace android {
namespace {

using testing::_;
using testing::AllOf;
using testing::AnyNumber;
using testing::Contains;
using testing::ElementsAre;
using testing::HasSubstr;
using testing::InSequence;
using testing::Not;
using testing::Property;
using testing::SizeIs;
using testing::StrEq;
using testing::UnorderedElementsAre;
@@ -645,7 +648,7 @@ TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));

    ASSERT_EQ(1, globalProto.stats_size());
    const SFTimeStatsLayerProto& layerProto = globalProto.stats().Get(0);
    const SFTimeStatsLayerProto& layerProto = globalProto.stats(0);
    ASSERT_TRUE(layerProto.has_layer_name());
    EXPECT_EQ(genLayerName(LAYER_ID_0), layerProto.layer_name());
    ASSERT_TRUE(layerProto.has_total_frames());
@@ -653,7 +656,7 @@ TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
    ASSERT_EQ(6, layerProto.deltas_size());
    for (const SFTimeStatsDeltaProto& deltaProto : layerProto.deltas()) {
        ASSERT_EQ(1, deltaProto.histograms_size());
        const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms().Get(0);
        const SFTimeStatsHistogramBucketProto& histogramProto = deltaProto.histograms(0);
        EXPECT_EQ(1, histogramProto.frame_count());
        if ("post2acquire" == deltaProto.delta_name()) {
            EXPECT_EQ(1, histogramProto.time_millis());
@@ -673,6 +676,46 @@ TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
    }
}

using LayerProto = SFTimeStatsLayerProto;
using DeltaProto = SFTimeStatsDeltaProto;
using BucketProto = SFTimeStatsHistogramBucketProto;

TEST_F(TimeStatsTest, canComputeLayerStabilityHistogram) {
    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());

    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000); // 0ms delta
    // Slightly unstable frames
    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000); // 1ms delta
    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 5, 6000000); // 1ms delta

    SFTimeStatsGlobalProto globalProto;
    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));

    EXPECT_THAT(globalProto.stats(),
                ElementsAre(AllOf(
                        Property(&LayerProto::layer_name, genLayerName(LAYER_ID_0)),
                        Property(&LayerProto::total_frames, 4),
                        Property(&LayerProto::deltas,
                                 Contains(AllOf(Property(&DeltaProto::delta_name,
                                                         "present2presentDelta"),
                                                Property(&DeltaProto::histograms,
                                                         UnorderedElementsAre(
                                                                 AllOf(Property(&BucketProto::
                                                                                        time_millis,
                                                                                0),
                                                                       Property(&BucketProto::
                                                                                        frame_count,
                                                                                1)),
                                                                 AllOf(Property(&BucketProto::
                                                                                        time_millis,
                                                                                1),
                                                                       Property(&BucketProto::
                                                                                        frame_count,
                                                                                2))))))))));
}

TEST_F(TimeStatsTest, canNotInsertInvalidLayerNameTimeStats) {
    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());