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

Commit cfa7c4b9 authored by Eric Tan's avatar Eric Tan
Browse files

Improve ReportPerformance::Histogram implementation and add drawing

Test: dumpsys media.log -r
Bug: 68148948
Change-Id: Idde42ba6b152f15c8c1834c8eea4d7ca24b4c934
parent bd9b5935
Loading
Loading
Loading
Loading
+69 −22
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <algorithm>
#include <climits>
#include <deque>
#include <iomanip>
#include <math.h>
#include <numeric>
#include <sstream>
@@ -51,23 +52,21 @@ namespace ReportPerformance {

void Histogram::add(double value)
{
    // TODO Handle domain and range error exceptions?
    const int binIndex = lround((value - mLow) / mBinSize);
    if (binIndex < 0) {
        mLowCount++;
    } else if (binIndex >= mNumBins) {
        mHighCount++;
    } else {
        mBins[binIndex]++;
    if (mBinSize <= 0 || mBins.size() < 2) {
        return;
    }
    // TODO Handle domain and range error exceptions?
    const int unboundedIndex = lround((value - mLow) / mBinSize) + 1;
    // std::clamp is introduced in C++17
    //const int index = std::clamp(unboundedIndex, 0, (int)(mBins.size() - 1));
    const int index = std::max(0, std::min((int)(mBins.size() - 1), unboundedIndex));
    mBins[index]++;
    mTotalCount++;
}

void Histogram::clear()
{
    std::fill(mBins.begin(), mBins.end(), 0);
    mLowCount = 0;
    mHighCount = 0;
    mTotalCount = 0;
}

@@ -81,27 +80,75 @@ std::string Histogram::toString() const {
    static constexpr char kDivider = '|';
    ss << kVersion << "," << mBinSize << "," << mNumBins << "," << mLow << ",{";
    bool first = true;
    if (mLowCount != 0) {
        ss << "-1" << kDivider << mLowCount;
        first = false;
    }
    for (size_t i = 0; i < mNumBins; i++) {
    for (size_t i = 0; i < mBins.size(); i++) {
        if (mBins[i] != 0) {
            if (!first) {
                ss << ",";
            }
            ss << i << kDivider << mBins[i];
            ss << static_cast<int>(i) - 1 << kDivider << mBins[i];
            first = false;
        }
    }
    if (mHighCount != 0) {
        if (!first) {
            ss << ",";
    ss << "}";

    return ss.str();
}
        ss << mNumBins << kDivider << mHighCount;
        first = false;

std::string Histogram::asciiArtString(size_t indent) const {
    if (totalCount() == 0 || mBinSize <= 0 || mBins.size() < 2) {
        return "";
    }
    ss << "}";

    static constexpr char kMarker = '-';
    // One increment is considered one step of a bin's height.
    static constexpr size_t kMarkersPerIncrement = 2;
    static constexpr size_t kMaxIncrements = 64 + 1;
    static constexpr size_t kMaxNumberWidth = 7;
    static const std::string kMarkers(kMarkersPerIncrement * kMaxIncrements, kMarker);
    static const std::string kSpaces(kMarkersPerIncrement * kMaxIncrements, ' ');
    // get the last n characters of s, or the whole string if it is shorter
    auto getTail = [](const size_t n, const std::string &s) {
        return s.c_str() + s.size() - std::min(n, s.size());
    };

    // Since totalCount() > 0, mBins is not empty and maxCount > 0.
    const unsigned maxCount = *std::max_element(mBins.begin(), mBins.end());
    const size_t maxIncrements = log2(maxCount) + 1;

    std::stringstream ss;

    // Non-zero bins must exist at this point because totalCount() > 0.
    size_t firstNonZeroBin = 0;
    // If firstNonZeroBin reaches mBins.size() - 1, then it must be a nonzero bin.
    for (; firstNonZeroBin < mBins.size() - 1 && mBins[firstNonZeroBin] == 0; firstNonZeroBin++) {}
    const size_t firstBinToPrint = firstNonZeroBin == 0 ? 0 : firstNonZeroBin - 1;

    size_t lastNonZeroBin = mBins.size() - 1;
    // If lastNonZeroBin reaches 0, then it must be a nonzero bin.
    for (; lastNonZeroBin > 0 && mBins[lastNonZeroBin] == 0; lastNonZeroBin--) {}
    const size_t lastBinToPrint = lastNonZeroBin == mBins.size() - 1 ? lastNonZeroBin
            : lastNonZeroBin + 1;

    for (size_t bin = firstBinToPrint; bin <= lastBinToPrint; bin++) {
        ss << std::setw(indent + kMaxNumberWidth);
        if (bin == 0) {
            ss << "<";
        } else if (bin == mBins.size() - 1) {
            ss << ">";
        } else {
            ss << mLow + (bin - 1) * mBinSize;
        }
        ss << " |";
        size_t increments = 0;
        const uint64_t binCount = mBins[bin];
        if (binCount > 0) {
            increments = log2(binCount) + 1;
            ss << getTail(increments * kMarkersPerIncrement, kMarkers);
        }
        ss << getTail((maxIncrements - increments + 1) * kMarkersPerIncrement, kSpaces)
                << binCount << "\n";
    }
    ss << "\n";

    return ss.str();
}
+16 −10
Original line number Diff line number Diff line
@@ -58,16 +58,16 @@ public:
    /**
     * \brief Creates a Histogram object.
     *
     * \param binSize the width of each bin of the histogram.
     * \param binSize the width of each bin of the histogram, must be greater than 0.
     *                Units are whatever data the caller decides to store.
     * \param numBins the number of bins desired in the histogram range.
     * \param numBins the number of bins desired in the histogram range, must be greater than 0.
     * \param low     the lower bound of the histogram bucket values.
     *                Units are whatever data the caller decides to store.
     *                Note that the upper bound can be calculated by the following:
     *                  upper = lower + binSize * numBins.
     */
    Histogram(double binSize, size_t numBins, double low = 0.)
        : mBinSize(binSize), mNumBins(numBins), mLow(low), mBins(mNumBins) {}
        : mBinSize(binSize), mNumBins(numBins), mLow(low), mBins(mNumBins + 2) {}

    Histogram(const Config &c)
        : Histogram(c.binSize, c.numBins, c.low) {}
@@ -112,17 +112,23 @@ public:
     */
    std::string toString() const;

    // Draw log scale sideways histogram as ASCII art and store as a std::string.
    // Empty string is returned if totalCount() == 0.
    std::string asciiArtString(size_t indent = 0) const;

private:
    // Histogram version number.
    static constexpr int kVersion = 1;

    const double mBinSize;          // Size of each bucket
    const size_t mNumBins;      // Number of buckets in histogram range
    const size_t mNumBins;          // Number of buckets in range (excludes low and high)
    const double mLow;              // Lower bound of values
    std::vector<int> mBins;     // Data structure to store the actual histogram

    int mLowCount = 0;          // Number of values less than mLow
    int mHighCount = 0;         // Number of values >= mLow + mBinSize * mNumBins
    // Data structure to store the actual histogram. Counts of bin values less than mLow
    // are stored in mBins[0]. Bin index i corresponds to mBins[i+1]. Counts of bin values
    // >= high are stored in mBins[mNumBins + 1].
    std::vector<uint64_t> mBins;

    uint64_t mTotalCount = 0;       // Total number of values recorded
};