Moved analysis work from NBLog to PerformanceAnalysis
Test: dumpsys media.log
Change-Id: Ibb595a25d7484840933ee0076c469b2b4d55aeec
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index d590283..73adff6 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -121,6 +121,7 @@
#include <new>
#include <audio_utils/roundup.h>
#include <media/nbaio/NBLog.h>
+#include <media/nbaio/PerformanceAnalysis.h>
// #include <utils/CallStack.h> // used to print callstack
#include <utils/Log.h>
#include <utils/String8.h>
@@ -797,8 +798,7 @@
mFifo(mShared != NULL ?
new audio_utils_fifo(size, sizeof(uint8_t),
mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
- mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL),
- findGlitch(false)
+ mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
{
}
@@ -814,39 +814,6 @@
delete mFifo;
}
-inline static int deltaMs(int64_t ns1, int64_t ns2) {
- return (ns2 - ns1) / (1000 * 1000);
-}
-
-// Produces a log warning if the timing of recent buffer periods caused a glitch
-// Computes sum of running window of three buffer periods
-// Checks whether the buffer periods leave enough CPU time for the next one
-// e.g. if a buffer period is expected to be 4 ms and a buffer requires 3 ms of CPU time,
-// here are some glitch cases:
-// 4 + 4 + 6 ; 5 + 4 + 5; 2 + 2 + 10
-// TODO: develop this code to track changes in histogram distribution in addition
-// to / instead of glitches
-void NBLog::Reader::alertIfGlitch(const std::vector<int64_t> &samples) {
- //TODO: measure kPeriodLen and kRatio from the data as they may change.
- static const int kPeriodLen = 4; // current period length is ideally 4 ms
- static const double kRatio = 0.75; // estimate of CPU time as ratio of period length
- // DAC processing time for 4 ms buffer
- static const int kPeriodTime = static_cast<int>(round(kPeriodLen * kRatio));
- static const int kNumBuff = 3; // number of buffers considered in local history
- std::deque<int> periods(kNumBuff, kPeriodLen);
- for (size_t i = 2; i < samples.size(); ++i) { // skip first time entry
- periods.push_front(deltaMs(samples[i - 1], samples[i]));
- periods.pop_back();
- // TODO: check that all glitch cases are covered
- if (std::accumulate(periods.begin(), periods.end(), 0) > kNumBuff * kPeriodLen +
- kPeriodLen - kPeriodTime) {
- ALOGW("A glitch occurred");
- periods.assign(kNumBuff, kPeriodLen);
- }
- }
- return;
-}
-
const uint8_t *NBLog::Reader::findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
const std::set<Event> &types) {
while (back + Entry::kPreviousLengthOffset >= front) {
@@ -1033,11 +1000,9 @@
++entry;
break;
}
- // if (!body.isEmpty()) {
- // dumpLine(timestamp, body);
- // }
}
- reportPerformance(&body, mRecentHists);
+ PerformanceAnalysis performanceAnalyzer;
+ performanceAnalyzer.reportPerformance(&body, mRecentHists);
if (!body.isEmpty()) {
dumpLine(timestamp, body);
}
@@ -1065,16 +1030,6 @@
return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
}
-void NBLog::Reader::setFindGlitch(bool s)
-{
- findGlitch = s;
-}
-
-bool NBLog::Reader::isFindGlitch() const
-{
- return findGlitch;
-}
-
// ---------------------------------------------------------------------------
void NBLog::appendTimestamp(String8 *body, const void *data) {
@@ -1209,178 +1164,6 @@
return arg;
}
-static int widthOf(int x) {
- int width = 0;
- while (x > 0) {
- ++width;
- x /= 10;
- }
- return width;
-}
-
-static inline uint32_t log2(uint32_t x) {
- // This works for x > 0
- return 31 - __builtin_clz(x);
-}
-
-// TODO create a subclass of Reader for this and related work
-void NBLog::Reader::reportPerformance(String8 *body,
- const std::deque<std::pair
- <int, short_histogram>> &shortHists,
- int maxHeight) {
- if (shortHists.size() < 1) {
- return;
- }
- // this is temporary code, which only prints out one histogram
- // of all data stored in buffer. The data is not erased, only overwritten.
- // TODO: more elaborate data analysis
- std::map<int, int> buckets;
- for (const auto &shortHist: shortHists) {
- for (const auto &countPair : shortHist.second) {
- buckets[countPair.first] += countPair.second;
- }
- }
-
- // 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 maxDelta = it->first;
- int maxCount = it->second;
- // Compute maximum values
- while (++it != buckets.end()) {
- if (it->first > maxDelta) {
- maxDelta = it->first;
- }
- if (it->second > maxCount) {
- maxCount = it->second;
- }
- }
- int height = log2(maxCount) + 1; // maxCount > 0, safe to call log2
- const int leftPadding = widthOf(1 << height);
- 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;
- }
- body->appendFormat("\n%*s", leftPadding + 11, "Occurrences");
- // write histogram label line with bucket values
- body->appendFormat("\n%s", " ");
- body->appendFormat("%*s", leftPadding, " ");
- for (auto const &x : buckets) {
- body->appendFormat("%*d", colWidth, x.second);
- }
- // write histogram ascii art
- body->appendFormat("\n%s", " ");
- for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) {
- const int value = 1 << row;
- body->appendFormat("%.*s", leftPadding, spaces.c_str());
- for (auto const &x : buckets) {
- body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|");
- }
- body->appendFormat("\n%s", " ");
- }
- // 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", " ");
-
- // write footer with bucket labels
- body->appendFormat("%*s", leftPadding, " ");
- for (auto const &x : buckets) {
- body->appendFormat("%*d", colWidth, x.first);
- }
- body->appendFormat("%.*s%s", colWidth, spaces.c_str(), "ms\n");
-
-}
-
-// 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<int64_t> &samples,
- bool logScale,
- int indent,
- int maxHeight) {
- // this avoids some corner cases
- if (samples.size() <= 1) {
- return;
- }
- // temp code for debugging the outlier timestamp
- const int kMaxMs = 100;
- for (size_t i = 1; i < samples.size()-1; ++i) {
- const int currDelta = deltaMs(samples[i - 1], samples[i]);
- if (currDelta > kMaxMs) {
- body->appendFormat("\nlocation: %zu, size: %zu, pos from end: %zu, %d\t", i,
- samples.size(), samples.size() - i, currDelta);
- }
- }
- // FIXME: as can be seen when printing the values, the outlier timestamps typically occur
- // in the first histogram 35 to 38 indices from the end (most often 35).
- // TODO: build histogram buckets earlier and discard timestamps to save memory
- std::map<int, int> buckets = buildBuckets(samples);
- // TODO consider changing all ints to uint32_t or uint64_t
-
- // 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 maxDelta = it->first;
- int maxCount = it->second;
- // Compute maximum values
- while (++it != buckets.end()) {
- if (it->first > maxDelta) {
- maxDelta = it->first;
- }
- if (it->second > maxCount) {
- maxCount = it->second;
- }
- }
- int height = logScale ? log2(maxCount) + 1 : maxCount; // maxCount > 0, safe to call log2
- const int leftPadding = widthOf(logScale ? 1 << 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;
- }
- body->appendFormat("\n%*s", leftPadding + 11, "Occurrences");
- // write histogram label line with bucket values
- body->appendFormat("\n%*s", indent, " ");
- 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) {
- const int value = logScale ? (1 << row) : row;
- body->appendFormat("%.*s", leftPadding, spaces.c_str());
- for (auto const &x : buckets) {
- 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, " ");
- for (auto const &x : buckets) {
- body->appendFormat("%*d", colWidth, x.first);
- }
- 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 ?