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

Commit e77c7669 authored by Dan Stoza's avatar Dan Stoza
Browse files

BufferQueue/SF: Add OccupancyTracker

Adds an OccupancyTracker to BufferQueue. This module keeps track of
how many buffers are in the queue over time, which, in combination
with various aggregation of these statistics, allows SurfaceFlinger
to report what fraction of the time a given layer was double- or
triple-buffered.

Change-Id: Ida6e967dc5483c00a633e9fe03998e420dd88502
parent 41132610
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -136,6 +136,10 @@ public:
    // Retrieve the sideband buffer stream, if any.
    virtual sp<NativeHandle> getSidebandStream() const;

    // See IGraphicBufferConsumer::getOccupancyHistory
    virtual status_t getOccupancyHistory(bool forceFlush,
            std::vector<OccupancyTracker::Segment>* outHistory) override;

    // dump our state in a String
    virtual void dump(String8& result, const char* prefix) const;

+3 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <gui/BufferItem.h>
#include <gui/BufferQueueDefs.h>
#include <gui/BufferSlot.h>
#include <gui/OccupancyTracker.h>

#include <utils/Condition.h>
#include <utils/Mutex.h>
@@ -322,6 +323,8 @@ private:
    // The slot of the last queued buffer
    int mLastQueuedSlot;

    OccupancyTracker mOccupancyTracker;

}; // class BufferQueueCore

} // namespace android
+4 −0
Original line number Diff line number Diff line
@@ -85,6 +85,10 @@ public:
    // See IGraphicBufferConsumer::setDefaultBufferDataSpace
    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);

    // See IGraphicBufferConsumer::getOccupancyHistory
    status_t getOccupancyHistory(bool forceFlush,
            std::vector<OccupancyTracker::Segment>* outHistory);

private:
    ConsumerBase(const ConsumerBase&);
    void operator=(const ConsumerBase&);
+7 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <binder/IInterface.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <gui/OccupancyTracker.h>

#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -265,6 +266,12 @@ public:
    // Retrieve the sideband buffer stream, if any.
    virtual sp<NativeHandle> getSidebandStream() const = 0;

    // Retrieves any stored segments of the occupancy history of this
    // BufferQueue and clears them. Optionally closes out the pending segment if
    // forceFlush is true.
    virtual status_t getOccupancyHistory(bool forceFlush,
            std::vector<OccupancyTracker::Segment>* outHistory) = 0;

    // dump state into a string
    virtual void dump(String8& result, const char* prefix) const = 0;

+104 −0
Original line number Diff line number Diff line
/*
 * Copyright 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#ifndef ANDROID_GUI_OCCUPANCYTRACKER_H
#define ANDROID_GUI_OCCUPANCYTRACKER_H

#include <binder/Parcelable.h>

#include <utils/Timers.h>

#include <deque>
#include <unordered_map>

namespace android {

class String8;

class OccupancyTracker
{
public:
    OccupancyTracker()
      : mPendingSegment(),
        mSegmentHistory(),
        mLastOccupancy(0),
        mLastOccupancyChangeTime(0) {}

    struct Segment : public Parcelable {
        Segment()
          : totalTime(0),
            numFrames(0),
            occupancyAverage(0.0f),
            usedThirdBuffer(false) {}

        Segment(nsecs_t totalTime, size_t numFrames, float occupancyAverage,
                bool usedThirdBuffer)
          : totalTime(totalTime),
            numFrames(numFrames),
            occupancyAverage(occupancyAverage),
            usedThirdBuffer(usedThirdBuffer) {}

        // Parcelable interface
        virtual status_t writeToParcel(Parcel* parcel) const override;
        virtual status_t readFromParcel(const Parcel* parcel) override;

        nsecs_t totalTime;
        size_t numFrames;

        // Average occupancy of the queue over this segment. (0.0, 1.0) implies
        // double-buffered, (1.0, 2.0) implies triple-buffered.
        float occupancyAverage;

        // Whether a third buffer was used at all during this segment (since a
        // segment could read as double-buffered on average, but still require a
        // third buffer to avoid jank for some smaller portion)
        bool usedThirdBuffer;
    };

    void registerOccupancyChange(size_t occupancy);
    std::vector<Segment> getSegmentHistory(bool forceFlush);

private:
    static constexpr size_t MAX_HISTORY_SIZE = 10;
    static constexpr nsecs_t NEW_SEGMENT_DELAY = ms2ns(100);
    static constexpr size_t LONG_SEGMENT_THRESHOLD = 3;

    struct PendingSegment {
        void clear() {
            totalTime = 0;
            numFrames = 0;
            mOccupancyTimes.clear();
        }

        nsecs_t totalTime;
        size_t numFrames;
        std::unordered_map<size_t, nsecs_t> mOccupancyTimes;
    };

    void recordPendingSegment();

    PendingSegment mPendingSegment;
    std::deque<Segment> mSegmentHistory;

    size_t mLastOccupancy;
    nsecs_t mLastOccupancyChangeTime;

}; // class OccupancyTracker

} // namespace android

#endif
Loading