/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_MEDIA_PERFORMANCEANALYSIS_H #define ANDROID_MEDIA_PERFORMANCEANALYSIS_H #include <deque> #include <map> #include <vector> #include <media/nblog/ReportPerformance.h> 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. Turn these into circular // buffers. // TODO: add a mutex. public: PerformanceAnalysis() {}; friend void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis); // Called in the case of an audio on/off event, e.g., EVENT_AUDIO_STATE. // Used to discard idle time intervals void handleStateChange(); // Writes wakeup timestamp entry to log and runs analysis void logTsEntry(timestamp ts); // FIXME: make peakdetector and storeOutlierData a single function // Input: mOutlierData. Looks at time elapsed between outliers // finds significant changes in the distribution // writes timestamps of significant changes to mPeakTimestamps bool detectAndStorePeak(msInterval delta, timestamp ts); // stores timestamps of intervals above a threshold: these are assumed outliers. // writes to mOutlierData <time elapsed since previous outlier, outlier timestamp> bool detectAndStoreOutlier(const msInterval diffMs); // Generates a string of analysis of the buffer periods and prints to console // FIXME: move this data visualization to a separate class. Model/view/controller void reportPerformance(String8 *body, int author, log_hash_t hash, int maxHeight = 10); private: // TODO use a circular buffer for the deques and vectors below // stores outlier analysis: // <elapsed time between outliers in ms, outlier beginning timestamp> std::deque<std::pair<msInterval, timestamp>> mOutlierData; // stores each timestamp at which a peak was detected // a peak is a moment at which the average outlier interval changed significantly std::deque<timestamp> mPeakTimestamps; // stores buffer period histograms with timestamp of first sample std::deque<std::pair<timestamp, Histogram>> mHists; // Parameters used when detecting outliers struct BufferPeriod { double mMean = -1; // average time between audio processing wakeups double mOutlierFactor = -1; // values > mMean * mOutlierFactor are outliers double mOutlier = -1; // this is set to mMean * mOutlierFactor timestamp mPrevTs = -1; // previous timestamp } mBufferPeriod; // capacity allocated to data structures struct MaxLength { size_t Hists; // number of histograms stored in memory size_t Outliers; // number of values stored in outlier array size_t Peaks; // number of values stored in peak array int HistTimespanMs; // maximum histogram timespan }; // These values allow for 10 hours of data allowing for a glitch and a peak // as often as every 3 seconds static constexpr MaxLength kMaxLength = {.Hists = 60, .Outliers = 12000, .Peaks = 12000, .HistTimespanMs = 10 * kSecPerMin * kMsPerSec }; // these variables ensure continuity while analyzing the timestamp // series one sample at a time. // TODO: change this to a running variance/mean class struct OutlierDistribution { msInterval mMean = 0; // sample mean since previous peak msInterval mSd = 0; // sample sd since previous peak msInterval mElapsed = 0; // time since previous detected outlier const int kMaxDeviation = 5; // standard deviations from the mean threshold msInterval mTypicalDiff = 0; // global mean of outliers double mN = 0; // length of sequence since the last peak double mM2 = 0; // used to calculate sd } mOutlierDistribution; }; void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis); void dumpLine(int fd, int indent, const String8 &body); } // namespace ReportPerformance } // namespace android #endif // ANDROID_MEDIA_PERFORMANCEANALYSIS_H