Loading media/libnbaio/NBLog.cpp +70 −33 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ #include <utils/Log.h> #include <utils/String8.h> #include <map> #include <queue> #include <utility> Loading Loading @@ -848,8 +847,6 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho } bool deferredTimestamp = false; #endif std::map<std::pair<log_hash_t, int>, std::vector<int>> hists; std::map<std::pair<log_hash_t, int>, int64_t*> lastTSs; for (auto entry = snapshot.begin(); entry != snapshot.end();) { switch (entry->type) { Loading Loading @@ -928,31 +925,38 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho // There's probably a more efficient way to do it log_hash_t hash; memcpy(&hash, &(data->hash), sizeof(hash)); int64_t ts; memcpy(&ts, &data->ts, sizeof(ts)); const std::pair<log_hash_t, int> key(hash, data->author); if (lastTSs[key] != nullptr) { int64_t ts1; memcpy(&ts1, lastTSs[key], sizeof(ts1)); int64_t ts2; memcpy(&ts2, &data->ts, sizeof(ts2)); // TODO might want to filter excessively high outliers, which are usually caused // by the thread being inactive. hists[key].push_back(deltaMs(ts1, ts2)); } lastTSs[key] = &(data->ts); mHists[key].push_back(ts); ++entry; break; } case EVENT_HISTOGRAM_FLUSH: body.appendFormat("Histograms:\n"); for (auto const &hist : hists) { body.appendFormat("Histogram %X - ", (int)hist.first.first); handleAuthor(HistogramEntry(entry), &body); drawHistogram(&body, hist.second); } hists.clear(); lastTSs.clear(); case EVENT_HISTOGRAM_FLUSH: { HistogramEntry histEntry(entry); // Log timestamp 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()); hist = mHists.erase(hist); } else { ++hist; } } ++entry; break; } case EVENT_END_FMT: body.appendFormat("warning: got to end format event"); ++entry; Loading Loading @@ -1137,25 +1141,53 @@ static int widthOf(int x) { return width; } static std::map<int, int> buildBuckets(const std::vector<int> &samples) { static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) { // TODO allow buckets of variable resolution std::map<int, int> buckets; for (int x : samples) { ++buckets[x]; for (size_t i = 1; i < samples.size(); ++i) { ++buckets[deltaMs(samples[i - 1], samples[i])]; } return buckets; } static inline uint32_t log2(uint32_t x) { // This works for x > 0 return 31 - __builtin_clz(x); } // TODO put this function in separate file. Make it return a std::string instead of modifying body void NBLog::Reader::drawHistogram(String8 *body, const std::vector<int> &samples, int maxHeight) { /* Example output: [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 Notice that all values that fall in the same row have the same height (65 and 127 are displayed identically). That's why exact counts are added at the top. */ void NBLog::Reader::drawHistogram(String8 *body, const std::vector<int64_t> &samples, bool logScale, int indent, int maxHeight) { if (samples.size() <= 1) { return; } std::map<int, int> buckets = buildBuckets(samples); // TODO add option for log scale // TODO consider changing all ints to uint32_t or uint64_t static const char *underscores = "________________"; static const char *spaces = " "; auto it = buckets.begin(); int maxLabel = it->first; int maxVal = it->second; // Compute maximum values while (++it != buckets.end()) { if (it->first > maxLabel) { maxLabel = it->first; Loading @@ -1164,31 +1196,36 @@ void NBLog::Reader::drawHistogram(String8 *body, const std::vector<int> &samples maxVal = it->second; } } int height = maxVal; 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 scalingFactor = 1; // scale data if it exceeds maximum height if (height > maxHeight) { scalingFactor = (height + maxHeight) / maxHeight; height /= scalingFactor; } body->appendFormat("\n"); // write header 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("\n"); // write histogram ascii art body->appendFormat("\n%*s", indent, " "); for (int row = height * scalingFactor; row > 0; row -= scalingFactor) { body->appendFormat("%*d|", leftPadding, row); int value = ((logScale) ? (1 << row) : row); body->appendFormat("%*u|", leftPadding, value); for (auto const &x : buckets) { body->appendFormat("%.*s%s", colWidth - 2, (row == scalingFactor) ? underscores : spaces, x.second < row ? ((row == scalingFactor) ? "__" : " ") : "[]"); (row <= scalingFactor) ? underscores : spaces, x.second < value ? ((row <= scalingFactor) ? "__" : " ") : "[]"); } body->appendFormat("\n"); body->appendFormat("\n%*s", indent, " "); } // write footer with bucket labels body->appendFormat("%*s", leftPadding + 1, " "); for (auto const &x : buckets) { Loading media/libnbaio/include/NBLog.h +5 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <utils/Mutex.h> #include <utils/threads.h> #include <map> #include <set> #include <vector> Loading Loading @@ -454,6 +455,8 @@ private: audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO, // non-NULL unless constructor fails std::map<std::pair<log_hash_t, int>, std::vector<int64_t>> mHists; void dumpLine(const String8& timestamp, String8& body); EntryIterator handleFormat(const FormatEntry &fmtEntry, Loading @@ -462,7 +465,8 @@ private: // dummy method for handling absent author entry virtual void handleAuthor(const AbstractEntry &fmtEntry, String8 *body) {} static void drawHistogram(String8 *body, const std::vector<int> &samples, int maxHeight = 10); static void drawHistogram(String8 *body, const std::vector<int64_t> &samples, bool logScale, int indent = 0, int maxHeight = 10); // Searches for the last entry of type <type> in the range [front, back) // back has to be entry-aligned. Returns nullptr if none enconuntered. Loading Loading
media/libnbaio/NBLog.cpp +70 −33 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ #include <utils/Log.h> #include <utils/String8.h> #include <map> #include <queue> #include <utility> Loading Loading @@ -848,8 +847,6 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho } bool deferredTimestamp = false; #endif std::map<std::pair<log_hash_t, int>, std::vector<int>> hists; std::map<std::pair<log_hash_t, int>, int64_t*> lastTSs; for (auto entry = snapshot.begin(); entry != snapshot.end();) { switch (entry->type) { Loading Loading @@ -928,31 +925,38 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho // There's probably a more efficient way to do it log_hash_t hash; memcpy(&hash, &(data->hash), sizeof(hash)); int64_t ts; memcpy(&ts, &data->ts, sizeof(ts)); const std::pair<log_hash_t, int> key(hash, data->author); if (lastTSs[key] != nullptr) { int64_t ts1; memcpy(&ts1, lastTSs[key], sizeof(ts1)); int64_t ts2; memcpy(&ts2, &data->ts, sizeof(ts2)); // TODO might want to filter excessively high outliers, which are usually caused // by the thread being inactive. hists[key].push_back(deltaMs(ts1, ts2)); } lastTSs[key] = &(data->ts); mHists[key].push_back(ts); ++entry; break; } case EVENT_HISTOGRAM_FLUSH: body.appendFormat("Histograms:\n"); for (auto const &hist : hists) { body.appendFormat("Histogram %X - ", (int)hist.first.first); handleAuthor(HistogramEntry(entry), &body); drawHistogram(&body, hist.second); } hists.clear(); lastTSs.clear(); case EVENT_HISTOGRAM_FLUSH: { HistogramEntry histEntry(entry); // Log timestamp 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()); hist = mHists.erase(hist); } else { ++hist; } } ++entry; break; } case EVENT_END_FMT: body.appendFormat("warning: got to end format event"); ++entry; Loading Loading @@ -1137,25 +1141,53 @@ static int widthOf(int x) { return width; } static std::map<int, int> buildBuckets(const std::vector<int> &samples) { static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) { // TODO allow buckets of variable resolution std::map<int, int> buckets; for (int x : samples) { ++buckets[x]; for (size_t i = 1; i < samples.size(); ++i) { ++buckets[deltaMs(samples[i - 1], samples[i])]; } return buckets; } static inline uint32_t log2(uint32_t x) { // This works for x > 0 return 31 - __builtin_clz(x); } // TODO put this function in separate file. Make it return a std::string instead of modifying body void NBLog::Reader::drawHistogram(String8 *body, const std::vector<int> &samples, int maxHeight) { /* Example output: [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 Notice that all values that fall in the same row have the same height (65 and 127 are displayed identically). That's why exact counts are added at the top. */ void NBLog::Reader::drawHistogram(String8 *body, const std::vector<int64_t> &samples, bool logScale, int indent, int maxHeight) { if (samples.size() <= 1) { return; } std::map<int, int> buckets = buildBuckets(samples); // TODO add option for log scale // TODO consider changing all ints to uint32_t or uint64_t static const char *underscores = "________________"; static const char *spaces = " "; auto it = buckets.begin(); int maxLabel = it->first; int maxVal = it->second; // Compute maximum values while (++it != buckets.end()) { if (it->first > maxLabel) { maxLabel = it->first; Loading @@ -1164,31 +1196,36 @@ void NBLog::Reader::drawHistogram(String8 *body, const std::vector<int> &samples maxVal = it->second; } } int height = maxVal; 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 scalingFactor = 1; // scale data if it exceeds maximum height if (height > maxHeight) { scalingFactor = (height + maxHeight) / maxHeight; height /= scalingFactor; } body->appendFormat("\n"); // write header 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("\n"); // write histogram ascii art body->appendFormat("\n%*s", indent, " "); for (int row = height * scalingFactor; row > 0; row -= scalingFactor) { body->appendFormat("%*d|", leftPadding, row); int value = ((logScale) ? (1 << row) : row); body->appendFormat("%*u|", leftPadding, value); for (auto const &x : buckets) { body->appendFormat("%.*s%s", colWidth - 2, (row == scalingFactor) ? underscores : spaces, x.second < row ? ((row == scalingFactor) ? "__" : " ") : "[]"); (row <= scalingFactor) ? underscores : spaces, x.second < value ? ((row <= scalingFactor) ? "__" : " ") : "[]"); } body->appendFormat("\n"); body->appendFormat("\n%*s", indent, " "); } // write footer with bucket labels body->appendFormat("%*s", leftPadding + 1, " "); for (auto const &x : buckets) { Loading
media/libnbaio/include/NBLog.h +5 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <utils/Mutex.h> #include <utils/threads.h> #include <map> #include <set> #include <vector> Loading Loading @@ -454,6 +455,8 @@ private: audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO, // non-NULL unless constructor fails std::map<std::pair<log_hash_t, int>, std::vector<int64_t>> mHists; void dumpLine(const String8& timestamp, String8& body); EntryIterator handleFormat(const FormatEntry &fmtEntry, Loading @@ -462,7 +465,8 @@ private: // dummy method for handling absent author entry virtual void handleAuthor(const AbstractEntry &fmtEntry, String8 *body) {} static void drawHistogram(String8 *body, const std::vector<int> &samples, int maxHeight = 10); static void drawHistogram(String8 *body, const std::vector<int64_t> &samples, bool logScale, int indent = 0, int maxHeight = 10); // Searches for the last entry of type <type> in the range [front, back) // back has to be entry-aligned. Returns nullptr if none enconuntered. Loading