media.log: improve histogram appearance

removed whitespace
fix histogram column appearance, removed y-axis labels
added axis labels and removed unnecessary characters in columns
minor code cleanup

New appearance:
[446203.725] Histogram flush - FastMixer: 6F660152
  Occurrences
      1  19  15   1   1

          |
          |   |
          |   |
          |   |
      |   |   |   |   |
   ------------------------
      0   3   4   6  29    ms

Old appearance:
[54.234] Histogram flush - AudioOut_D:
Histogram 33640BF1
            [ 1][ 1][ 1][ 3][54][69][ 1][ 2][ 1]
        64|                      []
        32|                  []  []
        16|                  []  []
         8|                  []  []
         4|                  []  []
         2|______________[]__[]__[]______[]____
              4   5   6   8   9  10  11  13  15

Test: dumpsys media.log
Change-Id: Iece8feec66db1cef66db4cb12d4db3f7e433b7d5
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index 5413007..3888bd9 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <climits>
+#include <math.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -54,7 +55,7 @@
 
 /*static*/
 std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr) {
-    uint8_t type = EntryIterator(ptr)->type;
+    const uint8_t type = EntryIterator(ptr)->type;
     switch (type) {
     case EVENT_START_FMT:
         return std::make_unique<FormatEntry>(FormatEntry(ptr));
@@ -937,18 +938,17 @@
         case EVENT_HISTOGRAM_FLUSH: {
             HistogramEntry histEntry(entry);
             // Log timestamp
-            int64_t ts = histEntry.timestamp();
+            const int64_t ts = histEntry.timestamp();
             timestamp.clear();
             timestamp.appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
                             (int) ((ts / (1000 * 1000)) % 1000));
             // Log histograms
             body.appendFormat("Histogram flush - ");
             handleAuthor(histEntry, &body);
-            body.appendFormat("\n");
             for (auto hist = mHists.begin(); hist != mHists.end();) {
                 if (hist->first.second == histEntry.author()) {
-                    body.appendFormat("Histogram %X", (int)hist->first.first);
-                    drawHistogram(&body, hist->second, true/*logScale*/, indent + timestamp.size());
+                    body.appendFormat("%X", (int)hist->first.first);
+                    drawHistogram(&body, hist->second, true, indent);
                     hist = mHists.erase(hist);
                 } else {
                     ++hist;
@@ -1178,66 +1178,70 @@
                                   bool logScale,
                                   int indent,
                                   int maxHeight) {
+    // this avoids some corner cases
     if (samples.size() <= 1) {
         return;
     }
     std::map<int, int> buckets = buildBuckets(samples);
     // TODO consider changing all ints to uint32_t or uint64_t
-    static const char *underscores = "________________";
-    static const char *spaces = "                ";
+
+    // underscores and spaces length corresponds to maximum width of histogram
+    static const int kLen = 40;
+    std::string underscores(kLen, '-');
+    std::string spaces(kLen, ' ');
 
     auto it = buckets.begin();
-    int maxLabel = it->first;
-    int maxVal = it->second;
+    int maxDelta = it->first;
+    int maxCount = it->second;
     // Compute maximum values
     while (++it != buckets.end()) {
-        if (it->first > maxLabel) {
-            maxLabel = it->first;
+        if (it->first > maxDelta) {
+            maxDelta = it->first;
         }
-        if (it->second > maxVal) {
-            maxVal = it->second;
+        if (it->second > maxCount) {
+            maxCount = it->second;
         }
     }
-    int height = (logScale) ? log2(maxVal) + 1 : maxVal; // maxVal > 0, safe to call log2
-    int leftPadding = widthOf(maxVal);
-    int colWidth = std::max(std::max(widthOf(maxLabel) + 1, 3), leftPadding + 2);
+    int height = logScale ? log2(maxCount) + 1 : maxCount; // maxCount > 0, safe to call log2
+    const int leftPadding = widthOf(logScale ? pow(2, height) : maxCount);
+    const int colWidth = std::max(std::max(widthOf(maxDelta) + 1, 3), leftPadding + 2);
     int scalingFactor = 1;
     // scale data if it exceeds maximum height
     if (height > maxHeight) {
         scalingFactor = (height + maxHeight) / maxHeight;
         height /= scalingFactor;
     }
-    // write header line with bucket values
+    body->appendFormat("\n%*s", leftPadding + 11, "Occurrences");
+    // write histogram label line with bucket values
     body->appendFormat("\n%*s", indent, " ");
-    body->appendFormat("%*s", leftPadding + 2, " ");
-    for (auto const &x : buckets)
-    {
-        body->appendFormat("[%*d]", colWidth - 2, x.second);
+    body->appendFormat("%*s", leftPadding, " ");
+    for (auto const &x : buckets) {
+        body->appendFormat("%*d", colWidth, x.second);
     }
     // write histogram ascii art
     body->appendFormat("\n%*s", indent, " ");
-    for (int row = height * scalingFactor; row > 0; row -= scalingFactor)
-    {
-        int value = ((logScale) ? (1 << row) : row);
-        body->appendFormat("%*u|", leftPadding, value);
+    for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) {
+        const int value = logScale ? (1 << row) : row;
+        body->appendFormat("%.*s", leftPadding, spaces.c_str());
         for (auto const &x : buckets) {
-            body->appendFormat("%.*s%s", colWidth - 2,
-                   (row <= scalingFactor) ? underscores : spaces,
-                   x.second < value ? ((row <= scalingFactor) ? "__" : "  ") : "[]");
+          body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|");
         }
         body->appendFormat("\n%*s", indent, " ");
     }
+    // print x-axis
+    const int columns = static_cast<int>(buckets.size());
+    body->appendFormat("%*c", leftPadding, ' ');
+    body->appendFormat("%.*s", (columns + 1) * colWidth, underscores.c_str());
+    body->appendFormat("\n%*s", indent, " ");
+
     // write footer with bucket labels
-    body->appendFormat("%*s", leftPadding + 1, " ");
-    for (auto const &x : buckets)
-    {
+    body->appendFormat("%*s", leftPadding, " ");
+    for (auto const &x : buckets) {
         body->appendFormat("%*d", colWidth, x.first);
     }
-    body->appendFormat("\n");
+    body->appendFormat("%.*s%s", colWidth, spaces.c_str(), "ms\n");
 }
 
-// ---------------------------------------------------------------------------
-
 NBLog::Merger::Merger(const void *shared, size_t size):
       mShared((Shared *) shared),
       mFifo(mShared != NULL ?