Simplify processAndFlushTimeStampSeries

Instead first writing to a deque of short-term
histograms and copying the data over to long-term
histograms, write directly to a single deque
of histograms.

Test: dumpsys media.log
Change-Id: I05a283a54b84bc7d061c7fae7b671390c1690def
diff --git a/media/libnbaio/PerformanceAnalysis.cpp b/media/libnbaio/PerformanceAnalysis.cpp
index d44dd45..41184a6 100644
--- a/media/libnbaio/PerformanceAnalysis.cpp
+++ b/media/libnbaio/PerformanceAnalysis.cpp
@@ -54,16 +54,6 @@
     kPeriodMsCPU = static_cast<int>(kPeriodMs * kRatio);
 }
 
-// converts a time series into a map. key: buffer period length. value: count
-static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) {
-    // TODO allow buckets of variable resolution
-    std::map<int, int> buckets;
-    for (size_t i = 1; i < samples.size(); ++i) {
-        ++buckets[deltaMs(samples[i - 1], samples[i])];
-    }
-    return buckets;
-}
-
 static int widthOf(int x) {
     int width = 0;
     while (x > 0) {
@@ -79,21 +69,41 @@
 // small or large values and stores these as peaks, and flushes
 // the timestamp series from memory.
 void PerformanceAnalysis::processAndFlushTimeStampSeries() {
+    if (mTimeStampSeries.empty()) {
+        ALOGD("Timestamp series is empty");
+        return;
+    }
+
+    // mHists is empty if program just started
+    if (mHists.empty()) {
+        mHists.emplace_front(static_cast<uint64_t>(mTimeStampSeries[0]),
+                            std::map<int, int>());
+    }
+
     // 1) analyze the series to store all outliers and their exact timestamps:
     storeOutlierData(mTimeStampSeries);
 
     // 2) detect peaks in the outlier series
     detectPeaks();
 
-    // 3) compute its histogram, append to mRecentHists and clear the time series
-    mRecentHists.emplace_back(static_cast<timestamp>(mTimeStampSeries[0]),
-                              buildBuckets(mTimeStampSeries));
-    // do not let mRecentHists exceed capacity
-    // ALOGD("mRecentHists size: %d", static_cast<int>(mRecentHists.size()));
-    if (mRecentHists.size() >= kRecentHistsCapacity) {
-        //  ALOGD("popped back mRecentHists");
-        mRecentHists.pop_front();
+    // 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) {
+        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);
+        }
     }
+
+    // 3) add current time intervals to histogram
+    for (size_t i = 1; i < mTimeStampSeries.size(); ++i) {
+        ++mHists[0].second[deltaMs(
+                mTimeStampSeries[i - 1], mTimeStampSeries[i])];
+    }
+
+    // clear the timestamps
     mTimeStampSeries.clear();
 }
 
@@ -116,48 +126,14 @@
     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() >= kShortHistSize) {
+    if (mTimeStampSeries.size() >= kHistSize) {
         processAndFlushTimeStampSeries();
     }
 }
 
-// When the short-term histogram array mRecentHists has reached capacity,
-// merge histograms for data compression and store them in mLongTermHists
-// clears mRecentHists
-// TODO: have logTsEntry write directly to mLongTermHists, discard mRecentHists,
-// start a new histogram when a peak occurs
-void PerformanceAnalysis::processAndFlushRecentHists() {
-
-    // Buckets is used to aggregate short-term histograms.
-    Histogram buckets;
-    timestamp startingTs = mRecentHists[0].first;
-
-    for (const auto &shortHist: mRecentHists) {
-        // If the time between starting and ending timestamps has reached the maximum,
-        // add the current histogram (buckets) to the long-term histogram buffer,
-        // clear buckets, and start a new long-term histogram aggregation process.
-        if (deltaMs(startingTs, shortHist.first) >= kMaxHistTimespanMs) {
-            mLongTermHists.emplace_back(startingTs, std::move(buckets));
-            buckets.clear();
-            startingTs = shortHist.first;
-            // When memory is full, delete oldest histogram
-            // TODO use a circular buffer
-            if (mLongTermHists.size() >= kLongTermHistsCapacity) {
-                mLongTermHists.pop_front();
-            }
-        }
-
-        // add current histogram to buckets
-        for (const auto &countPair : shortHist.second) {
-            buckets[countPair.first] += countPair.second;
-        }
-    }
-    mRecentHists.clear();
-    // TODO: decide when/where to call writeToFile
-    // TODO: add a thread-specific extension to the file name
-    static const char* const kName = (const char *) "/data/misc/audioserver/sample_results.txt";
-    writeToFile(mOutlierData, mLongTermHists, kName, false);
-}
+// TODO: move this someplace
+// static const char* const kName = (const char *) "/data/misc/audioserver/sample_results.txt";
+//    writeToFile(mOutlierData, mLongTermHists, kName, false);
 
 // Given a series of outlier intervals (mOutlier data),
 // looks for changes in distribution (peaks), which can be either positive or negative.
@@ -267,13 +243,14 @@
 // TODO consider changing all ints to uint32_t or uint64_t
 // TODO: move this to ReportPerformance, probably make it a friend function of PerformanceAnalysis
 void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) {
-    if (mRecentHists.size() < 1) {
-        ALOGD("reportPerformance: mRecentHists is empty");
+    if (mHists.empty()) {
+        ALOGD("reportPerformance: mHists is empty");
         return;
     }
+    ALOGD("reportPerformance: hists size %d", static_cast<int>(mHists.size()));
     // TODO: more elaborate data analysis
     std::map<int, int> buckets;
-    for (const auto &shortHist: mRecentHists) {
+    for (const auto &shortHist: mHists) {
         for (const auto &countPair : shortHist.second) {
             buckets[countPair.first] += countPair.second;
         }
diff --git a/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h b/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
index d523aa9..0f47619 100644
--- a/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
+++ b/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
@@ -43,16 +43,17 @@
     // the timestamp series from memory.
     void processAndFlushTimeStampSeries();
 
+    // Given a series of audio processing wakeup timestamps,
+    // compresses and and analyzes the data, and flushes
+    // the timestamp series from memory.
+    void processAndFlushTimeStampSeriesOld();
+
     // Called when an audio on/off event is read from the buffer,
     // e.g. EVENT_AUDIO_STATE.
     // calls flushTimeStampSeries on the data up to the event,
     // effectively discarding the idle audio time interval
     void handleStateChange();
 
-    // When the short-term histogram array mRecentHists has reached capacity,
-    // merges histograms for data compression and stores them in mLongTermHists
-    void processAndFlushRecentHists();
-
     // Writes wakeup timestamp entry to log and runs analysis
     // TODO: make this thread safe. Each thread should have its own instance
     // of PerformanceAnalysis.
@@ -90,16 +91,11 @@
     // a peak is a moment at which the average outlier interval changed significantly
     std::deque<timestamp> mPeakTimestamps;
 
-    // TODO: turn these into circular buffers for better data flow
-    // FIFO of small histograms
-    // stores fixed-size short buffer period histograms with timestamp of first sample
-    std::deque<std::pair<timestamp, Histogram>> mRecentHists;
+    // stores stores buffer period histograms with timestamp of first sample
+    // TODO use a circular buffer
+    std::deque<std::pair<timestamp, Histogram>> mHists;
 
-    // FIFO of small histograms
-    // stores fixed-size long-term buffer period histograms with timestamp of first sample
-    std::deque<std::pair<timestamp, Histogram>> mLongTermHists;
-
-    // vector of timestamps, collected from NBLog for a (TODO) specific thread
+    // vector of timestamps, collected from NBLog for a specific thread
     // when a vector reaches its maximum size, the data is processed and flushed
     std::vector<timestamp_raw> mTimeStampSeries;
 
@@ -119,12 +115,11 @@
     static const int kStddevThreshold = 5;
 
     // capacity allocated to data structures
-    // TODO: adjust all of these values
-    static const int kRecentHistsCapacity = 100; // number of short-term histograms stored in memory
-    static const int kShortHistSize = 50; // number of samples in a short-term histogram
+    // 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
-    static const int kLongTermHistsCapacity = 20; // number of long-term histogram stored in memory
     // maximum elapsed time between first and last timestamp of a long-term histogram
     static const int kMaxHistTimespanMs = 5 * kMsPerSec;