Write thread and data to separate files

Each file name starts with either "histogram" or
"outlier" and contains thread and hash (source
file location) information.

Test: dumpsys media.log

Change-Id: I4bbea8b5265ac539e6fb2ce16207e4f5c89d21d4
diff --git a/media/libnbaio/PerformanceAnalysis.cpp b/media/libnbaio/PerformanceAnalysis.cpp
index 698d592..d1dff47 100644
--- a/media/libnbaio/PerformanceAnalysis.cpp
+++ b/media/libnbaio/PerformanceAnalysis.cpp
@@ -73,7 +73,7 @@
         return;
     }
 
-    // mHists is empty if program just started
+    // mHists is empty if thread/hash pair is sending data for the first time
     if (mHists.empty()) {
         mHists.emplace_front(static_cast<uint64_t>(mTimeStampSeries[0]),
                             std::map<int, int>());
@@ -130,10 +130,6 @@
     }
 }
 
-// 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.
 // The function sets the mean to the starting value and sigma to 0, and updates
@@ -223,7 +219,6 @@
     }
 }
 
-
 // FIXME: delete this temporary test code, recycled for various new functions
 void PerformanceAnalysis::testFunction() {
     // produces values (4: 5000000), (13: 18000000)
@@ -241,7 +236,10 @@
 // TODO Make it return a std::string instead of modifying body --> is this still relevant?
 // 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) const {
+void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) {
+    // Add any new data
+    processAndFlushTimeStampSeries();
+
     if (mHists.empty()) {
         ALOGD("reportPerformance: mHists is empty");
         return;
@@ -348,11 +346,18 @@
 //------------------------------------------------------------------------------
 
 // writes summary of performance into specified file descriptor
-void dump(int fd, int indent, const PerformanceAnalysisMap &threadPerformanceAnalysis) {
+void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) {
     String8 body;
+    const char* const kName = "/data/misc/audioserver/";
     for (auto & thread : threadPerformanceAnalysis) {
         for (auto & hash: thread.second) {
-            hash.second.reportPerformance(&body);
+            PerformanceAnalysis& curr = hash.second;
+            curr.processAndFlushTimeStampSeries();
+            // write performance data to console
+            curr.reportPerformance(&body);
+            // write to file
+            writeToFile(curr.mOutlierData, curr.mHists, kName, false,
+                        thread.first, hash.first);
         }
     }
     if (!body.isEmpty()) {
diff --git a/media/libnbaio/ReportPerformance.cpp b/media/libnbaio/ReportPerformance.cpp
index 7d3869c..87c223b 100644
--- a/media/libnbaio/ReportPerformance.cpp
+++ b/media/libnbaio/ReportPerformance.cpp
@@ -23,12 +23,12 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
+#include <sstream>
 #include <sys/prctl.h>
 #include <utility>
 #include <media/nbaio/NBLog.h>
 #include <media/nbaio/PerformanceAnalysis.h>
 #include <media/nbaio/ReportPerformance.h>
-// #include <utils/CallStack.h> // used to print callstack
 #include <utils/Log.h>
 #include <utils/String8.h>
 
@@ -40,34 +40,48 @@
 // TODO: format the data efficiently and write different types of data to different files
 void writeToFile(const std::deque<std::pair<outlierInterval, timestamp>> &outlierData,
                                     const std::deque<std::pair<timestamp, Histogram>> &hists,
-                                    const char * kName,
-                                    bool append) {
-    ALOGD("writing performance data to file");
+                                    const char * kDirectory,
+                                    bool append, int author, log_hash_t hash) {
     if (outlierData.empty() || hists.empty()) {
+        ALOGW("No data, returning.");
         return;
     }
 
+    std::stringstream outlierName;
+    std::stringstream histogramName;
+
+    outlierName << kDirectory << "outliers_" << author << "_" << hash;
+    histogramName << kDirectory << "histograms_" << author << "_" << hash;
+
     std::ofstream ofs;
-    ofs.open(kName, append ? std::ios::app : std::ios::trunc);
+    ofs.open(outlierName.str().c_str(), append ? std::ios::app : std::ios::trunc);
     if (!ofs.is_open()) {
-        ALOGW("couldn't open file %s", kName);
+        ALOGW("couldn't open file %s", outlierName.str().c_str());
         return;
     }
     ofs << "Outlier data: interval and timestamp\n";
     for (const auto &outlier : outlierData) {
         ofs << outlier.first << ": " << outlier.second << "\n";
     }
-    ofs << "Histogram data\n";
-    for (const auto &hist : hists) {
-        ofs << "\ttimestamp\n";
-        ofs << hist.first << "\n";
-        ofs << "\tbuckets and counts\n";
-        for (const auto &bucket : hist.second) {
-            ofs << bucket.first << ": " << bucket.second << "\n";
-        }
-        ofs << "\n"; // separate histograms with a newline
-    }
     ofs.close();
+
+    std::ofstream hfs;
+    hfs.open(histogramName.str().c_str(), append ? std::ios::app : std::ios::trunc);
+    if (!hfs.is_open()) {
+        ALOGW("couldn't open file %s", histogramName.str().c_str());
+        return;
+    }
+    hfs << "Histogram data\n";
+    for (const auto &hist : hists) {
+        hfs << "\ttimestamp\n";
+        hfs << hist.first << "\n";
+        hfs << "\tbuckets and counts\n";
+        for (const auto &bucket : hist.second) {
+            hfs << bucket.first << ": " << bucket.second << "\n";
+        }
+        hfs << "\n"; // separate histograms with a newline
+    }
+    hfs.close();
 }
 
 } // namespace ReportPerformance
diff --git a/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h b/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
index dff307d..da68821 100644
--- a/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
+++ b/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
@@ -29,6 +29,12 @@
 
 namespace ReportPerformance {
 
+class PerformanceAnalysis;
+
+// a map of PerformanceAnalysis instances
+// The outer key is for the thread, the inner key for the source file location.
+using PerformanceAnalysisMap = std::map<int, std::map<log_hash_t, PerformanceAnalysis>>;
+
 class PerformanceAnalysis {
     // This class stores and analyzes audio processing wakeup timestamps from NBLog
     // FIXME: currently, all performance data is stored in deques. Need to add a mutex.
@@ -38,15 +44,13 @@
 
     PerformanceAnalysis();
 
-    // Given a series of audio processing wakeup timestamps,
-    // compresses and and analyzes the data, and flushes
-    // the timestamp series from memory.
-    void processAndFlushTimeStampSeries();
+    friend void dump(int fd, int indent,
+                     PerformanceAnalysisMap &threadPerformanceAnalysis);
 
     // Given a series of audio processing wakeup timestamps,
     // compresses and and analyzes the data, and flushes
     // the timestamp series from memory.
-    void processAndFlushTimeStampSeriesOld();
+    void processAndFlushTimeStampSeries();
 
     // Called when an audio on/off event is read from the buffer,
     // e.g. EVENT_AUDIO_STATE.
@@ -73,7 +77,7 @@
     // input: series of short histograms. Generates a string of analysis of the buffer periods
     // TODO: WIP write more detailed analysis
     // FIXME: move this data visualization to a separate class. Model/view/controller
-    void reportPerformance(String8 *body, int maxHeight = 10) const;
+    void reportPerformance(String8 *body, int maxHeight = 10);
 
     // TODO: delete this. temp for testing
     void testFunction();
@@ -134,12 +138,7 @@
 
 };
 
-// a map of PerformanceAnalysis instances
-// The outer key is for the thread, the inner key for the source file location.
-using PerformanceAnalysisMap = std::map<int, std::map<log_hash_t, PerformanceAnalysis>>;
-
-void dump(int fd, int indent, const PerformanceAnalysisMap &threadPerformanceAnalysis);
-
+void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis);
 void dumpLine(int fd, int indent, const String8 &body);
 
 } // namespace ReportPerformance
diff --git a/media/libnbaio/include/media/nbaio/ReportPerformance.h b/media/libnbaio/include/media/nbaio/ReportPerformance.h
index e5b9840..afbbb75 100644
--- a/media/libnbaio/include/media/nbaio/ReportPerformance.h
+++ b/media/libnbaio/include/media/nbaio/ReportPerformance.h
@@ -58,8 +58,7 @@
 // intervals to a file.
 void writeToFile(const std::deque<std::pair<outlierInterval, timestamp>> &outlierData,
                  const std::deque<std::pair<timestamp, Histogram>> &hists,
-                 const char * kName,
-                 bool append);
+                 const char * kName, bool append, int author, log_hash_t hash);
 
 } // namespace ReportPerformance