Loading media/libnblog/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ cc_library_shared { "libbinder", "libcutils", "liblog", "libmediametrics", "libutils", ], Loading media/libnblog/NBLog.cpp +16 −3 Original line number Diff line number Diff line Loading @@ -788,7 +788,7 @@ std::unique_ptr<NBLog::Snapshot> NBLog::Reader::getSnapshot() // writes the data to a map of class PerformanceAnalysis, based on their thread ID. void NBLog::MergeReader::processSnapshot(NBLog::Snapshot &snapshot, int author) { PerformanceData& data = mThreadPerformanceData[author]; ReportPerformance::PerformanceData& data = mThreadPerformanceData[author]; // We don't do "auto it" because it reduces readability in this case. for (EntryIterator it = snapshot.begin(); it != snapshot.end(); ++it) { switch (it->type) { Loading Loading @@ -856,6 +856,19 @@ void NBLog::MergeReader::getAndProcessSnapshot() processSnapshot(*(snapshots[i]), i); } } checkPushToMediaMetrics(); } void NBLog::MergeReader::checkPushToMediaMetrics() { const nsecs_t now = systemTime(); for (auto& item : mThreadPerformanceData) { ReportPerformance::PerformanceData& data = item.second; if (now - data.start >= kPeriodicMediaMetricsPush) { (void)ReportPerformance::sendToMediaMetrics(data); data.reset(); // data is persistent per thread } } } void NBLog::MergeReader::dump(int fd, int indent) Loading @@ -864,8 +877,8 @@ void NBLog::MergeReader::dump(int fd, int indent) ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis); Json::Value root(Json::arrayValue); for (const auto& item : mThreadPerformanceData) { const PerformanceData& data = item.second; std::unique_ptr<Json::Value> threadData = dumpToJson(data); const ReportPerformance::PerformanceData& data = item.second; std::unique_ptr<Json::Value> threadData = ReportPerformance::dumpToJson(data); if (threadData == nullptr) { continue; } Loading media/libnblog/PerformanceAnalysis.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ namespace android { namespace ReportPerformance { void Histogram::add(double value) { // TODO Handle domain and range error exceptions? Loading Loading @@ -107,8 +109,6 @@ std::string Histogram::toString() const { //------------------------------------------------------------------------------ namespace ReportPerformance { // Given an audio processing wakeup timestamp, buckets the time interval // since the previous timestamp into a histogram, searches for // outliers, analyzes the outlier series for unexpectedly Loading media/libnblog/ReportPerformance.cpp +66 −3 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <sys/time.h> #include <utility> #include <json/json.h> #include <media/MediaAnalyticsItem.h> #include <media/nblog/NBLog.h> #include <media/nblog/PerformanceAnalysis.h> #include <media/nblog/ReportPerformance.h> Loading @@ -37,6 +38,8 @@ namespace android { namespace ReportPerformance { std::unique_ptr<Json::Value> dumpToJson(const PerformanceData& data) { std::unique_ptr<Json::Value> rootPtr = std::make_unique<Json::Value>(Json::objectValue); Loading @@ -54,16 +57,76 @@ std::unique_ptr<Json::Value> dumpToJson(const PerformanceData& data) return rootPtr; } //------------------------------------------------------------------------------ bool sendToMediaMetrics(const PerformanceData& data) { // See documentation for these metrics here: // docs.google.com/document/d/11--6dyOXVOpacYQLZiaOY5QVtQjUyqNx2zT9cCzLKYE/edit?usp=sharing static constexpr char kThreadType[] = "android.media.audiothread.type"; static constexpr char kThreadFrameCount[] = "android.media.audiothread.framecount"; static constexpr char kThreadSampleRate[] = "android.media.audiothread.samplerate"; static constexpr char kThreadWorkHist[] = "android.media.audiothread.workMs.hist"; static constexpr char kThreadLatencyHist[] = "android.media.audiothread.latencyMs.hist"; static constexpr char kThreadWarmupHist[] = "android.media.audiothread.warmupMs.hist"; static constexpr char kThreadUnderruns[] = "android.media.audiothread.underruns"; static constexpr char kThreadOverruns[] = "android.media.audiothread.overruns"; static constexpr char kThreadActive[] = "android.media.audiothread.activeMs"; static constexpr char kThreadDuration[] = "android.media.audiothread.durationMs"; std::unique_ptr<MediaAnalyticsItem> item(new MediaAnalyticsItem("audiothread")); const Histogram &workHist = data.workHist; if (workHist.totalCount() > 0) { item->setCString(kThreadWorkHist, workHist.toString().c_str()); } namespace ReportPerformance { const Histogram &latencyHist = data.latencyHist; if (latencyHist.totalCount() > 0) { item->setCString(kThreadLatencyHist, latencyHist.toString().c_str()); } const Histogram &warmupHist = data.warmupHist; if (warmupHist.totalCount() > 0) { item->setCString(kThreadWarmupHist, warmupHist.toString().c_str()); } if (data.underruns > 0) { item->setInt64(kThreadUnderruns, data.underruns); } if (data.overruns > 0) { item->setInt64(kThreadOverruns, data.overruns); } // Send to Media Metrics if the record is not empty. // The thread and time info are added inside the if statement because // we want to send them only if there are performance metrics to send. if (item->count() > 0) { // Add thread info fields. const int type = data.type; // TODO have a int-to-string mapping defined somewhere else for other thread types. if (type == 2) { item->setCString(kThreadType, "FASTMIXER"); } else { item->setCString(kThreadType, "UNKNOWN"); } item->setInt32(kThreadFrameCount, data.frameCount); item->setInt32(kThreadSampleRate, data.sampleRate); // Add time info fields. item->setInt64(kThreadActive, data.active / 1000000); item->setInt64(kThreadDuration, (systemTime() - data.start) / 1000000); return item->selfrecord(); } return false; } //------------------------------------------------------------------------------ // TODO: use a function like this to extract logic from writeToFile // https://stackoverflow.com/a/9279620 // 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, void writeToFile(const std::deque<std::pair<timestamp, Hist>> &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) { Loading media/libnblog/include/media/nblog/NBLog.h +15 −1 Original line number Diff line number Diff line Loading @@ -440,6 +440,7 @@ public: void log(Event event, const void *data, size_t length); void logvf(const char *fmt, va_list ap); // helper functions for logging parts of a formatted entry void logStart(const char *fmt); void logTimestampFormat(); Loading Loading @@ -499,10 +500,12 @@ public: private: // Amount of tries for reader to catch up with writer in getSnapshot(). static constexpr int kMaxObtainTries = 3; // invalidBeginTypes and invalidEndTypes are used to align the Snapshot::begin() and // Snapshot::end() EntryIterators to valid entries. static const std::unordered_set<Event> invalidBeginTypes; static const std::unordered_set<Event> invalidEndTypes; // declared as const because audio_utils_fifo() constructor sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor Loading Loading @@ -561,6 +564,7 @@ public: static void appendFloat(String8 *body, const void *data); static void appendPID(String8 *body, const void *data, size_t length); static void appendTimestamp(String8 *body, const void *data); // The bufferDump functions are used for debugging only. static String8 bufferDump(const uint8_t *buffer, size_t size); static String8 bufferDump(const EntryIterator &it); Loading Loading @@ -603,11 +607,17 @@ public: MergeReader(const void *shared, size_t size, Merger &merger); void dump(int fd, int indent = 0); // process a particular snapshot of the reader void processSnapshot(Snapshot &snap, int author); // call getSnapshot of the content of the reader's buffer and process the data void getAndProcessSnapshot(); // check for periodic push of performance data to media metrics, and perform // the send if it is time to do so. void checkPushToMediaMetrics(); private: // FIXME Needs to be protected by a lock, // because even though our use of it is read-only there may be asynchronous updates Loading @@ -620,7 +630,11 @@ public: ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis; // compresses and stores audio performance data from each thread's buffers. std::map<int /*author, i.e. thread index*/, PerformanceData> mThreadPerformanceData; // first parameter is author, i.e. thread index. std::map<int, ReportPerformance::PerformanceData> mThreadPerformanceData; // how often to push data to Media Metrics static constexpr nsecs_t kPeriodicMediaMetricsPush = s2ns((nsecs_t)2 * 60 * 60); // 2 hours // handle author entry by looking up the author's name and appending it to the body // returns number of bytes read from fmtEntry Loading Loading
media/libnblog/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ cc_library_shared { "libbinder", "libcutils", "liblog", "libmediametrics", "libutils", ], Loading
media/libnblog/NBLog.cpp +16 −3 Original line number Diff line number Diff line Loading @@ -788,7 +788,7 @@ std::unique_ptr<NBLog::Snapshot> NBLog::Reader::getSnapshot() // writes the data to a map of class PerformanceAnalysis, based on their thread ID. void NBLog::MergeReader::processSnapshot(NBLog::Snapshot &snapshot, int author) { PerformanceData& data = mThreadPerformanceData[author]; ReportPerformance::PerformanceData& data = mThreadPerformanceData[author]; // We don't do "auto it" because it reduces readability in this case. for (EntryIterator it = snapshot.begin(); it != snapshot.end(); ++it) { switch (it->type) { Loading Loading @@ -856,6 +856,19 @@ void NBLog::MergeReader::getAndProcessSnapshot() processSnapshot(*(snapshots[i]), i); } } checkPushToMediaMetrics(); } void NBLog::MergeReader::checkPushToMediaMetrics() { const nsecs_t now = systemTime(); for (auto& item : mThreadPerformanceData) { ReportPerformance::PerformanceData& data = item.second; if (now - data.start >= kPeriodicMediaMetricsPush) { (void)ReportPerformance::sendToMediaMetrics(data); data.reset(); // data is persistent per thread } } } void NBLog::MergeReader::dump(int fd, int indent) Loading @@ -864,8 +877,8 @@ void NBLog::MergeReader::dump(int fd, int indent) ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis); Json::Value root(Json::arrayValue); for (const auto& item : mThreadPerformanceData) { const PerformanceData& data = item.second; std::unique_ptr<Json::Value> threadData = dumpToJson(data); const ReportPerformance::PerformanceData& data = item.second; std::unique_ptr<Json::Value> threadData = ReportPerformance::dumpToJson(data); if (threadData == nullptr) { continue; } Loading
media/libnblog/PerformanceAnalysis.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ namespace android { namespace ReportPerformance { void Histogram::add(double value) { // TODO Handle domain and range error exceptions? Loading Loading @@ -107,8 +109,6 @@ std::string Histogram::toString() const { //------------------------------------------------------------------------------ namespace ReportPerformance { // Given an audio processing wakeup timestamp, buckets the time interval // since the previous timestamp into a histogram, searches for // outliers, analyzes the outlier series for unexpectedly Loading
media/libnblog/ReportPerformance.cpp +66 −3 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <sys/time.h> #include <utility> #include <json/json.h> #include <media/MediaAnalyticsItem.h> #include <media/nblog/NBLog.h> #include <media/nblog/PerformanceAnalysis.h> #include <media/nblog/ReportPerformance.h> Loading @@ -37,6 +38,8 @@ namespace android { namespace ReportPerformance { std::unique_ptr<Json::Value> dumpToJson(const PerformanceData& data) { std::unique_ptr<Json::Value> rootPtr = std::make_unique<Json::Value>(Json::objectValue); Loading @@ -54,16 +57,76 @@ std::unique_ptr<Json::Value> dumpToJson(const PerformanceData& data) return rootPtr; } //------------------------------------------------------------------------------ bool sendToMediaMetrics(const PerformanceData& data) { // See documentation for these metrics here: // docs.google.com/document/d/11--6dyOXVOpacYQLZiaOY5QVtQjUyqNx2zT9cCzLKYE/edit?usp=sharing static constexpr char kThreadType[] = "android.media.audiothread.type"; static constexpr char kThreadFrameCount[] = "android.media.audiothread.framecount"; static constexpr char kThreadSampleRate[] = "android.media.audiothread.samplerate"; static constexpr char kThreadWorkHist[] = "android.media.audiothread.workMs.hist"; static constexpr char kThreadLatencyHist[] = "android.media.audiothread.latencyMs.hist"; static constexpr char kThreadWarmupHist[] = "android.media.audiothread.warmupMs.hist"; static constexpr char kThreadUnderruns[] = "android.media.audiothread.underruns"; static constexpr char kThreadOverruns[] = "android.media.audiothread.overruns"; static constexpr char kThreadActive[] = "android.media.audiothread.activeMs"; static constexpr char kThreadDuration[] = "android.media.audiothread.durationMs"; std::unique_ptr<MediaAnalyticsItem> item(new MediaAnalyticsItem("audiothread")); const Histogram &workHist = data.workHist; if (workHist.totalCount() > 0) { item->setCString(kThreadWorkHist, workHist.toString().c_str()); } namespace ReportPerformance { const Histogram &latencyHist = data.latencyHist; if (latencyHist.totalCount() > 0) { item->setCString(kThreadLatencyHist, latencyHist.toString().c_str()); } const Histogram &warmupHist = data.warmupHist; if (warmupHist.totalCount() > 0) { item->setCString(kThreadWarmupHist, warmupHist.toString().c_str()); } if (data.underruns > 0) { item->setInt64(kThreadUnderruns, data.underruns); } if (data.overruns > 0) { item->setInt64(kThreadOverruns, data.overruns); } // Send to Media Metrics if the record is not empty. // The thread and time info are added inside the if statement because // we want to send them only if there are performance metrics to send. if (item->count() > 0) { // Add thread info fields. const int type = data.type; // TODO have a int-to-string mapping defined somewhere else for other thread types. if (type == 2) { item->setCString(kThreadType, "FASTMIXER"); } else { item->setCString(kThreadType, "UNKNOWN"); } item->setInt32(kThreadFrameCount, data.frameCount); item->setInt32(kThreadSampleRate, data.sampleRate); // Add time info fields. item->setInt64(kThreadActive, data.active / 1000000); item->setInt64(kThreadDuration, (systemTime() - data.start) / 1000000); return item->selfrecord(); } return false; } //------------------------------------------------------------------------------ // TODO: use a function like this to extract logic from writeToFile // https://stackoverflow.com/a/9279620 // 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, void writeToFile(const std::deque<std::pair<timestamp, Hist>> &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) { Loading
media/libnblog/include/media/nblog/NBLog.h +15 −1 Original line number Diff line number Diff line Loading @@ -440,6 +440,7 @@ public: void log(Event event, const void *data, size_t length); void logvf(const char *fmt, va_list ap); // helper functions for logging parts of a formatted entry void logStart(const char *fmt); void logTimestampFormat(); Loading Loading @@ -499,10 +500,12 @@ public: private: // Amount of tries for reader to catch up with writer in getSnapshot(). static constexpr int kMaxObtainTries = 3; // invalidBeginTypes and invalidEndTypes are used to align the Snapshot::begin() and // Snapshot::end() EntryIterators to valid entries. static const std::unordered_set<Event> invalidBeginTypes; static const std::unordered_set<Event> invalidEndTypes; // declared as const because audio_utils_fifo() constructor sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor Loading Loading @@ -561,6 +564,7 @@ public: static void appendFloat(String8 *body, const void *data); static void appendPID(String8 *body, const void *data, size_t length); static void appendTimestamp(String8 *body, const void *data); // The bufferDump functions are used for debugging only. static String8 bufferDump(const uint8_t *buffer, size_t size); static String8 bufferDump(const EntryIterator &it); Loading Loading @@ -603,11 +607,17 @@ public: MergeReader(const void *shared, size_t size, Merger &merger); void dump(int fd, int indent = 0); // process a particular snapshot of the reader void processSnapshot(Snapshot &snap, int author); // call getSnapshot of the content of the reader's buffer and process the data void getAndProcessSnapshot(); // check for periodic push of performance data to media metrics, and perform // the send if it is time to do so. void checkPushToMediaMetrics(); private: // FIXME Needs to be protected by a lock, // because even though our use of it is read-only there may be asynchronous updates Loading @@ -620,7 +630,11 @@ public: ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis; // compresses and stores audio performance data from each thread's buffers. std::map<int /*author, i.e. thread index*/, PerformanceData> mThreadPerformanceData; // first parameter is author, i.e. thread index. std::map<int, ReportPerformance::PerformanceData> mThreadPerformanceData; // how often to push data to Media Metrics static constexpr nsecs_t kPeriodicMediaMetricsPush = s2ns((nsecs_t)2 * 60 * 60); // 2 hours // handle author entry by looking up the author's name and appending it to the body // returns number of bytes read from fmtEntry Loading