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

Commit 6547ff43 authored by Jamie Gennis's avatar Jamie Gennis
Browse files

surfaceflinger: add frame duration logging

Change-Id: Ib414a45e7e191f23a2726cbbbeb606e9ce68a3b5
parent bdce8170
Loading
Loading
Loading
Loading
+11 −6
Original line number Original line Diff line number Diff line
@@ -31,17 +31,22 @@ ANDROID_SINGLETON_STATIC_INSTANCE(EventLog)
EventLog::EventLog() {
EventLog::EventLog() {
}
}


void EventLog::doLogJank(const String8& window, int32_t value) {
void EventLog::doLogFrameDurations(const String8& window,
    EventLog::TagBuffer buffer(LOGTAG_SF_JANK);
        const int32_t* durations, size_t numDurations) {
    buffer.startList(2);
    EventLog::TagBuffer buffer(LOGTAG_SF_FRAME_DUR);
    buffer.startList(1 + numDurations);
    buffer.writeString8(window);
    buffer.writeString8(window);
    buffer.writeInt32(value);
    for (size_t i = 0; i < numDurations; i++) {
        buffer.writeInt32(durations[i]);
    }
    buffer.endList();
    buffer.endList();
    buffer.log();
    buffer.log();
}
}


void EventLog::logJank(const String8& window, int32_t value) {
void EventLog::logFrameDurations(const String8& window,
    EventLog::getInstance().doLogJank(window, value);
        const int32_t* durations, size_t numDurations) {
    EventLog::getInstance().doLogFrameDurations(window, durations,
            numDurations);
}
}


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
+5 −3
Original line number Original line Diff line number Diff line
@@ -30,7 +30,8 @@ class String8;
class EventLog : public Singleton<EventLog> {
class EventLog : public Singleton<EventLog> {


public:
public:
    static void logJank(const String8& window, int32_t value);
    static void logFrameDurations(const String8& window,
            const int32_t* durations, size_t numDurations);


protected:
protected:
    EventLog();
    EventLog();
@@ -72,8 +73,9 @@ private:
    EventLog(const EventLog&);
    EventLog(const EventLog&);
    EventLog& operator =(const EventLog&);
    EventLog& operator =(const EventLog&);


    enum { LOGTAG_SF_JANK = 60100 };
    enum { LOGTAG_SF_FRAME_DUR = 60100 };
    void doLogJank(const String8& window, int32_t value);
    void doLogFrameDurations(const String8& window, const int32_t* durations,
            size_t numDurations);
};
};


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
+5 −2
Original line number Original line Diff line number Diff line
@@ -30,9 +30,12 @@
# 5: Id
# 5: Id
# 6: Percent
# 6: Percent
# Default value for data of type int/long is 2 (bytes).
# Default value for data of type int/long is 2 (bytes).
#
# See system/core/logcat/event.logtags for the master copy of the tags.

# 60100 - 60199 reserved for surfaceflinger


# surfaceflinger
60100 sf_frame_dur (window|3),(dur0|1),(dur1|1),(dur2|1),(dur3|1),(dur4|1),(dur5|1),(dur6|1)
60100 sf_jank (window|3),(value|1)


# NOTE - the range 1000000-2000000 is reserved for partners and others who
# NOTE - the range 1000000-2000000 is reserved for partners and others who
# want to define their own log tags without conflicting with the core platform.
# want to define their own log tags without conflicting with the core platform.
+80 −1
Original line number Original line Diff line number Diff line
@@ -17,17 +17,22 @@
// This is needed for stdint.h to define INT64_MAX in C++
// This is needed for stdint.h to define INT64_MAX in C++
#define __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS


#include <cutils/log.h>

#include <ui/Fence.h>
#include <ui/Fence.h>


#include <utils/String8.h>
#include <utils/String8.h>


#include "FrameTracker.h"
#include "FrameTracker.h"
#include "EventLog/EventLog.h"


namespace android {
namespace android {


FrameTracker::FrameTracker() :
FrameTracker::FrameTracker() :
        mOffset(0),
        mOffset(0),
        mNumFences(0) {
        mNumFences(0),
        mDisplayPeriod(0) {
    resetFrameCountersLocked();
}
}


void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
@@ -57,8 +62,18 @@ void FrameTracker::setActualPresentFence(const sp<Fence>& readyFence) {
    mNumFences++;
    mNumFences++;
}
}


void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) {
    Mutex::Autolock lock(mMutex);
    mDisplayPeriod = displayPeriod;
}

void FrameTracker::advanceFrame() {
void FrameTracker::advanceFrame() {
    Mutex::Autolock lock(mMutex);
    Mutex::Autolock lock(mMutex);

    // Update the statistic to include the frame we just finished.
    updateStatsLocked(mOffset);

    // Advance to the next frame.
    mOffset = (mOffset+1) % NUM_FRAME_RECORDS;
    mOffset = (mOffset+1) % NUM_FRAME_RECORDS;
    mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
    mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
    mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
    mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
@@ -98,12 +113,19 @@ void FrameTracker::clear() {
    mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
    mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
}
}


void FrameTracker::logAndResetStats(const String8& name) {
    Mutex::Autolock lock(mMutex);
    logStatsLocked(name);
    resetFrameCountersLocked();
}

void FrameTracker::processFencesLocked() const {
void FrameTracker::processFencesLocked() const {
    FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords);
    FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords);
    int& numFences = const_cast<int&>(mNumFences);
    int& numFences = const_cast<int&>(mNumFences);


    for (int i = 1; i < NUM_FRAME_RECORDS && numFences > 0; i++) {
    for (int i = 1; i < NUM_FRAME_RECORDS && numFences > 0; i++) {
        size_t idx = (mOffset+NUM_FRAME_RECORDS-i) % NUM_FRAME_RECORDS;
        size_t idx = (mOffset+NUM_FRAME_RECORDS-i) % NUM_FRAME_RECORDS;
        bool updated = false;


        const sp<Fence>& rfence = records[idx].frameReadyFence;
        const sp<Fence>& rfence = records[idx].frameReadyFence;
        if (rfence != NULL) {
        if (rfence != NULL) {
@@ -111,6 +133,7 @@ void FrameTracker::processFencesLocked() const {
            if (records[idx].frameReadyTime < INT64_MAX) {
            if (records[idx].frameReadyTime < INT64_MAX) {
                records[idx].frameReadyFence = NULL;
                records[idx].frameReadyFence = NULL;
                numFences--;
                numFences--;
                updated = true;
            }
            }
        }
        }


@@ -120,9 +143,65 @@ void FrameTracker::processFencesLocked() const {
            if (records[idx].actualPresentTime < INT64_MAX) {
            if (records[idx].actualPresentTime < INT64_MAX) {
                records[idx].actualPresentFence = NULL;
                records[idx].actualPresentFence = NULL;
                numFences--;
                numFences--;
                updated = true;
            }
        }

        if (updated) {
            updateStatsLocked(idx);
        }
        }
    }
    }
}
}

void FrameTracker::updateStatsLocked(size_t newFrameIdx) const {
    int* numFrames = const_cast<int*>(mNumFrames);

    if (mDisplayPeriod > 0 && isFrameValidLocked(newFrameIdx)) {
        size_t prevFrameIdx = (newFrameIdx+NUM_FRAME_RECORDS-1) %
                NUM_FRAME_RECORDS;

        if (isFrameValidLocked(prevFrameIdx)) {
            nsecs_t newPresentTime =
                    mFrameRecords[newFrameIdx].actualPresentTime;
            nsecs_t prevPresentTime =
                    mFrameRecords[prevFrameIdx].actualPresentTime;

            nsecs_t duration = newPresentTime - prevPresentTime;
            int numPeriods = int((duration + mDisplayPeriod/2) /
                    mDisplayPeriod);

            for (int i = 0; i < NUM_FRAME_BUCKETS-1; i++) {
                int nextBucket = 1 << (i+1);
                if (numPeriods < nextBucket) {
                    numFrames[i]++;
                    return;
                }
            }

            // The last duration bucket is a catch-all.
            numFrames[NUM_FRAME_BUCKETS-1]++;
        }
    }
}

void FrameTracker::resetFrameCountersLocked() {
    for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
        mNumFrames[i] = 0;
    }
}

void FrameTracker::logStatsLocked(const String8& name) const {
    for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
        if (mNumFrames[i] > 0) {
            EventLog::logFrameDurations(name, mNumFrames, NUM_FRAME_BUCKETS);
            return;
        }
    }
}

bool FrameTracker::isFrameValidLocked(size_t idx) const {
    return mFrameRecords[idx].actualPresentTime > 0 &&
            mFrameRecords[idx].actualPresentTime < INT64_MAX;
}
}


void FrameTracker::dump(String8& result) const {
void FrameTracker::dump(String8& result) const {
+37 −0
Original line number Original line Diff line number Diff line
@@ -43,6 +43,8 @@ public:
    // frame time history.
    // frame time history.
    enum { NUM_FRAME_RECORDS = 128 };
    enum { NUM_FRAME_RECORDS = 128 };


    enum { NUM_FRAME_BUCKETS = 7 };

    FrameTracker();
    FrameTracker();


    // setDesiredPresentTime sets the time at which the current frame
    // setDesiredPresentTime sets the time at which the current frame
@@ -68,12 +70,21 @@ public:
    // at which the current frame became visible to the user.
    // at which the current frame became visible to the user.
    void setActualPresentFence(const sp<Fence>& fence);
    void setActualPresentFence(const sp<Fence>& fence);


    // setDisplayRefreshPeriod sets the display refresh period in nanoseconds.
    // This is used to compute frame presentation duration statistics relative
    // to this period.
    void setDisplayRefreshPeriod(nsecs_t displayPeriod);

    // advanceFrame advances the frame tracker to the next frame.
    // advanceFrame advances the frame tracker to the next frame.
    void advanceFrame();
    void advanceFrame();


    // clear resets all the tracked frame data to zero.
    // clear resets all the tracked frame data to zero.
    void clear();
    void clear();


    // logAndResetStats dumps the current statistics to the binary event log
    // and then resets the accumulated statistics to their initial values.
    void logAndResetStats(const String8& name);

    // dump appends the current frame display time history to the result string.
    // dump appends the current frame display time history to the result string.
    void dump(String8& result) const;
    void dump(String8& result) const;


@@ -99,6 +110,21 @@ private:
    // change.  This allows it to be called from the dump method.
    // change.  This allows it to be called from the dump method.
    void processFencesLocked() const;
    void processFencesLocked() const;


    // updateStatsLocked updates the running statistics that are gathered
    // about the frame times.
    void updateStatsLocked(size_t newFrameIdx) const;

    // resetFrameCounteresLocked sets all elements of the mNumFrames array to
    // 0.
    void resetFrameCountersLocked();

    // logStatsLocked dumps the current statistics to the binary event log.
    void logStatsLocked(const String8& name) const;

    // isFrameValidLocked returns true if the data for the given frame index is
    // valid and has all arrived (i.e. there are no oustanding fences).
    bool isFrameValidLocked(size_t idx) const;

    // mFrameRecords is the circular buffer storing the tracked data for each
    // mFrameRecords is the circular buffer storing the tracked data for each
    // frame.
    // frame.
    FrameRecord mFrameRecords[NUM_FRAME_RECORDS];
    FrameRecord mFrameRecords[NUM_FRAME_RECORDS];
@@ -115,6 +141,17 @@ private:
    // doesn't grow with NUM_FRAME_RECORDS.
    // doesn't grow with NUM_FRAME_RECORDS.
    int mNumFences;
    int mNumFences;


    // mNumFrames keeps a count of the number of frames with a duration in a
    // particular range of vsync periods.  Element n of the array stores the
    // number of frames with duration in the half-inclusive range
    // [2^n, 2^(n+1)).  The last element of the array contains the count for
    // all frames with duration greater than 2^(NUM_FRAME_BUCKETS-1).
    int32_t mNumFrames[NUM_FRAME_BUCKETS];

    // mDisplayPeriod is the display refresh period of the display for which
    // this FrameTracker is gathering information.
    nsecs_t mDisplayPeriod;

    // mMutex is used to protect access to all member variables.
    // mMutex is used to protect access to all member variables.
    mutable Mutex mMutex;
    mutable Mutex mMutex;
};
};
Loading