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

Commit 716d2c66 authored by Sanna Catherine de Treville Wager's avatar Sanna Catherine de Treville Wager
Browse files

Organize PerformanceAnalysis members in structs

Stores related variables in structs instead of
directly in the class definition

Test: dumpsys media.log
Change-Id: I776e35e74ac69b428170b379a9bcf4d18b3fa041
parent f8c34284
Loading
Loading
Loading
Loading
+36 −30
Original line number Diff line number Diff line
@@ -87,12 +87,12 @@ void PerformanceAnalysis::processAndFlushTimeStampSeries() {

    // if the current histogram has spanned its maximum time interval,
    // insert a new empty histogram to the front of mHists
    if (deltaMs(mHists[0].first, mTimeStampSeries[0]) >= kMaxHistTimespanMs) {
    if (deltaMs(mHists[0].first, mTimeStampSeries[0]) >= kMaxLength.HistTimespanMs) {
        mHists.emplace_front(static_cast<uint64_t>(mTimeStampSeries[0]),
                             std::map<int, int>());
        // When memory is full, delete oldest histogram
        if (mHists.size() >= kHistsCapacity) {
            mHists.resize(kHistsCapacity);
        if (mHists.size() >= kMaxLength.Hists) {
            mHists.resize(kMaxLength.Hists);
        }
    }

@@ -125,7 +125,7 @@ void PerformanceAnalysis::logTsEntry(int64_t ts) {
    mTimeStampSeries.push_back(ts);
    // if length of the time series has reached kShortHistSize samples,
    // analyze the data and flush the timestamp series from memory
    if (mTimeStampSeries.size() >= kHistSize) {
    if (mTimeStampSeries.size() >= kMaxLength.TimeStamps) {
        processAndFlushTimeStampSeries();
    }
}
@@ -152,36 +152,39 @@ void PerformanceAnalysis::detectPeaks() {
    // the mean and standard deviation are updated every time a peak is detected
    // initialize first time. The mean from the previous sequence is stored
    // for the next sequence. Here, they are initialized for the first time.
    if (mPeakDetectorMean < 0) {
        mPeakDetectorMean = static_cast<double>(start->first);
        mPeakDetectorSd = 0;
    if (mOutlierDistribution.Mean < 0) {
        mOutlierDistribution.Mean = static_cast<double>(start->first);
        mOutlierDistribution.Sd = 0;
    }
    auto sqr = [](auto x){ return x * x; };
    for (auto it = mOutlierData.begin(); it != mOutlierData.end(); ++it) {
        // no surprise occurred:
        // the new element is a small number of standard deviations from the mean
        if ((fabs(it->first - mPeakDetectorMean) < kStddevThreshold * mPeakDetectorSd) ||
        if ((fabs(it->first - mOutlierDistribution.Mean) <
             mOutlierDistribution.kMaxDeviation * mOutlierDistribution.Sd) ||
             // or: right after peak has been detected, the delta is smaller than average
            (mPeakDetectorSd == 0 && fabs(it->first - mPeakDetectorMean) < kTypicalDiff)) {
            (mOutlierDistribution.Sd == 0 &&
                     fabs(it->first - mOutlierDistribution.Mean) < kTypicalDiff)) {
            // update the mean and sd:
            // count number of elements (distance between start interator and current)
            const int kN = std::distance(start, it) + 1;
            // usual formulas for mean and sd
            mPeakDetectorMean = std::accumulate(start, it + 1, 0.0,
            mOutlierDistribution.Mean = std::accumulate(start, it + 1, 0.0,
                                   [](auto &a, auto &b){return a + b.first;}) / kN;
            mPeakDetectorSd = sqrt(std::accumulate(start, it + 1, 0.0,
                      [=](auto &a, auto &b){ return a + sqr(b.first - mPeakDetectorMean);})) /
            mOutlierDistribution.Sd = sqrt(std::accumulate(start, it + 1, 0.0,
                    [=](auto &a, auto &b){
                    return a + sqr(b.first - mOutlierDistribution.Mean);})) /
                    ((kN > 1)? kN - 1 : kN); // kN - 1: mean is correlated with variance
        }
        // surprising value: store peak timestamp and reset mean, sd, and start iterator
        else {
            mPeakTimestamps.emplace_back(it->second);
            // TODO: remove pop_front once a circular buffer is in place
            if (mPeakTimestamps.size() >= kPeakSeriesSize) {
                mPeakTimestamps.pop_front();
            mPeakTimestamps.emplace_front(it->second);
            // TODO: turn this into a circular buffer
            if (mPeakTimestamps.size() >= kMaxLength.Peaks) {
                mPeakTimestamps.resize(kMaxLength.Peaks);
            }
            mPeakDetectorMean = static_cast<double>(it->first);
            mPeakDetectorSd = 0;
            mOutlierDistribution.Mean = static_cast<double>(it->first);
            mOutlierDistribution.Sd = 0;
            start = it;
        }
    }
@@ -190,7 +193,8 @@ void PerformanceAnalysis::detectPeaks() {

// Called by LogTsEntry. The input is a vector of timestamps.
// Finds outliers and writes to mOutlierdata.
// Each value in mOutlierdata consists of: <outlier timestamp, time elapsed since previous outlier>.
// Each value in mOutlierdata consists of: <outlier timestamp,
// time elapsed since previous outlier>.
// e.g. timestamps (ms) 1, 4, 5, 16, 18, 28 will produce pairs (4, 5), (13, 18).
// This function is applied to the time series before it is converted into a histogram.
void PerformanceAnalysis::storeOutlierData(const std::vector<int64_t> &timestamps) {
@@ -198,24 +202,25 @@ void PerformanceAnalysis::storeOutlierData(const std::vector<int64_t> &timestamp
        return;
    }
    // first pass: need to initialize
    if (mElapsed == 0) {
        mPrevNs = timestamps[0];
    if (mOutlierDistribution.Elapsed == 0) {
        mOutlierDistribution.PrevNs = timestamps[0];
    }
    for (const auto &ts: timestamps) {
        const uint64_t diffMs = static_cast<uint64_t>(deltaMs(mPrevNs, ts));
        const uint64_t diffMs = static_cast<uint64_t>(deltaMs(mOutlierDistribution.PrevNs, ts));
        if (diffMs >= static_cast<uint64_t>(kOutlierMs)) {
            mOutlierData.emplace_back(mElapsed, static_cast<uint64_t>(mPrevNs));
            mOutlierData.emplace_front(mOutlierDistribution.Elapsed,
                                      static_cast<uint64_t>(mOutlierDistribution.PrevNs));
            // Remove oldest value if the vector is full
            // TODO: remove pop_front once circular buffer is in place
            // FIXME: make sure kShortHistSize is large enough that that data will never be lost
            // before being written to file or to a FIFO
            if (mOutlierData.size() >= kOutlierSeriesSize) {
                mOutlierData.pop_front();
            if (mOutlierData.size() >= kMaxLength.Outliers) {
                mOutlierData.resize(kMaxLength.Outliers);
            }
            mElapsed = 0;
            mOutlierDistribution.Elapsed = 0;
        }
        mElapsed += diffMs;
        mPrevNs = ts;
        mOutlierDistribution.Elapsed += diffMs;
        mOutlierDistribution.PrevNs = ts;
    }
}

@@ -279,7 +284,8 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) {
        const int value = 1 << row;
        body->appendFormat("%.*s", leftPadding, spaces.c_str());
        for (auto const &x : buckets) {
          body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|");
          body->appendFormat("%.*s%s", colWidth - 1,
                             spaces.c_str(), x.second < value ? " " : "|");
        }
        body->appendFormat("\n%s", " ");
    }
+19 −18
Original line number Diff line number Diff line
@@ -102,10 +102,9 @@ private:
    // when a vector reaches its maximum size, the data is processed and flushed
    std::vector<timestamp_raw> mTimeStampSeries;

    static const int kMsPerSec = 1000;

    // Parameters used when detecting outliers
    // TODO: learn some of these from the data, delete unused ones
    // TODO: put used variables in a struct
    // FIXME: decide whether to make kPeriodMs static.
    static const int kNumBuff = 3; // number of buffers considered in local history
    int kPeriodMs; // current period length is ideally 4 ms
@@ -114,27 +113,29 @@ private:
    static constexpr double kRatio = 0.75; // estimate of CPU time as ratio of period length
    int kPeriodMsCPU; // compute based on kPeriodLen and kRatio

    // Peak detection: number of standard deviations from mean considered a significant change
    static const int kStddevThreshold = 5;

    // capacity allocated to data structures
    // TODO: make these values longer when testing is finished
    static const int kHistsCapacity = 20; // number of short-term histograms stored in memory
    static const int kHistSize = 1000; // max number of samples stored in a histogram
    static const int kOutlierSeriesSize = 100; // number of values stored in outlier array
    static const int kPeakSeriesSize = 100; // number of values stored in peak array
    struct MaxLength {
        size_t Hists; // number of histograms stored in memory
        size_t TimeStamps; // histogram size, e.g. maximum length of timestamp series
        size_t Outliers; // number of values stored in outlier array
        size_t Peaks; // number of values stored in peak array
        // maximum elapsed time between first and last timestamp of a long-term histogram
    static const int kMaxHistTimespanMs = 5 * kMsPerSec;
        int HistTimespanMs;
    };
    static constexpr MaxLength kMaxLength = {.Hists = 20, .TimeStamps = 1000,
            .Outliers = 100, .Peaks = 100, .HistTimespanMs = 5 * kMsPerSec };

    // these variables are stored in-class to ensure continuity while analyzing the timestamp
    // series one short sequence at a time: the variables are not re-initialized every time.
    // FIXME: create inner class for these variables and decide which other ones to add to it
    double mPeakDetectorMean = -1;
    double mPeakDetectorSd = -1;
    // variables for storeOutlierData
    uint64_t mElapsed = 0;
    int64_t mPrevNs = -1;

    struct OutlierDistribution {
        double Mean = -1;
        double Sd = -1;
        uint64_t Elapsed = 0;
        int64_t PrevNs = -1;
        // number of standard deviations from mean considered a significant change
        const int kMaxDeviation = 5;
    } mOutlierDistribution;
};

void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis);
+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ class String8;

namespace ReportPerformance {

const int kMsPerSec = 1000;

// stores a histogram: key: observed buffer period. value: count
// TODO: unsigned, unsigned
using Histogram = std::map<int, int>;