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

Commit d5065451 authored by Alec Mouri's avatar Alec Mouri
Browse files

[TimeStats] Add callback for global stats

Now that the new statsd api is completed, we can implement the puller
logic in TimeStats instead of in statsd's code.

Bug: 119885568
Test: adb shell cmd stats pull-source 10062
Change-Id: Ic90ec5ddc082160bd7e784becf8bf3c3a99ef971
parent 0f67b9fa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -490,6 +490,7 @@ void SurfaceFlinger::bootFinished()
    ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );

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

    // wait patiently for the window manager death
    const String16 name("window");
+8 −0
Original line number Diff line number Diff line
@@ -5,15 +5,23 @@ cc_library_shared {
    ],
    shared_libs: [
        "libbase",
        "libbinder",
        "libcutils",
        "liblog",
        "libprotobuf-cpp-lite",
        "libstatslog",
        "libstatspull",
        "libstatssocket",
        "libtimestats_proto",
        "libui",
        "libutils",
    ],
    export_include_dirs: ["."],
    export_shared_lib_headers: [
        "libbinder",
        "libstatslog",
        "libstatspull",
        "libstatssocket",
        "libtimestats_proto",
    ],
    cppflags: [
+83 −8
Original line number Diff line number Diff line
@@ -32,14 +32,54 @@ namespace android {

namespace impl {

bool TimeStats::pullGlobalAtomCallback(int32_t atom_tag, pulled_stats_event_list* data,
                                       const void* cookie) {
    impl::TimeStats* timeStats =
            const_cast<impl::TimeStats*>(reinterpret_cast<const impl::TimeStats*>(cookie));
    if (atom_tag != android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) {
        return false;
    }

    std::lock_guard<std::mutex> lock(timeStats->mMutex);

    const auto& stats = timeStats->mTimeStats;
    if (stats.statsStart == 0) {
        return false;
    }
    timeStats->flushPowerTimeLocked();

    struct stats_event* event = timeStats->mStatsDelegate->addStatsEventToPullData(data);
    timeStats->mStatsDelegate->statsEventSetAtomId(event,
                                                   android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
    timeStats->mStatsDelegate->statsEventWriteInt64(event, stats.totalFrames);
    timeStats->mStatsDelegate->statsEventWriteInt64(event, stats.missedFrames);
    timeStats->mStatsDelegate->statsEventWriteInt64(event, stats.clientCompositionFrames);
    timeStats->mStatsDelegate->statsEventWriteInt64(event, stats.displayOnTime);
    timeStats->mStatsDelegate->statsEventWriteInt64(event, stats.presentToPresent.totalTime());
    timeStats->mStatsDelegate->statsEventBuild(event);
    timeStats->clearGlobalLocked();

    return true;
}

TimeStats::TimeStats() {
    // Temporarily enable TimeStats by default. Telemetry is disabled while
    // we move onto statsd, so TimeStats is currently not exercised at all
    // during testing.
    // TODO: remove this.
    // during testing without enabling by default.
    // TODO: remove this, as we should only be paying this overhead on devices
    // where statsd exists.
    enable();
}

TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate) : TimeStats() {
    mStatsDelegate = std::move(statsDelegate);
}

void TimeStats::onBootFinished() {
    std::lock_guard<std::mutex> lock(mMutex);
    mRegisteredCallback = false;
}

void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
    ATRACE_CALL();

@@ -65,7 +105,7 @@ void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::strin
    }

    if (argsMap.count("-clear")) {
        clear();
        clearAll();
    }

    if (argsMap.count("-enable")) {
@@ -549,6 +589,30 @@ void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {

        mGlobalRecord.renderEngineDurations.pop_front();
    }
    // Try to register to statsd at the end of every global flush, if we haven't
    // yet.
    registerToStatsdIfNeededLocked();
}

bool TimeStats::StatsEventDelegate::checkStatsService() {
    ATRACE_CALL();
    bool ret =
            android::defaultServiceManager()->checkService(android::String16("stats")) != nullptr;
    return ret;
}

void TimeStats::registerToStatsdIfNeededLocked() {
    if (!mRegisteredCallback && mStatsDelegate->checkStatsService()) {
        // Note that this assumes that statsd will never crash. To be absolutely
        // correct we would need to register a DeathRecipient ourselves, but to
        // minimize the cost on the rendering path let's only register once as
        // soon as we know that statd has booted up.
        ALOGD("Registering statsd callback");
        mStatsDelegate
                ->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
                                                TimeStats::pullGlobalAtomCallback, nullptr, this);
        mRegisteredCallback = true;
    }
}

void TimeStats::setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) {
@@ -605,12 +669,15 @@ void TimeStats::disable() {
    ALOGD("Disabled");
}

void TimeStats::clear() {
void TimeStats::clearAll() {
    std::lock_guard<std::mutex> lock(mMutex);
    clearGlobalLocked();
    clearLayersLocked();
}

void TimeStats::clearGlobalLocked() {
    ATRACE_CALL();

    std::lock_guard<std::mutex> lock(mMutex);
    mTimeStatsTracker.clear();
    mTimeStats.stats.clear();
    mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
    mTimeStats.statsEnd = 0;
    mTimeStats.totalFrames = 0;
@@ -624,7 +691,15 @@ void TimeStats::clear() {
    mPowerTime.prevTime = systemTime();
    mGlobalRecord.prevPresentTime = 0;
    mGlobalRecord.presentFences.clear();
    ALOGD("Cleared");
    ALOGD("Cleared global stats");
}

void TimeStats::clearLayersLocked() {
    ATRACE_CALL();

    mTimeStatsTracker.clear();
    mTimeStats.stats.clear();
    ALOGD("Cleared layer stats");
}

bool TimeStats::isEnabled() {
+52 −1
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@

#pragma once

#include <binder/IServiceManager.h>
#include <hardware/hwcomposer_defs.h>
#include <stats_event.h>
#include <stats_pull_atom_callback.h>
#include <statslog.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
#include <ui/FenceTime.h>
@@ -37,6 +41,10 @@ class TimeStats {
public:
    virtual ~TimeStats() = default;

    // Called once boot has been finished to perform additional capabilities,
    // e.g. registration to statsd.
    virtual void onBootFinished() = 0;

    virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
    virtual bool isEnabled() = 0;
    virtual std::string miniDump() = 0;
@@ -131,6 +139,40 @@ class TimeStats : public android::TimeStats {
public:
    TimeStats();

    // Delegate to the statsd service and associated APIs.
    // Production code may use this class directly, whereas unit test may define
    // a subclass for ease of testing.
    class StatsEventDelegate {
    public:
        virtual ~StatsEventDelegate() = default;
        virtual struct stats_event* addStatsEventToPullData(pulled_stats_event_list* data) {
            return add_stats_event_to_pull_data(data);
        }
        virtual void registerStatsPullAtomCallback(int32_t atom_tag,
                                                   stats_pull_atom_callback_t callback,
                                                   pull_atom_metadata* metadata, void* cookie) {
            return register_stats_pull_atom_callback(atom_tag, callback, metadata, cookie);
        }

        // Check if the statsd daemon exists, as otherwise callback registration
        // will silently fail.
        virtual bool checkStatsService();

        virtual void statsEventSetAtomId(struct stats_event* event, int32_t atom_id) {
            return stats_event_set_atom_id(event, atom_id);
        }

        virtual void statsEventWriteInt64(struct stats_event* event, int64_t field) {
            return stats_event_write_int64(event, field);
        }

        virtual void statsEventBuild(struct stats_event* event) { return stats_event_build(event); }
    };
    // For testing only for injecting custom dependencies.
    TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate);

    void onBootFinished() override;

    void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
    bool isEnabled() override;
    std::string miniDump() override;
@@ -167,14 +209,19 @@ public:
    static const size_t MAX_NUM_TIME_RECORDS = 64;

private:
    static bool pullGlobalAtomCallback(int32_t atom_tag, pulled_stats_event_list* data,
                                       const void* cookie);
    bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
    void flushAvailableRecordsToStatsLocked(int32_t layerId);
    void flushPowerTimeLocked();
    void flushAvailableGlobalRecordsToStatsLocked();
    void registerToStatsdIfNeededLocked();

    void enable();
    void disable();
    void clear();
    void clearAll();
    void clearGlobalLocked();
    void clearLayersLocked();
    void dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result);

    std::atomic<bool> mEnabled = false;
@@ -187,6 +234,10 @@ private:

    static const size_t MAX_NUM_LAYER_RECORDS = 200;
    static const size_t MAX_NUM_LAYER_STATS = 200;
    // Default is true, so that registration doesn't happen until the device has
    // been booted.
    bool mRegisteredCallback = true;
    std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
};

} // namespace impl
+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ cc_test {
        "perfetto_trace_protos",
    ],
    shared_libs: [
        "libstatssocket",
        "libsurfaceflinger",
        "libtimestats",
        "libtimestats_proto",
Loading