Loading media/libnbaio/PerformanceAnalysis.cpp +62 −52 Original line number Diff line number Diff line Loading @@ -46,16 +46,6 @@ namespace android { namespace ReportPerformance { static int widthOf(int x) { int width = 0; while (x > 0) { ++width; x /= 10; } return width; } // Given a the most recent timestamp of a series of audio processing // wakeup timestamps, // buckets the time interval into a histogram, searches for Loading @@ -75,8 +65,6 @@ void PerformanceAnalysis::logTsEntry(timestamp ts) { const int diffJiffy = deltaJiffy(mBufferPeriod.mPrevTs, ts); // update buffer period distribution // old versus new weight ratio when updating the buffer period mean static constexpr double exponentialWeight = 0.999; // update buffer period mean with exponential weighting Loading Loading @@ -200,6 +188,8 @@ bool PerformanceAnalysis::detectAndStorePeak(msInterval diff, timestamp ts) { // 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). // TODO: learn what timestamp sequences correlate with glitches instead of // manually designing a heuristic. bool PerformanceAnalysis::detectAndStoreOutlier(const msInterval diffMs) { bool isOutlier = false; if (diffMs >= mBufferPeriod.mOutlier) { Loading @@ -219,32 +209,73 @@ bool PerformanceAnalysis::detectAndStoreOutlier(const msInterval diffMs) { return isOutlier; } static int widthOf(int x) { int width = 0; if (x < 0) { width++; x = x == INT_MIN ? INT_MAX : -x; } // assert (x >= 0) do { ++width; x /= 10; } while (x > 0); return width; } // computes the column width required for a specific histogram value inline int numberWidth(int number, int leftPadding) { return std::max(std::max(widthOf(number) + 4, 3), leftPadding + 2); inline int numberWidth(double number, int leftPadding) { // Added values account for whitespaces needed around numbers, and for the // dot and decimal digit not accounted for by widthOf return std::max(std::max(widthOf(static_cast<int>(number)) + 3, 2), leftPadding + 1); } // rounds value to precision based on log-distance from mean inline double logRound(double x, double mean) { // Larger values increase range of high resolution constexpr double kBase = 2; const double power = floor( log(abs(x - mean) / mean) / log(kBase)) + 1; // do not round values close to the mean if (power < 1) { return x; } const int factor = static_cast<int>(pow(10, power)); return (static_cast<int>(x) * factor) / factor; } // TODO Make it return a std::string instead of modifying body // TODO: move this to ReportPerformance, probably make it a friend function of PerformanceAnalysis void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { // TODO: move this to ReportPerformance, probably make it a friend function // of PerformanceAnalysis void PerformanceAnalysis::reportPerformance(String8 *body, int author, log_hash_t hash, int maxHeight) { if (mHists.empty()) { return; } std::map<int, int> buckets; // ms of active audio in displayed histogram double elapsedMs = 0; // starting timestamp of histogram timestamp startingTs = mHists[0].first; // histogram which stores .1 precision ms counts instead of Jiffy multiple counts // TODO: when there is more data, print many histograms, possibly separated at peaks std::map<double, int> buckets; for (const auto &shortHist: mHists) { for (const auto &countPair : shortHist.second) { buckets[countPair.first] += countPair.second; const double ms = static_cast<double>(countPair.first) / kJiffyPerMs; buckets[logRound(ms, mBufferPeriod.mMean)] += countPair.second; elapsedMs += ms; } } // underscores and spaces length corresponds to maximum width of histogram static const int kLen = 100; static const int kLen = 200; std::string underscores(kLen, '_'); std::string spaces(kLen, ' '); auto it = buckets.begin(); int maxDelta = it->first; double maxDelta = it->first; int maxCount = it->second; // Compute maximum values while (++it != buckets.end()) { Loading @@ -264,13 +295,16 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { scalingFactor = (height + maxHeight) / maxHeight; height /= scalingFactor; } // TODO: print reader (author) ID body->appendFormat("\n%*s", leftPadding + 11, "Occurrences"); body->appendFormat("\n%*s %3.2f %s", leftPadding + 11, "Occurrences in", (elapsedMs / kMsPerSec), "seconds of audio:"); body->appendFormat("\n%*s%d, %lld, %lld\n", leftPadding + 11, "Thread, hash, starting timestamp: ", author, static_cast<long long int>(hash), static_cast<long long int>(startingTs)); // write histogram label line with bucket values body->appendFormat("\n%s", " "); body->appendFormat("%*s", leftPadding, " "); for (auto const &x : buckets) { const int colWidth = numberWidth(x.first / kJiffyPerMs, leftPadding); const int colWidth = numberWidth(x.first, leftPadding); body->appendFormat("%*d", colWidth, x.second); } // write histogram ascii art Loading @@ -279,7 +313,7 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { const int value = 1 << row; body->appendFormat("%.*s", leftPadding, spaces.c_str()); for (auto const &x : buckets) { const int colWidth = numberWidth(x.first / kJiffyPerMs, leftPadding); const int colWidth = numberWidth(x.first, leftPadding); body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|"); } Loading @@ -294,43 +328,19 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { // write footer with bucket labels body->appendFormat("%*s", leftPadding, " "); for (auto const &x : buckets) { const int colWidth = numberWidth(x.first / kJiffyPerMs, leftPadding); body->appendFormat("%*.*f", colWidth, 1, static_cast<double>(x.first) / kJiffyPerMs); const int colWidth = numberWidth(x.first, leftPadding); body->appendFormat("%*.*f", colWidth, 1, x.first); } body->appendFormat("%.*s%s", bucketWidth, spaces.c_str(), "ms\n"); // Now report glitches body->appendFormat("\ntime elapsed between glitches and glitch timestamps\n"); body->appendFormat("\ntime elapsed between glitches and glitch timestamps:\n"); for (const auto &outlier: mOutlierData) { body->appendFormat("%lld: %lld\n", static_cast<long long>(outlier.first), static_cast<long long>(outlier.second)); } } // TODO: learn what timestamp sequences correlate with glitches instead of // manually designing a heuristic. Ultimately, detect glitches directly from audio. // 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 // void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) { // std::deque<int> periods(kNumBuff, kPeriodMs); // 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 * kPeriodMs + // kPeriodMs - kPeriodMsCPU) { // periods.assign(kNumBuff, kPeriodMs); // } // } // return; //} //------------------------------------------------------------------------------ // writes summary of performance into specified file descriptor Loading @@ -341,7 +351,7 @@ void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) for (auto & hash: thread.second) { PerformanceAnalysis& curr = hash.second; // write performance data to console curr.reportPerformance(&body); curr.reportPerformance(&body, thread.first, hash.first); if (!body.isEmpty()) { dumpLine(fd, indent, body); body.clear(); Loading media/libnbaio/ReportPerformance.cpp +33 −16 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <string.h> #include <sstream> #include <sys/prctl.h> #include <sys/time.h> #include <utility> #include <media/nbaio/NBLog.h> #include <media/nbaio/PerformanceAnalysis.h> Loading @@ -36,13 +37,16 @@ namespace android { namespace ReportPerformance { // Writes outlier intervals, timestamps, and histograms spanning long time intervals to a file. // TODO: format the data efficiently and write different types of data to different files // Writes outlier intervals, timestamps, and histograms spanning long time intervals to file. // TODO: write data in binary format void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists, const std::deque<std::pair<msInterval, timestamp>> &outlierData, const std::deque<timestamp> &peakTimestamps, const char * directory, bool append, int author, log_hash_t hash) { if (outlierData.empty() || hists.empty()) { // TODO: remove old files, implement rotating files as in AudioFlinger.cpp if (outlierData.empty() && hists.empty() && peakTimestamps.empty()) { ALOGW("No data, returning."); return; } Loading @@ -51,9 +55,21 @@ void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists, std::stringstream histogramName; std::stringstream peakName; histogramName << directory << "histograms_" << author << "_" << hash; outlierName << directory << "outliers_" << author << "_" << hash; peakName << directory << "peaks_" << author << "_" << hash; // get current time char currTime[16]; //YYYYMMDDHHMMSS + '\0' + one unused struct timeval tv; gettimeofday(&tv, NULL); struct tm tm; localtime_r(&tv.tv_sec, &tm); strftime(currTime, sizeof(currTime), "%Y%m%d%H%M%S", &tm); // generate file names std::stringstream common; common << author << "_" << hash << "_" << currTime << ".csv"; histogramName << directory << "histograms_" << common.str(); outlierName << directory << "outliers_" << common.str(); peakName << directory << "peaks_" << common.str(); std::ofstream hfs; hfs.open(histogramName.str(), append ? std::ios::app : std::ios::trunc); Loading @@ -61,16 +77,16 @@ void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists, ALOGW("couldn't open file %s", histogramName.str().c_str()); return; } hfs << "Histogram data\n"; // each histogram is written as a line where the first value is the timestamp and // subsequent values are pairs of buckets and counts. Each value is separated // by a comma, and each histogram is separated by a newline. for (const auto &hist : hists) { hfs << "\ttimestamp\n"; hfs << hist.first << "\n"; hfs << "\tbuckets (in ms) and counts\n"; hfs << hist.first << ", "; for (const auto &bucket : hist.second) { hfs << bucket.first / static_cast<double>(kJiffyPerMs) << ": " << bucket.second << "\n"; << ", " << bucket.second << ", "; } hfs << "\n"; // separate histograms with a newline hfs << "\n"; } hfs.close(); Loading @@ -80,9 +96,10 @@ void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists, ALOGW("couldn't open file %s", outlierName.str().c_str()); return; } ofs << "Outlier data: interval and timestamp\n"; // outliers are written as pairs separated by newlines, where each // pair's values are separated by a comma for (const auto &outlier : outlierData) { ofs << outlier.first << ": " << outlier.second << "\n"; ofs << outlier.first << ", " << outlier.second << "\n"; } ofs.close(); Loading @@ -92,9 +109,9 @@ void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists, ALOGW("couldn't open file %s", peakName.str().c_str()); return; } pfs << "Peak data: timestamp\n"; // peaks are simply timestamps separated by commas for (const auto &peak : peakTimestamps) { pfs << peak << "\n"; pfs << peak << ", "; } pfs.close(); } Loading media/libnbaio/include/media/nbaio/PerformanceAnalysis.h +2 −18 Original line number Diff line number Diff line Loading @@ -14,9 +14,6 @@ * limitations under the License. */ // Non-blocking event logger intended for safe communication between // processes via shared memory #ifndef ANDROID_MEDIA_PERFORMANCEANALYSIS_H #define ANDROID_MEDIA_PERFORMANCEANALYSIS_H Loading Loading @@ -78,12 +75,8 @@ public: // Generates a string of analysis of the buffer periods and prints to console // 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); // This function detects glitches in a time series. // TODO: learn what timestamp sequences correlate with glitches instead of // manually designing a heuristic. Ultimately, detect glitches directly from audio. // void alertIfGlitch(const std::vector<timestamp_raw> &samples); void reportPerformance(String8 *body, int author, log_hash_t hash, int maxHeight = 10); private: Loading @@ -108,15 +101,6 @@ private: timestamp mPrevTs = -1; // previous timestamp } mBufferPeriod; // TODO: delete values below if unused or add them to the BufferPeriod struct // FIXME: decide whether to make kPeriodMs static. // static const int kNumBuff = 3; // number of buffers considered in local history // int kPeriodMs; // current period length is ideally 4 ms // static const int kOutlierMs = 7; // values greater or equal to this cause glitches // DAC processing time for 4 ms buffer // static constexpr double kRatio = 0.75; // estimate CPU time as ratio of period // int kPeriodMsCPU; // compute based on kPeriodLen and kRatio // capacity allocated to data structures // TODO: make these values longer when testing is finished struct MaxLength { Loading services/audioflinger/Threads.cpp +6 −1 Original line number Diff line number Diff line Loading @@ -2636,6 +2636,7 @@ void AudioFlinger::PlaybackThread::checkSilentMode_l() // shared by MIXER and DIRECT, overridden by DUPLICATING ssize_t AudioFlinger::PlaybackThread::threadLoop_write() { LOG_HIST_TS(); mInWrite = true; ssize_t bytesWritten; const size_t offset = mCurrentWriteLength - mBytesRemaining; Loading Loading @@ -3114,6 +3115,10 @@ bool AudioFlinger::PlaybackThread::threadLoop() threadLoop_standby(); // This is where we go into standby if (!mStandby) { LOG_AUDIO_STATE(); } mStandby = true; } Loading Loading @@ -5429,7 +5434,7 @@ AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger, mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true), mOffloadUnderrunPosition(~0LL) { //FIXME: mStandby should be set to true by ThreadBase constructor //FIXME: mStandby should be set to true by ThreadBase constructo mStandby = true; mKeepWakeLock = property_get_bool("ro.audio.offload_wakelock", true /* default_value */); } Loading services/audioflinger/Threads.h +3 −0 Original line number Diff line number Diff line Loading @@ -485,6 +485,7 @@ protected: // Updated by updateSuspendedSessions_l() only. KeyedVector< audio_session_t, KeyedVector< int, sp<SuspendedSessionDesc> > > mSuspendedSessions; // TODO: add comment and adjust size as needed static const size_t kLogSize = 4 * 1024; sp<NBLog::Writer> mNBLogWriter; bool mSystemReady; Loading Loading @@ -984,6 +985,7 @@ private: sp<NBAIO_Source> mTeeSource; #endif uint32_t mScreenState; // cached copy of gScreenState // TODO: add comment and adjust size as needed static const size_t kFastMixerLogSize = 8 * 1024; sp<NBLog::Writer> mFastMixerNBLogWriter; Loading Loading @@ -1456,6 +1458,7 @@ private: // If a fast capture is present, the Pipe as IMemory, otherwise clear sp<IMemory> mPipeMemory; // TODO: add comment and adjust size as needed static const size_t kFastCaptureLogSize = 4 * 1024; sp<NBLog::Writer> mFastCaptureNBLogWriter; Loading Loading
media/libnbaio/PerformanceAnalysis.cpp +62 −52 Original line number Diff line number Diff line Loading @@ -46,16 +46,6 @@ namespace android { namespace ReportPerformance { static int widthOf(int x) { int width = 0; while (x > 0) { ++width; x /= 10; } return width; } // Given a the most recent timestamp of a series of audio processing // wakeup timestamps, // buckets the time interval into a histogram, searches for Loading @@ -75,8 +65,6 @@ void PerformanceAnalysis::logTsEntry(timestamp ts) { const int diffJiffy = deltaJiffy(mBufferPeriod.mPrevTs, ts); // update buffer period distribution // old versus new weight ratio when updating the buffer period mean static constexpr double exponentialWeight = 0.999; // update buffer period mean with exponential weighting Loading Loading @@ -200,6 +188,8 @@ bool PerformanceAnalysis::detectAndStorePeak(msInterval diff, timestamp ts) { // 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). // TODO: learn what timestamp sequences correlate with glitches instead of // manually designing a heuristic. bool PerformanceAnalysis::detectAndStoreOutlier(const msInterval diffMs) { bool isOutlier = false; if (diffMs >= mBufferPeriod.mOutlier) { Loading @@ -219,32 +209,73 @@ bool PerformanceAnalysis::detectAndStoreOutlier(const msInterval diffMs) { return isOutlier; } static int widthOf(int x) { int width = 0; if (x < 0) { width++; x = x == INT_MIN ? INT_MAX : -x; } // assert (x >= 0) do { ++width; x /= 10; } while (x > 0); return width; } // computes the column width required for a specific histogram value inline int numberWidth(int number, int leftPadding) { return std::max(std::max(widthOf(number) + 4, 3), leftPadding + 2); inline int numberWidth(double number, int leftPadding) { // Added values account for whitespaces needed around numbers, and for the // dot and decimal digit not accounted for by widthOf return std::max(std::max(widthOf(static_cast<int>(number)) + 3, 2), leftPadding + 1); } // rounds value to precision based on log-distance from mean inline double logRound(double x, double mean) { // Larger values increase range of high resolution constexpr double kBase = 2; const double power = floor( log(abs(x - mean) / mean) / log(kBase)) + 1; // do not round values close to the mean if (power < 1) { return x; } const int factor = static_cast<int>(pow(10, power)); return (static_cast<int>(x) * factor) / factor; } // TODO Make it return a std::string instead of modifying body // TODO: move this to ReportPerformance, probably make it a friend function of PerformanceAnalysis void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { // TODO: move this to ReportPerformance, probably make it a friend function // of PerformanceAnalysis void PerformanceAnalysis::reportPerformance(String8 *body, int author, log_hash_t hash, int maxHeight) { if (mHists.empty()) { return; } std::map<int, int> buckets; // ms of active audio in displayed histogram double elapsedMs = 0; // starting timestamp of histogram timestamp startingTs = mHists[0].first; // histogram which stores .1 precision ms counts instead of Jiffy multiple counts // TODO: when there is more data, print many histograms, possibly separated at peaks std::map<double, int> buckets; for (const auto &shortHist: mHists) { for (const auto &countPair : shortHist.second) { buckets[countPair.first] += countPair.second; const double ms = static_cast<double>(countPair.first) / kJiffyPerMs; buckets[logRound(ms, mBufferPeriod.mMean)] += countPair.second; elapsedMs += ms; } } // underscores and spaces length corresponds to maximum width of histogram static const int kLen = 100; static const int kLen = 200; std::string underscores(kLen, '_'); std::string spaces(kLen, ' '); auto it = buckets.begin(); int maxDelta = it->first; double maxDelta = it->first; int maxCount = it->second; // Compute maximum values while (++it != buckets.end()) { Loading @@ -264,13 +295,16 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { scalingFactor = (height + maxHeight) / maxHeight; height /= scalingFactor; } // TODO: print reader (author) ID body->appendFormat("\n%*s", leftPadding + 11, "Occurrences"); body->appendFormat("\n%*s %3.2f %s", leftPadding + 11, "Occurrences in", (elapsedMs / kMsPerSec), "seconds of audio:"); body->appendFormat("\n%*s%d, %lld, %lld\n", leftPadding + 11, "Thread, hash, starting timestamp: ", author, static_cast<long long int>(hash), static_cast<long long int>(startingTs)); // write histogram label line with bucket values body->appendFormat("\n%s", " "); body->appendFormat("%*s", leftPadding, " "); for (auto const &x : buckets) { const int colWidth = numberWidth(x.first / kJiffyPerMs, leftPadding); const int colWidth = numberWidth(x.first, leftPadding); body->appendFormat("%*d", colWidth, x.second); } // write histogram ascii art Loading @@ -279,7 +313,7 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { const int value = 1 << row; body->appendFormat("%.*s", leftPadding, spaces.c_str()); for (auto const &x : buckets) { const int colWidth = numberWidth(x.first / kJiffyPerMs, leftPadding); const int colWidth = numberWidth(x.first, leftPadding); body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|"); } Loading @@ -294,43 +328,19 @@ void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { // write footer with bucket labels body->appendFormat("%*s", leftPadding, " "); for (auto const &x : buckets) { const int colWidth = numberWidth(x.first / kJiffyPerMs, leftPadding); body->appendFormat("%*.*f", colWidth, 1, static_cast<double>(x.first) / kJiffyPerMs); const int colWidth = numberWidth(x.first, leftPadding); body->appendFormat("%*.*f", colWidth, 1, x.first); } body->appendFormat("%.*s%s", bucketWidth, spaces.c_str(), "ms\n"); // Now report glitches body->appendFormat("\ntime elapsed between glitches and glitch timestamps\n"); body->appendFormat("\ntime elapsed between glitches and glitch timestamps:\n"); for (const auto &outlier: mOutlierData) { body->appendFormat("%lld: %lld\n", static_cast<long long>(outlier.first), static_cast<long long>(outlier.second)); } } // TODO: learn what timestamp sequences correlate with glitches instead of // manually designing a heuristic. Ultimately, detect glitches directly from audio. // 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 // void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) { // std::deque<int> periods(kNumBuff, kPeriodMs); // 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 * kPeriodMs + // kPeriodMs - kPeriodMsCPU) { // periods.assign(kNumBuff, kPeriodMs); // } // } // return; //} //------------------------------------------------------------------------------ // writes summary of performance into specified file descriptor Loading @@ -341,7 +351,7 @@ void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) for (auto & hash: thread.second) { PerformanceAnalysis& curr = hash.second; // write performance data to console curr.reportPerformance(&body); curr.reportPerformance(&body, thread.first, hash.first); if (!body.isEmpty()) { dumpLine(fd, indent, body); body.clear(); Loading
media/libnbaio/ReportPerformance.cpp +33 −16 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <string.h> #include <sstream> #include <sys/prctl.h> #include <sys/time.h> #include <utility> #include <media/nbaio/NBLog.h> #include <media/nbaio/PerformanceAnalysis.h> Loading @@ -36,13 +37,16 @@ namespace android { namespace ReportPerformance { // Writes outlier intervals, timestamps, and histograms spanning long time intervals to a file. // TODO: format the data efficiently and write different types of data to different files // Writes outlier intervals, timestamps, and histograms spanning long time intervals to file. // TODO: write data in binary format void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists, const std::deque<std::pair<msInterval, timestamp>> &outlierData, const std::deque<timestamp> &peakTimestamps, const char * directory, bool append, int author, log_hash_t hash) { if (outlierData.empty() || hists.empty()) { // TODO: remove old files, implement rotating files as in AudioFlinger.cpp if (outlierData.empty() && hists.empty() && peakTimestamps.empty()) { ALOGW("No data, returning."); return; } Loading @@ -51,9 +55,21 @@ void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists, std::stringstream histogramName; std::stringstream peakName; histogramName << directory << "histograms_" << author << "_" << hash; outlierName << directory << "outliers_" << author << "_" << hash; peakName << directory << "peaks_" << author << "_" << hash; // get current time char currTime[16]; //YYYYMMDDHHMMSS + '\0' + one unused struct timeval tv; gettimeofday(&tv, NULL); struct tm tm; localtime_r(&tv.tv_sec, &tm); strftime(currTime, sizeof(currTime), "%Y%m%d%H%M%S", &tm); // generate file names std::stringstream common; common << author << "_" << hash << "_" << currTime << ".csv"; histogramName << directory << "histograms_" << common.str(); outlierName << directory << "outliers_" << common.str(); peakName << directory << "peaks_" << common.str(); std::ofstream hfs; hfs.open(histogramName.str(), append ? std::ios::app : std::ios::trunc); Loading @@ -61,16 +77,16 @@ void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists, ALOGW("couldn't open file %s", histogramName.str().c_str()); return; } hfs << "Histogram data\n"; // each histogram is written as a line where the first value is the timestamp and // subsequent values are pairs of buckets and counts. Each value is separated // by a comma, and each histogram is separated by a newline. for (const auto &hist : hists) { hfs << "\ttimestamp\n"; hfs << hist.first << "\n"; hfs << "\tbuckets (in ms) and counts\n"; hfs << hist.first << ", "; for (const auto &bucket : hist.second) { hfs << bucket.first / static_cast<double>(kJiffyPerMs) << ": " << bucket.second << "\n"; << ", " << bucket.second << ", "; } hfs << "\n"; // separate histograms with a newline hfs << "\n"; } hfs.close(); Loading @@ -80,9 +96,10 @@ void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists, ALOGW("couldn't open file %s", outlierName.str().c_str()); return; } ofs << "Outlier data: interval and timestamp\n"; // outliers are written as pairs separated by newlines, where each // pair's values are separated by a comma for (const auto &outlier : outlierData) { ofs << outlier.first << ": " << outlier.second << "\n"; ofs << outlier.first << ", " << outlier.second << "\n"; } ofs.close(); Loading @@ -92,9 +109,9 @@ void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists, ALOGW("couldn't open file %s", peakName.str().c_str()); return; } pfs << "Peak data: timestamp\n"; // peaks are simply timestamps separated by commas for (const auto &peak : peakTimestamps) { pfs << peak << "\n"; pfs << peak << ", "; } pfs.close(); } Loading
media/libnbaio/include/media/nbaio/PerformanceAnalysis.h +2 −18 Original line number Diff line number Diff line Loading @@ -14,9 +14,6 @@ * limitations under the License. */ // Non-blocking event logger intended for safe communication between // processes via shared memory #ifndef ANDROID_MEDIA_PERFORMANCEANALYSIS_H #define ANDROID_MEDIA_PERFORMANCEANALYSIS_H Loading Loading @@ -78,12 +75,8 @@ public: // Generates a string of analysis of the buffer periods and prints to console // 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); // This function detects glitches in a time series. // TODO: learn what timestamp sequences correlate with glitches instead of // manually designing a heuristic. Ultimately, detect glitches directly from audio. // void alertIfGlitch(const std::vector<timestamp_raw> &samples); void reportPerformance(String8 *body, int author, log_hash_t hash, int maxHeight = 10); private: Loading @@ -108,15 +101,6 @@ private: timestamp mPrevTs = -1; // previous timestamp } mBufferPeriod; // TODO: delete values below if unused or add them to the BufferPeriod struct // FIXME: decide whether to make kPeriodMs static. // static const int kNumBuff = 3; // number of buffers considered in local history // int kPeriodMs; // current period length is ideally 4 ms // static const int kOutlierMs = 7; // values greater or equal to this cause glitches // DAC processing time for 4 ms buffer // static constexpr double kRatio = 0.75; // estimate CPU time as ratio of period // int kPeriodMsCPU; // compute based on kPeriodLen and kRatio // capacity allocated to data structures // TODO: make these values longer when testing is finished struct MaxLength { Loading
services/audioflinger/Threads.cpp +6 −1 Original line number Diff line number Diff line Loading @@ -2636,6 +2636,7 @@ void AudioFlinger::PlaybackThread::checkSilentMode_l() // shared by MIXER and DIRECT, overridden by DUPLICATING ssize_t AudioFlinger::PlaybackThread::threadLoop_write() { LOG_HIST_TS(); mInWrite = true; ssize_t bytesWritten; const size_t offset = mCurrentWriteLength - mBytesRemaining; Loading Loading @@ -3114,6 +3115,10 @@ bool AudioFlinger::PlaybackThread::threadLoop() threadLoop_standby(); // This is where we go into standby if (!mStandby) { LOG_AUDIO_STATE(); } mStandby = true; } Loading Loading @@ -5429,7 +5434,7 @@ AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger, mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true), mOffloadUnderrunPosition(~0LL) { //FIXME: mStandby should be set to true by ThreadBase constructor //FIXME: mStandby should be set to true by ThreadBase constructo mStandby = true; mKeepWakeLock = property_get_bool("ro.audio.offload_wakelock", true /* default_value */); } Loading
services/audioflinger/Threads.h +3 −0 Original line number Diff line number Diff line Loading @@ -485,6 +485,7 @@ protected: // Updated by updateSuspendedSessions_l() only. KeyedVector< audio_session_t, KeyedVector< int, sp<SuspendedSessionDesc> > > mSuspendedSessions; // TODO: add comment and adjust size as needed static const size_t kLogSize = 4 * 1024; sp<NBLog::Writer> mNBLogWriter; bool mSystemReady; Loading Loading @@ -984,6 +985,7 @@ private: sp<NBAIO_Source> mTeeSource; #endif uint32_t mScreenState; // cached copy of gScreenState // TODO: add comment and adjust size as needed static const size_t kFastMixerLogSize = 8 * 1024; sp<NBLog::Writer> mFastMixerNBLogWriter; Loading Loading @@ -1456,6 +1458,7 @@ private: // If a fast capture is present, the Pipe as IMemory, otherwise clear sp<IMemory> mPipeMemory; // TODO: add comment and adjust size as needed static const size_t kFastCaptureLogSize = 4 * 1024; sp<NBLog::Writer> mFastCaptureNBLogWriter; Loading