Loading media/libnbaio/NBLog.cpp +25 −25 Original line number Diff line number Diff line Loading @@ -69,26 +69,19 @@ * class instances, where the wakeup() intervals are stored as histograms * and analyzed. * * 3) reading the data from private buffer * MediaLogService::dump * calls NBLog::Reader::dump(CONSOLE) * The private buffer contains all logs for all readers in shared memory * NBLog::Reader::dump(int) * calls getSnapshot on the current reader * calls dump(int, size_t, Snapshot) * NBLog::Reader::dump(int, size, snapshot) * iterates through snapshot's events and switches based on their type * (string, timestamp, etc...) * In the case of EVENT_HISTOGRAM_ENTRY_TS, adds a list of timestamp sequences * (histogram entry) to NBLog::mHists * TODO: add every HISTOGRAM_ENTRY_TS to two * circular buffers: one short-term and one long-term (can add even longer-term * structures in the future). When dump is called, print everything currently * in the buffer. * NBLog::drawHistogram * input: timestamp array * buckets this to a histogram and prints * * 3) Dumpsys media.log call to report the data * MediaLogService::dump in MediaLogService.cpp * calls NBLog::Reader::dump, which calls ReportPerformance::dump * ReportPerformance::dump * calls PerformanceAnalysis::ReportPerformance * and ReportPerformance::WriteToFile * PerformanceAnalysis::ReportPerformance * for each thread/source file location instance of PerformanceAnalysis data, * combines all histograms into a single one and prints it to the console * along with outlier data * ReportPerformance::WriteToFile * writes histogram, outlier, and peak information to file separately for each * instance of PerformanceAnalysis data. */ #define LOG_TAG "NBLog" Loading Loading @@ -763,7 +756,8 @@ bool NBLog::LockedWriter::setEnabled(bool enabled) // --------------------------------------------------------------------------- const std::set<NBLog::Event> NBLog::Reader::startingTypes {NBLog::Event::EVENT_START_FMT, NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS}; NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS, NBLog::Event::EVENT_AUDIO_STATE}; const std::set<NBLog::Event> NBLog::Reader::endingTypes {NBLog::Event::EVENT_END_FMT, NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS, NBLog::Event::EVENT_AUDIO_STATE}; Loading Loading @@ -903,7 +897,9 @@ void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot memcpy(&hash, &(data->hash), sizeof(hash)); int64_t ts; memcpy(&ts, &data->ts, sizeof(ts)); mThreadPerformanceAnalysis[data->author][hash].logTsEntry(ts); // TODO: hash for histogram ts and audio state need to match // and correspond to audio production source file location mThreadPerformanceAnalysis[data->author][0 /*hash*/].logTsEntry(ts); ++entry; break; } Loading @@ -913,7 +909,10 @@ void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot // There's probably a more efficient way to do it log_hash_t hash; memcpy(&hash, &(data->hash), sizeof(hash)); mThreadPerformanceAnalysis[data->author][hash].handleStateChange(); // TODO: remove ts if unused int64_t ts; memcpy(&ts, &data->ts, sizeof(ts)); mThreadPerformanceAnalysis[data->author][0 /*hash*/].handleStateChange(); ++entry; break; } Loading Loading @@ -942,6 +941,7 @@ void NBLog::MergeReader::getAndProcessSnapshot() } void NBLog::MergeReader::dump(int fd, int indent) { // TODO: add a mutex around media.log dump ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis); } Loading media/libnbaio/PerformanceAnalysis.cpp +45 −71 Original line number Diff line number Diff line Loading @@ -62,34 +62,38 @@ static int widthOf(int x) { return width; } // Given a series of audio processing wakeup timestamps, // buckets the time intervals into a histogram, searches for // Given a the most recent timestamp of a series of audio processing // wakeup timestamps, // buckets the time interval into a histogram, searches for // outliers, analyzes the outlier series for unexpectedly // small or large values and stores these as peaks, and flushes // the timestamp series from memory. void PerformanceAnalysis::processAndFlushTimeStampSeries() { if (mTimeStampSeries.empty()) { // small or large values and stores these as peaks void PerformanceAnalysis::logTsEntry(int64_t ts) { // after a state change, start a new series and do not // record time intervals in-between if (mOutlierDistribution.mPrevTs == 0) { mOutlierDistribution.mPrevTs = ts; return; } // TODO: add mPrev ts depending on whether or not handleStateChange was called for (size_t i = 1; i < mTimeStampSeries.size(); i++) { // Check whether the current timestamp is an outlier const bool isOutlier = detectAndStoreOutlier(mTimeStampSeries[i]); // Check whether the time interval between the current timestamp // and the previous one is long enough to count as an outlier const bool isOutlier = detectAndStoreOutlier(ts); // If an outlier was found, check whether it was a peak if (isOutlier) { /*bool isPeak =*/ detectAndStorePeak( mOutlierData[0].first, mOutlierData[0].second); // TODO: decide whether to insert a new empty histogram if a peak // TODO: remove isPeak if unused to avoid "unused variable" error // occurred at the current timestamp } // Insert a histogram to mHists if it is empty, or // close the current histogram and insert a new empty one if // if the current histogram has spanned its maximum time interval. // Also insert a new empty histogram if a change in behavior (peak) // occurred at the current timestamp if (mHists.empty() || deltaMs(mHists[0].first, mTimeStampSeries[i]) >= kMaxLength.HistTimespanMs) { mHists.emplace_front(static_cast<uint64_t>(mTimeStampSeries[i]), std::map<int, int>()); if (mHists.empty() || deltaMs(mHists[0].first, ts) >= kMaxLength.HistTimespanMs) { mHists.emplace_front(static_cast<uint64_t>(ts), std::map<int, int>()); // When memory is full, delete oldest histogram // TODO: use a circular buffer if (mHists.size() >= kMaxLength.Hists) { Loading @@ -97,38 +101,19 @@ void PerformanceAnalysis::processAndFlushTimeStampSeries() { } } // add current time intervals to histogram ++mHists[0].second[deltaMs(mTimeStampSeries[i-1], mTimeStampSeries[i])]; ++mHists[0].second[deltaMs(mOutlierDistribution.mPrevTs, ts)]; // update previous timestamp mOutlierDistribution.mPrevTs = ts; } // clear the timestamps mTimeStampSeries.clear(); // reset outlier values mOutlierDistribution.mPrevNs = -1; } // forces short-term histogram storage to avoid adding idle audio time interval // to buffer period data void PerformanceAnalysis::handleStateChange() { ALOGD("handleStateChange"); processAndFlushTimeStampSeries(); mOutlierDistribution.mPrevTs = 0; return; } // Takes a single buffer period timestamp entry information and stores it in a // temporary series of timestamps. Once the series is full, the data is analyzed, // stored, and emptied. void PerformanceAnalysis::logTsEntry(int64_t ts) { // TODO might want to filter excessively high outliers, which are usually caused // by the thread being inactive. // Store time series data for each reader in order to bucket it once there // is enough data. Then, write to recentHists as a histogram. 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() >= kMaxLength.TimeStamps) { processAndFlushTimeStampSeries(); } } // Checks whether the time interval between two outliers is far enough from // a typical delta to be considered a peak. Loading @@ -140,7 +125,6 @@ void PerformanceAnalysis::logTsEntry(int64_t ts) { bool PerformanceAnalysis::detectAndStorePeak(outlierInterval diff, timestamp ts) { bool isPeak = false; if (mOutlierData.empty()) { ALOGD("mOutlierData is empty"); return false; } // Update mean of the distribution Loading Loading @@ -173,7 +157,7 @@ bool PerformanceAnalysis::detectAndStorePeak(outlierInterval diff, timestamp ts) const double kDelta2 = diff - mOutlierDistribution.mMean; mOutlierDistribution.mM2 += kDelta * kDelta2; mOutlierDistribution.mSd = (mOutlierDistribution.mN < 2) ? 0 : mOutlierDistribution.mM2 / (mOutlierDistribution.mN - 1); sqrt(mOutlierDistribution.mM2 / (mOutlierDistribution.mN - 1)); } else { // new value is far from the mean: // store peak timestamp and reset mean, sd, and short-term sequence Loading @@ -196,25 +180,19 @@ bool PerformanceAnalysis::detectAndStorePeak(outlierInterval diff, timestamp ts) return isPeak; } // Determines whether the difference between a timestamp and the previous // one is beyond a threshold. If yes, stores the timestamp as an outlier // and writes to mOutlierdata in the following format: // Time elapsed since previous outlier: Timestamp of start of outlier // e.g. timestamps (ms) 1, 4, 5, 16, 18, 28 will produce pairs (4, 5), (13, 18). bool PerformanceAnalysis::detectAndStoreOutlier(const int64_t ts) { // first pass: need to initialize if (mOutlierDistribution.mPrevNs == -1) { mOutlierDistribution.mPrevNs = ts; } bool isOutlier = false; const uint64_t diffMs = static_cast<uint64_t>(deltaMs(mOutlierDistribution.mPrevNs, ts)); // ALOGD("%d\t", static_cast<int>(diffMs)); if (diffMs >= static_cast<uint64_t>(kOutlierMs)) { const int64_t diffMs = static_cast<int64_t>(deltaMs(mOutlierDistribution.mPrevTs, ts)); if (diffMs >= static_cast<int64_t>(kOutlierMs)) { isOutlier = true; //ALOGD("outlier outlier %d %d", static_cast<int>(diffMs), // static_cast<int>(mOutlierDistribution.mElapsed)); mOutlierData.emplace_front(mOutlierDistribution.mElapsed, static_cast<uint64_t>(mOutlierDistribution.mPrevNs)); static_cast<uint64_t>(mOutlierDistribution.mPrevTs)); // Remove oldest value if the vector is full // TODO: turn this into a circular buffer // TODO: make sure kShortHistSize is large enough that that data will never be lost Loading @@ -225,10 +203,10 @@ bool PerformanceAnalysis::detectAndStoreOutlier(const int64_t ts) { mOutlierDistribution.mElapsed = 0; } mOutlierDistribution.mElapsed += diffMs; mOutlierDistribution.mPrevNs = ts; return isOutlier; } // 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 Loading @@ -237,7 +215,6 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { ALOGD("reportPerformance: mHists is empty"); return; } ALOGD("reportPerformance: hists size %d", static_cast<int>(mHists.size())); std::map<int, int> buckets; for (const auto &shortHist: mHists) { Loading Loading @@ -312,6 +289,7 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { } } // TODO: decide whether to use this or whether it is overkill, and it is enough // to only treat as glitches single wakeup call intervals which are too long. // Ultimately, glitch detection will be directly on the audio signal. Loading @@ -329,7 +307,6 @@ void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) { // TODO: check that all glitch cases are covered if (std::accumulate(periods.begin(), periods.end(), 0) > kNumBuff * kPeriodMs + kPeriodMs - kPeriodMsCPU) { ALOGW("A glitch occurred"); periods.assign(kNumBuff, kPeriodMs); } } Loading @@ -341,14 +318,10 @@ void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) { // writes summary of performance into specified file descriptor void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) { String8 body; int i = 0; // TODO: delete const char* const kDirectory = "/data/misc/audioserver/"; for (auto & thread : threadPerformanceAnalysis) { for (auto & hash: thread.second) { ALOGD("hash number %d", i++); PerformanceAnalysis& curr = hash.second; // Add any new data curr.processAndFlushTimeStampSeries(); // write performance data to console curr.reportPerformance(&body); if (!body.isEmpty()) { Loading @@ -362,6 +335,7 @@ void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) } } // Writes a string into specified file descriptor void dumpLine(int fd, int indent, const String8 &body) { dprintf(fd, "%.*s%s \n", indent, "", body.string()); Loading media/libnbaio/include/media/nbaio/NBLog.h +0 −2 Original line number Diff line number Diff line Loading @@ -252,8 +252,6 @@ private: int author; }; //TODO __attribute__((packed)); using StateTsEntryWithAuthor = HistTsEntryWithAuthor; struct HistIntEntry { log_hash_t hash; int value; Loading media/libnbaio/include/media/nbaio/PerformanceAnalysis.h +3 −5 Original line number Diff line number Diff line Loading @@ -100,10 +100,6 @@ private: // stores buffer period histograms with timestamp of first sample std::deque<std::pair<timestamp, Histogram>> mHists; // 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; // Parameters used when detecting outliers // TODO: learn some of these from the data, delete unused ones // TODO: put used variables in a struct Loading @@ -130,11 +126,13 @@ private: // these variables are stored in-class to ensure continuity while analyzing the timestamp // series one short sequence at a time: the variables are not re-initialized every time. // TODO: use m prefix // TODO: change this to a running variance/mean class struct OutlierDistribution { double mMean = 0; // sample mean since previous peak double mSd = 0; // sample sd since previous peak outlierInterval mElapsed = 0; // time since previous detected outlier int64_t mPrevNs = -1; // previous timestamp int64_t mPrevTs = -1; // previous timestamp // number of standard deviations from mean considered a significant change const int kMaxDeviation = 5; double mTypicalDiff = 0; // global mean of outliers Loading services/audioflinger/FastMixer.cpp +7 −3 Original line number Diff line number Diff line Loading @@ -138,8 +138,6 @@ bool FastMixer::isSubClassCommand(FastThreadState::Command command) void FastMixer::onStateChange() { // log that audio was turned on/off LOG_AUDIO_STATE(); const FastMixerState * const current = (const FastMixerState *) mCurrent; const FastMixerState * const previous = (const FastMixerState *) mPrevious; FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState; Loading Loading @@ -336,7 +334,13 @@ void FastMixer::onStateChange() void FastMixer::onWork() { // TODO: pass an ID parameter to indicate which time series we want to write to in NBLog.cpp // Or: pass both of these into a single call with a boolean if (mIsWarm) { LOG_HIST_TS(); } else { LOG_AUDIO_STATE(); } const FastMixerState * const current = (const FastMixerState *) mCurrent; FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState; const FastMixerState::Command command = mCommand; Loading Loading
media/libnbaio/NBLog.cpp +25 −25 Original line number Diff line number Diff line Loading @@ -69,26 +69,19 @@ * class instances, where the wakeup() intervals are stored as histograms * and analyzed. * * 3) reading the data from private buffer * MediaLogService::dump * calls NBLog::Reader::dump(CONSOLE) * The private buffer contains all logs for all readers in shared memory * NBLog::Reader::dump(int) * calls getSnapshot on the current reader * calls dump(int, size_t, Snapshot) * NBLog::Reader::dump(int, size, snapshot) * iterates through snapshot's events and switches based on their type * (string, timestamp, etc...) * In the case of EVENT_HISTOGRAM_ENTRY_TS, adds a list of timestamp sequences * (histogram entry) to NBLog::mHists * TODO: add every HISTOGRAM_ENTRY_TS to two * circular buffers: one short-term and one long-term (can add even longer-term * structures in the future). When dump is called, print everything currently * in the buffer. * NBLog::drawHistogram * input: timestamp array * buckets this to a histogram and prints * * 3) Dumpsys media.log call to report the data * MediaLogService::dump in MediaLogService.cpp * calls NBLog::Reader::dump, which calls ReportPerformance::dump * ReportPerformance::dump * calls PerformanceAnalysis::ReportPerformance * and ReportPerformance::WriteToFile * PerformanceAnalysis::ReportPerformance * for each thread/source file location instance of PerformanceAnalysis data, * combines all histograms into a single one and prints it to the console * along with outlier data * ReportPerformance::WriteToFile * writes histogram, outlier, and peak information to file separately for each * instance of PerformanceAnalysis data. */ #define LOG_TAG "NBLog" Loading Loading @@ -763,7 +756,8 @@ bool NBLog::LockedWriter::setEnabled(bool enabled) // --------------------------------------------------------------------------- const std::set<NBLog::Event> NBLog::Reader::startingTypes {NBLog::Event::EVENT_START_FMT, NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS}; NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS, NBLog::Event::EVENT_AUDIO_STATE}; const std::set<NBLog::Event> NBLog::Reader::endingTypes {NBLog::Event::EVENT_END_FMT, NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS, NBLog::Event::EVENT_AUDIO_STATE}; Loading Loading @@ -903,7 +897,9 @@ void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot memcpy(&hash, &(data->hash), sizeof(hash)); int64_t ts; memcpy(&ts, &data->ts, sizeof(ts)); mThreadPerformanceAnalysis[data->author][hash].logTsEntry(ts); // TODO: hash for histogram ts and audio state need to match // and correspond to audio production source file location mThreadPerformanceAnalysis[data->author][0 /*hash*/].logTsEntry(ts); ++entry; break; } Loading @@ -913,7 +909,10 @@ void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot // There's probably a more efficient way to do it log_hash_t hash; memcpy(&hash, &(data->hash), sizeof(hash)); mThreadPerformanceAnalysis[data->author][hash].handleStateChange(); // TODO: remove ts if unused int64_t ts; memcpy(&ts, &data->ts, sizeof(ts)); mThreadPerformanceAnalysis[data->author][0 /*hash*/].handleStateChange(); ++entry; break; } Loading Loading @@ -942,6 +941,7 @@ void NBLog::MergeReader::getAndProcessSnapshot() } void NBLog::MergeReader::dump(int fd, int indent) { // TODO: add a mutex around media.log dump ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis); } Loading
media/libnbaio/PerformanceAnalysis.cpp +45 −71 Original line number Diff line number Diff line Loading @@ -62,34 +62,38 @@ static int widthOf(int x) { return width; } // Given a series of audio processing wakeup timestamps, // buckets the time intervals into a histogram, searches for // Given a the most recent timestamp of a series of audio processing // wakeup timestamps, // buckets the time interval into a histogram, searches for // outliers, analyzes the outlier series for unexpectedly // small or large values and stores these as peaks, and flushes // the timestamp series from memory. void PerformanceAnalysis::processAndFlushTimeStampSeries() { if (mTimeStampSeries.empty()) { // small or large values and stores these as peaks void PerformanceAnalysis::logTsEntry(int64_t ts) { // after a state change, start a new series and do not // record time intervals in-between if (mOutlierDistribution.mPrevTs == 0) { mOutlierDistribution.mPrevTs = ts; return; } // TODO: add mPrev ts depending on whether or not handleStateChange was called for (size_t i = 1; i < mTimeStampSeries.size(); i++) { // Check whether the current timestamp is an outlier const bool isOutlier = detectAndStoreOutlier(mTimeStampSeries[i]); // Check whether the time interval between the current timestamp // and the previous one is long enough to count as an outlier const bool isOutlier = detectAndStoreOutlier(ts); // If an outlier was found, check whether it was a peak if (isOutlier) { /*bool isPeak =*/ detectAndStorePeak( mOutlierData[0].first, mOutlierData[0].second); // TODO: decide whether to insert a new empty histogram if a peak // TODO: remove isPeak if unused to avoid "unused variable" error // occurred at the current timestamp } // Insert a histogram to mHists if it is empty, or // close the current histogram and insert a new empty one if // if the current histogram has spanned its maximum time interval. // Also insert a new empty histogram if a change in behavior (peak) // occurred at the current timestamp if (mHists.empty() || deltaMs(mHists[0].first, mTimeStampSeries[i]) >= kMaxLength.HistTimespanMs) { mHists.emplace_front(static_cast<uint64_t>(mTimeStampSeries[i]), std::map<int, int>()); if (mHists.empty() || deltaMs(mHists[0].first, ts) >= kMaxLength.HistTimespanMs) { mHists.emplace_front(static_cast<uint64_t>(ts), std::map<int, int>()); // When memory is full, delete oldest histogram // TODO: use a circular buffer if (mHists.size() >= kMaxLength.Hists) { Loading @@ -97,38 +101,19 @@ void PerformanceAnalysis::processAndFlushTimeStampSeries() { } } // add current time intervals to histogram ++mHists[0].second[deltaMs(mTimeStampSeries[i-1], mTimeStampSeries[i])]; ++mHists[0].second[deltaMs(mOutlierDistribution.mPrevTs, ts)]; // update previous timestamp mOutlierDistribution.mPrevTs = ts; } // clear the timestamps mTimeStampSeries.clear(); // reset outlier values mOutlierDistribution.mPrevNs = -1; } // forces short-term histogram storage to avoid adding idle audio time interval // to buffer period data void PerformanceAnalysis::handleStateChange() { ALOGD("handleStateChange"); processAndFlushTimeStampSeries(); mOutlierDistribution.mPrevTs = 0; return; } // Takes a single buffer period timestamp entry information and stores it in a // temporary series of timestamps. Once the series is full, the data is analyzed, // stored, and emptied. void PerformanceAnalysis::logTsEntry(int64_t ts) { // TODO might want to filter excessively high outliers, which are usually caused // by the thread being inactive. // Store time series data for each reader in order to bucket it once there // is enough data. Then, write to recentHists as a histogram. 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() >= kMaxLength.TimeStamps) { processAndFlushTimeStampSeries(); } } // Checks whether the time interval between two outliers is far enough from // a typical delta to be considered a peak. Loading @@ -140,7 +125,6 @@ void PerformanceAnalysis::logTsEntry(int64_t ts) { bool PerformanceAnalysis::detectAndStorePeak(outlierInterval diff, timestamp ts) { bool isPeak = false; if (mOutlierData.empty()) { ALOGD("mOutlierData is empty"); return false; } // Update mean of the distribution Loading Loading @@ -173,7 +157,7 @@ bool PerformanceAnalysis::detectAndStorePeak(outlierInterval diff, timestamp ts) const double kDelta2 = diff - mOutlierDistribution.mMean; mOutlierDistribution.mM2 += kDelta * kDelta2; mOutlierDistribution.mSd = (mOutlierDistribution.mN < 2) ? 0 : mOutlierDistribution.mM2 / (mOutlierDistribution.mN - 1); sqrt(mOutlierDistribution.mM2 / (mOutlierDistribution.mN - 1)); } else { // new value is far from the mean: // store peak timestamp and reset mean, sd, and short-term sequence Loading @@ -196,25 +180,19 @@ bool PerformanceAnalysis::detectAndStorePeak(outlierInterval diff, timestamp ts) return isPeak; } // Determines whether the difference between a timestamp and the previous // one is beyond a threshold. If yes, stores the timestamp as an outlier // and writes to mOutlierdata in the following format: // Time elapsed since previous outlier: Timestamp of start of outlier // e.g. timestamps (ms) 1, 4, 5, 16, 18, 28 will produce pairs (4, 5), (13, 18). bool PerformanceAnalysis::detectAndStoreOutlier(const int64_t ts) { // first pass: need to initialize if (mOutlierDistribution.mPrevNs == -1) { mOutlierDistribution.mPrevNs = ts; } bool isOutlier = false; const uint64_t diffMs = static_cast<uint64_t>(deltaMs(mOutlierDistribution.mPrevNs, ts)); // ALOGD("%d\t", static_cast<int>(diffMs)); if (diffMs >= static_cast<uint64_t>(kOutlierMs)) { const int64_t diffMs = static_cast<int64_t>(deltaMs(mOutlierDistribution.mPrevTs, ts)); if (diffMs >= static_cast<int64_t>(kOutlierMs)) { isOutlier = true; //ALOGD("outlier outlier %d %d", static_cast<int>(diffMs), // static_cast<int>(mOutlierDistribution.mElapsed)); mOutlierData.emplace_front(mOutlierDistribution.mElapsed, static_cast<uint64_t>(mOutlierDistribution.mPrevNs)); static_cast<uint64_t>(mOutlierDistribution.mPrevTs)); // Remove oldest value if the vector is full // TODO: turn this into a circular buffer // TODO: make sure kShortHistSize is large enough that that data will never be lost Loading @@ -225,10 +203,10 @@ bool PerformanceAnalysis::detectAndStoreOutlier(const int64_t ts) { mOutlierDistribution.mElapsed = 0; } mOutlierDistribution.mElapsed += diffMs; mOutlierDistribution.mPrevNs = ts; return isOutlier; } // 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 Loading @@ -237,7 +215,6 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { ALOGD("reportPerformance: mHists is empty"); return; } ALOGD("reportPerformance: hists size %d", static_cast<int>(mHists.size())); std::map<int, int> buckets; for (const auto &shortHist: mHists) { Loading Loading @@ -312,6 +289,7 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { } } // TODO: decide whether to use this or whether it is overkill, and it is enough // to only treat as glitches single wakeup call intervals which are too long. // Ultimately, glitch detection will be directly on the audio signal. Loading @@ -329,7 +307,6 @@ void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) { // TODO: check that all glitch cases are covered if (std::accumulate(periods.begin(), periods.end(), 0) > kNumBuff * kPeriodMs + kPeriodMs - kPeriodMsCPU) { ALOGW("A glitch occurred"); periods.assign(kNumBuff, kPeriodMs); } } Loading @@ -341,14 +318,10 @@ void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) { // writes summary of performance into specified file descriptor void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) { String8 body; int i = 0; // TODO: delete const char* const kDirectory = "/data/misc/audioserver/"; for (auto & thread : threadPerformanceAnalysis) { for (auto & hash: thread.second) { ALOGD("hash number %d", i++); PerformanceAnalysis& curr = hash.second; // Add any new data curr.processAndFlushTimeStampSeries(); // write performance data to console curr.reportPerformance(&body); if (!body.isEmpty()) { Loading @@ -362,6 +335,7 @@ void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) } } // Writes a string into specified file descriptor void dumpLine(int fd, int indent, const String8 &body) { dprintf(fd, "%.*s%s \n", indent, "", body.string()); Loading
media/libnbaio/include/media/nbaio/NBLog.h +0 −2 Original line number Diff line number Diff line Loading @@ -252,8 +252,6 @@ private: int author; }; //TODO __attribute__((packed)); using StateTsEntryWithAuthor = HistTsEntryWithAuthor; struct HistIntEntry { log_hash_t hash; int value; Loading
media/libnbaio/include/media/nbaio/PerformanceAnalysis.h +3 −5 Original line number Diff line number Diff line Loading @@ -100,10 +100,6 @@ private: // stores buffer period histograms with timestamp of first sample std::deque<std::pair<timestamp, Histogram>> mHists; // 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; // Parameters used when detecting outliers // TODO: learn some of these from the data, delete unused ones // TODO: put used variables in a struct Loading @@ -130,11 +126,13 @@ private: // these variables are stored in-class to ensure continuity while analyzing the timestamp // series one short sequence at a time: the variables are not re-initialized every time. // TODO: use m prefix // TODO: change this to a running variance/mean class struct OutlierDistribution { double mMean = 0; // sample mean since previous peak double mSd = 0; // sample sd since previous peak outlierInterval mElapsed = 0; // time since previous detected outlier int64_t mPrevNs = -1; // previous timestamp int64_t mPrevTs = -1; // previous timestamp // number of standard deviations from mean considered a significant change const int kMaxDeviation = 5; double mTypicalDiff = 0; // global mean of outliers Loading
services/audioflinger/FastMixer.cpp +7 −3 Original line number Diff line number Diff line Loading @@ -138,8 +138,6 @@ bool FastMixer::isSubClassCommand(FastThreadState::Command command) void FastMixer::onStateChange() { // log that audio was turned on/off LOG_AUDIO_STATE(); const FastMixerState * const current = (const FastMixerState *) mCurrent; const FastMixerState * const previous = (const FastMixerState *) mPrevious; FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState; Loading Loading @@ -336,7 +334,13 @@ void FastMixer::onStateChange() void FastMixer::onWork() { // TODO: pass an ID parameter to indicate which time series we want to write to in NBLog.cpp // Or: pass both of these into a single call with a boolean if (mIsWarm) { LOG_HIST_TS(); } else { LOG_AUDIO_STATE(); } const FastMixerState * const current = (const FastMixerState *) mCurrent; FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState; const FastMixerState::Command command = mCommand; Loading