Loading media/libnbaio/NBLog.cpp +15 −14 Original line number Diff line number Diff line Loading @@ -49,20 +49,25 @@ * * 2) reading the data from shared memory * Thread::threadloop() * TODO: add description? * NBLog::MergeThread::threadLoop() * calls NBLog::Merger::merge * Waits on a mutex, called periodically * Calls NBLog::Merger::merge and MergeReader.getAndProcessSnapshot. * NBLog::Merger::merge * Merges snapshots sorted by timestamp * for each reader in vector of class NamedReader, * callsNamedReader::reader()->getSnapshot * TODO: check whether the rest of this function is relevant * Calls Reader::getSnapshot on each individual thread buffer to in shared * memory and writes all their data to the single FIFO stored in mMerger. * NBLog::Reader::getSnapshot * copies snapshot of reader's fifo buffer into its own buffer * calls mFifoReader->obtain to find readable data * sets snapshot.begin() and .end() iterators to boundaries of valid entries * moves the fifo reader index to after the last entry read * in this case, the buffer is in shared memory. in (4), the buffer is private * NBLog::MergeThread::getAndProcessSnapshot * Iterates through the entries in the local FIFO. Processes the data in * specific ways depending on the entry type. If the data is a histogram * timestamp or an audio on/off signal, writes to a map of PerformanceAnalysis * class instances, where the wakeup() intervals are stored as histograms * and analyzed. * * 3) reading the data from private buffer * MediaLogService::dump Loading Loading @@ -876,8 +881,7 @@ std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot() void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot) { String8 timestamp, body; // TODO: check: is the FIXME below still a problem? // FIXME: this is not thread safe // TODO: check: is this thread safe? // TODO: add lost data information and notification to ReportPerformance size_t lost = snapshot.lost() + (snapshot.begin() - EntryIterator(snapshot.data())); if (lost > 0) { Loading @@ -899,7 +903,7 @@ 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].logTsEntry(ts); mThreadPerformanceAnalysis[data->author][hash].logTsEntry(ts); ++entry; break; } Loading @@ -907,12 +911,9 @@ void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot HistTsEntryWithAuthor *data = (HistTsEntryWithAuthor *) (entry->data); // TODO This memcpies are here to avoid unaligned memory access crash. // There's probably a more efficient way to do it // TODO: incorporate hash information in mThreadPerformanceAnalysis // log_hash_t hash; // memcpy(&hash, &(data->hash), sizeof(hash)); // int64_t ts; // memcpy(&ts, &data->ts, sizeof(ts)); mThreadPerformanceAnalysis[data->author].handleStateChange(); log_hash_t hash; memcpy(&hash, &(data->hash), sizeof(hash)); mThreadPerformanceAnalysis[data->author][hash].handleStateChange(); ++entry; break; } Loading media/libnbaio/PerformanceAnalysis.cpp +16 −10 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ void PerformanceAnalysis::processAndFlushTimeStampSeries() { return; } // mHists is empty if program just started // mHists is empty if thread/hash pair is sending data for the first time if (mHists.empty()) { mHists.emplace_front(static_cast<uint64_t>(mTimeStampSeries[0]), std::map<int, int>()); Loading Loading @@ -130,10 +130,6 @@ void PerformanceAnalysis::logTsEntry(int64_t ts) { } } // TODO: move this someplace // static const char* const kName = (const char *) "/data/misc/audioserver/sample_results.txt"; // writeToFile(mOutlierData, mLongTermHists, kName, false); // Given a series of outlier intervals (mOutlier data), // looks for changes in distribution (peaks), which can be either positive or negative. // The function sets the mean to the starting value and sigma to 0, and updates Loading Loading @@ -223,7 +219,6 @@ void PerformanceAnalysis::storeOutlierData(const std::vector<int64_t> ×tamp } } // FIXME: delete this temporary test code, recycled for various new functions void PerformanceAnalysis::testFunction() { // produces values (4: 5000000), (13: 18000000) Loading @@ -241,7 +236,10 @@ void PerformanceAnalysis::testFunction() { // 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 void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) const { void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { // Add any new data processAndFlushTimeStampSeries(); if (mHists.empty()) { ALOGD("reportPerformance: mHists is empty"); return; Loading Loading @@ -348,11 +346,19 @@ void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) { //------------------------------------------------------------------------------ // writes summary of performance into specified file descriptor void dump(int fd, int indent, const std::map<int, PerformanceAnalysis> &threadPerformanceAnalysis) { void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) { String8 body; const char* const kName = "/data/misc/audioserver/"; for (auto & thread : threadPerformanceAnalysis) { thread.second.reportPerformance(&body); for (auto & hash: thread.second) { PerformanceAnalysis& curr = hash.second; curr.processAndFlushTimeStampSeries(); // write performance data to console curr.reportPerformance(&body); // write to file writeToFile(curr.mOutlierData, curr.mHists, kName, false, thread.first, hash.first); } } if (!body.isEmpty()) { dumpLine(fd, indent, body); Loading media/libnbaio/ReportPerformance.cpp +27 −13 Original line number Diff line number Diff line Loading @@ -23,12 +23,12 @@ #include <stdint.h> #include <stdio.h> #include <string.h> #include <sstream> #include <sys/prctl.h> #include <utility> #include <media/nbaio/NBLog.h> #include <media/nbaio/PerformanceAnalysis.h> #include <media/nbaio/ReportPerformance.h> // #include <utils/CallStack.h> // used to print callstack #include <utils/Log.h> #include <utils/String8.h> Loading @@ -40,34 +40,48 @@ namespace ReportPerformance { // TODO: format the data efficiently and write different types of data to different files void writeToFile(const std::deque<std::pair<outlierInterval, timestamp>> &outlierData, const std::deque<std::pair<timestamp, Histogram>> &hists, const char * kName, bool append) { ALOGD("writing performance data to file"); const char * kDirectory, bool append, int author, log_hash_t hash) { if (outlierData.empty() || hists.empty()) { ALOGW("No data, returning."); return; } std::stringstream outlierName; std::stringstream histogramName; outlierName << kDirectory << "outliers_" << author << "_" << hash; histogramName << kDirectory << "histograms_" << author << "_" << hash; std::ofstream ofs; ofs.open(kName, append ? std::ios::app : std::ios::trunc); ofs.open(outlierName.str().c_str(), append ? std::ios::app : std::ios::trunc); if (!ofs.is_open()) { ALOGW("couldn't open file %s", kName); ALOGW("couldn't open file %s", outlierName.str().c_str()); return; } ofs << "Outlier data: interval and timestamp\n"; for (const auto &outlier : outlierData) { ofs << outlier.first << ": " << outlier.second << "\n"; } ofs << "Histogram data\n"; ofs.close(); std::ofstream hfs; hfs.open(histogramName.str().c_str(), append ? std::ios::app : std::ios::trunc); if (!hfs.is_open()) { ALOGW("couldn't open file %s", histogramName.str().c_str()); return; } hfs << "Histogram data\n"; for (const auto &hist : hists) { ofs << "\ttimestamp\n"; ofs << hist.first << "\n"; ofs << "\tbuckets and counts\n"; hfs << "\ttimestamp\n"; hfs << hist.first << "\n"; hfs << "\tbuckets and counts\n"; for (const auto &bucket : hist.second) { ofs << bucket.first << ": " << bucket.second << "\n"; hfs << bucket.first << ": " << bucket.second << "\n"; } ofs << "\n"; // separate histograms with a newline hfs << "\n"; // separate histograms with a newline } ofs.close(); hfs.close(); } } // namespace ReportPerformance Loading media/libnbaio/include/media/nbaio/NBLog.h +3 −1 Original line number Diff line number Diff line Loading @@ -557,7 +557,9 @@ public: const std::vector<NamedReader>& mNamedReaders; // analyzes, compresses and stores the merged data std::map<int, ReportPerformance::PerformanceAnalysis> mThreadPerformanceAnalysis; // contains a separate instance for every author (thread), and for every source file // location within each author ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis; // handle author entry by looking up the author's name and appending it to the body // returns number of bytes read from fmtEntry Loading media/libnbaio/include/media/nbaio/PerformanceAnalysis.h +11 −9 Original line number Diff line number Diff line Loading @@ -29,6 +29,12 @@ namespace android { namespace ReportPerformance { class PerformanceAnalysis; // a map of PerformanceAnalysis instances // The outer key is for the thread, the inner key for the source file location. using PerformanceAnalysisMap = std::map<int, std::map<log_hash_t, PerformanceAnalysis>>; class PerformanceAnalysis { // This class stores and analyzes audio processing wakeup timestamps from NBLog // FIXME: currently, all performance data is stored in deques. Need to add a mutex. Loading @@ -38,15 +44,13 @@ public: PerformanceAnalysis(); // Given a series of audio processing wakeup timestamps, // compresses and and analyzes the data, and flushes // the timestamp series from memory. void processAndFlushTimeStampSeries(); friend void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis); // Given a series of audio processing wakeup timestamps, // compresses and and analyzes the data, and flushes // the timestamp series from memory. void processAndFlushTimeStampSeriesOld(); void processAndFlushTimeStampSeries(); // Called when an audio on/off event is read from the buffer, // e.g. EVENT_AUDIO_STATE. Loading @@ -73,7 +77,7 @@ public: // input: series of short histograms. Generates a string of analysis of the buffer periods // 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) const; void reportPerformance(String8 *body, int maxHeight = 10); // TODO: delete this. temp for testing void testFunction(); Loading Loading @@ -134,9 +138,7 @@ private: }; void dump(int fd, int indent, const std::map<int, PerformanceAnalysis> &threadPerformanceAnalysis); void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis); void dumpLine(int fd, int indent, const String8 &body); } // namespace ReportPerformance Loading Loading
media/libnbaio/NBLog.cpp +15 −14 Original line number Diff line number Diff line Loading @@ -49,20 +49,25 @@ * * 2) reading the data from shared memory * Thread::threadloop() * TODO: add description? * NBLog::MergeThread::threadLoop() * calls NBLog::Merger::merge * Waits on a mutex, called periodically * Calls NBLog::Merger::merge and MergeReader.getAndProcessSnapshot. * NBLog::Merger::merge * Merges snapshots sorted by timestamp * for each reader in vector of class NamedReader, * callsNamedReader::reader()->getSnapshot * TODO: check whether the rest of this function is relevant * Calls Reader::getSnapshot on each individual thread buffer to in shared * memory and writes all their data to the single FIFO stored in mMerger. * NBLog::Reader::getSnapshot * copies snapshot of reader's fifo buffer into its own buffer * calls mFifoReader->obtain to find readable data * sets snapshot.begin() and .end() iterators to boundaries of valid entries * moves the fifo reader index to after the last entry read * in this case, the buffer is in shared memory. in (4), the buffer is private * NBLog::MergeThread::getAndProcessSnapshot * Iterates through the entries in the local FIFO. Processes the data in * specific ways depending on the entry type. If the data is a histogram * timestamp or an audio on/off signal, writes to a map of PerformanceAnalysis * class instances, where the wakeup() intervals are stored as histograms * and analyzed. * * 3) reading the data from private buffer * MediaLogService::dump Loading Loading @@ -876,8 +881,7 @@ std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot() void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot) { String8 timestamp, body; // TODO: check: is the FIXME below still a problem? // FIXME: this is not thread safe // TODO: check: is this thread safe? // TODO: add lost data information and notification to ReportPerformance size_t lost = snapshot.lost() + (snapshot.begin() - EntryIterator(snapshot.data())); if (lost > 0) { Loading @@ -899,7 +903,7 @@ 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].logTsEntry(ts); mThreadPerformanceAnalysis[data->author][hash].logTsEntry(ts); ++entry; break; } Loading @@ -907,12 +911,9 @@ void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot HistTsEntryWithAuthor *data = (HistTsEntryWithAuthor *) (entry->data); // TODO This memcpies are here to avoid unaligned memory access crash. // There's probably a more efficient way to do it // TODO: incorporate hash information in mThreadPerformanceAnalysis // log_hash_t hash; // memcpy(&hash, &(data->hash), sizeof(hash)); // int64_t ts; // memcpy(&ts, &data->ts, sizeof(ts)); mThreadPerformanceAnalysis[data->author].handleStateChange(); log_hash_t hash; memcpy(&hash, &(data->hash), sizeof(hash)); mThreadPerformanceAnalysis[data->author][hash].handleStateChange(); ++entry; break; } Loading
media/libnbaio/PerformanceAnalysis.cpp +16 −10 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ void PerformanceAnalysis::processAndFlushTimeStampSeries() { return; } // mHists is empty if program just started // mHists is empty if thread/hash pair is sending data for the first time if (mHists.empty()) { mHists.emplace_front(static_cast<uint64_t>(mTimeStampSeries[0]), std::map<int, int>()); Loading Loading @@ -130,10 +130,6 @@ void PerformanceAnalysis::logTsEntry(int64_t ts) { } } // TODO: move this someplace // static const char* const kName = (const char *) "/data/misc/audioserver/sample_results.txt"; // writeToFile(mOutlierData, mLongTermHists, kName, false); // Given a series of outlier intervals (mOutlier data), // looks for changes in distribution (peaks), which can be either positive or negative. // The function sets the mean to the starting value and sigma to 0, and updates Loading Loading @@ -223,7 +219,6 @@ void PerformanceAnalysis::storeOutlierData(const std::vector<int64_t> ×tamp } } // FIXME: delete this temporary test code, recycled for various new functions void PerformanceAnalysis::testFunction() { // produces values (4: 5000000), (13: 18000000) Loading @@ -241,7 +236,10 @@ void PerformanceAnalysis::testFunction() { // 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 void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) const { void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) { // Add any new data processAndFlushTimeStampSeries(); if (mHists.empty()) { ALOGD("reportPerformance: mHists is empty"); return; Loading Loading @@ -348,11 +346,19 @@ void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) { //------------------------------------------------------------------------------ // writes summary of performance into specified file descriptor void dump(int fd, int indent, const std::map<int, PerformanceAnalysis> &threadPerformanceAnalysis) { void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) { String8 body; const char* const kName = "/data/misc/audioserver/"; for (auto & thread : threadPerformanceAnalysis) { thread.second.reportPerformance(&body); for (auto & hash: thread.second) { PerformanceAnalysis& curr = hash.second; curr.processAndFlushTimeStampSeries(); // write performance data to console curr.reportPerformance(&body); // write to file writeToFile(curr.mOutlierData, curr.mHists, kName, false, thread.first, hash.first); } } if (!body.isEmpty()) { dumpLine(fd, indent, body); Loading
media/libnbaio/ReportPerformance.cpp +27 −13 Original line number Diff line number Diff line Loading @@ -23,12 +23,12 @@ #include <stdint.h> #include <stdio.h> #include <string.h> #include <sstream> #include <sys/prctl.h> #include <utility> #include <media/nbaio/NBLog.h> #include <media/nbaio/PerformanceAnalysis.h> #include <media/nbaio/ReportPerformance.h> // #include <utils/CallStack.h> // used to print callstack #include <utils/Log.h> #include <utils/String8.h> Loading @@ -40,34 +40,48 @@ namespace ReportPerformance { // TODO: format the data efficiently and write different types of data to different files void writeToFile(const std::deque<std::pair<outlierInterval, timestamp>> &outlierData, const std::deque<std::pair<timestamp, Histogram>> &hists, const char * kName, bool append) { ALOGD("writing performance data to file"); const char * kDirectory, bool append, int author, log_hash_t hash) { if (outlierData.empty() || hists.empty()) { ALOGW("No data, returning."); return; } std::stringstream outlierName; std::stringstream histogramName; outlierName << kDirectory << "outliers_" << author << "_" << hash; histogramName << kDirectory << "histograms_" << author << "_" << hash; std::ofstream ofs; ofs.open(kName, append ? std::ios::app : std::ios::trunc); ofs.open(outlierName.str().c_str(), append ? std::ios::app : std::ios::trunc); if (!ofs.is_open()) { ALOGW("couldn't open file %s", kName); ALOGW("couldn't open file %s", outlierName.str().c_str()); return; } ofs << "Outlier data: interval and timestamp\n"; for (const auto &outlier : outlierData) { ofs << outlier.first << ": " << outlier.second << "\n"; } ofs << "Histogram data\n"; ofs.close(); std::ofstream hfs; hfs.open(histogramName.str().c_str(), append ? std::ios::app : std::ios::trunc); if (!hfs.is_open()) { ALOGW("couldn't open file %s", histogramName.str().c_str()); return; } hfs << "Histogram data\n"; for (const auto &hist : hists) { ofs << "\ttimestamp\n"; ofs << hist.first << "\n"; ofs << "\tbuckets and counts\n"; hfs << "\ttimestamp\n"; hfs << hist.first << "\n"; hfs << "\tbuckets and counts\n"; for (const auto &bucket : hist.second) { ofs << bucket.first << ": " << bucket.second << "\n"; hfs << bucket.first << ": " << bucket.second << "\n"; } ofs << "\n"; // separate histograms with a newline hfs << "\n"; // separate histograms with a newline } ofs.close(); hfs.close(); } } // namespace ReportPerformance Loading
media/libnbaio/include/media/nbaio/NBLog.h +3 −1 Original line number Diff line number Diff line Loading @@ -557,7 +557,9 @@ public: const std::vector<NamedReader>& mNamedReaders; // analyzes, compresses and stores the merged data std::map<int, ReportPerformance::PerformanceAnalysis> mThreadPerformanceAnalysis; // contains a separate instance for every author (thread), and for every source file // location within each author ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis; // handle author entry by looking up the author's name and appending it to the body // returns number of bytes read from fmtEntry Loading
media/libnbaio/include/media/nbaio/PerformanceAnalysis.h +11 −9 Original line number Diff line number Diff line Loading @@ -29,6 +29,12 @@ namespace android { namespace ReportPerformance { class PerformanceAnalysis; // a map of PerformanceAnalysis instances // The outer key is for the thread, the inner key for the source file location. using PerformanceAnalysisMap = std::map<int, std::map<log_hash_t, PerformanceAnalysis>>; class PerformanceAnalysis { // This class stores and analyzes audio processing wakeup timestamps from NBLog // FIXME: currently, all performance data is stored in deques. Need to add a mutex. Loading @@ -38,15 +44,13 @@ public: PerformanceAnalysis(); // Given a series of audio processing wakeup timestamps, // compresses and and analyzes the data, and flushes // the timestamp series from memory. void processAndFlushTimeStampSeries(); friend void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis); // Given a series of audio processing wakeup timestamps, // compresses and and analyzes the data, and flushes // the timestamp series from memory. void processAndFlushTimeStampSeriesOld(); void processAndFlushTimeStampSeries(); // Called when an audio on/off event is read from the buffer, // e.g. EVENT_AUDIO_STATE. Loading @@ -73,7 +77,7 @@ public: // input: series of short histograms. Generates a string of analysis of the buffer periods // 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) const; void reportPerformance(String8 *body, int maxHeight = 10); // TODO: delete this. temp for testing void testFunction(); Loading Loading @@ -134,9 +138,7 @@ private: }; void dump(int fd, int indent, const std::map<int, PerformanceAnalysis> &threadPerformanceAnalysis); void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis); void dumpLine(int fd, int indent, const String8 &body); } // namespace ReportPerformance Loading