1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // Non-blocking event logger intended for safe communication between processes via shared memory 18 19 #ifndef ANDROID_MEDIA_PERFORMANCEANALYSIS_H 20 #define ANDROID_MEDIA_PERFORMANCEANALYSIS_H 21 22 #include <map> 23 #include <deque> 24 #include <vector> 25 #include "NBLog.h" 26 #include "ReportPerformance.h" 27 28 namespace android { 29 30 namespace ReportPerformance { 31 32 class PerformanceAnalysis { 33 // This class stores and analyzes audio processing wakeup timestamps from NBLog 34 // FIXME: currently, all performance data is stored in deques. Need to add a mutex. 35 // FIXME: continue this way until analysis is done in a separate thread. Then, use 36 // the fifo writer utilities. 37 public: 38 39 PerformanceAnalysis(); 40 41 // Given a series of audio processing wakeup timestamps, 42 // compresses and and analyzes the data, and flushes 43 // the timestamp series from memory. 44 void processAndFlushTimeStampSeries(); 45 46 // Called when an audio on/off event is read from the buffer, 47 // e.g. EVENT_AUDIO_STATE. 48 // calls flushTimeStampSeries on the data up to the event, 49 // effectively discarding the idle audio time interval 50 void handleStateChange(); 51 52 // When the short-term histogram array mRecentHists has reached capacity, 53 // merges histograms for data compression and stores them in mLongTermHists 54 void processAndFlushRecentHists(); 55 56 // Writes wakeup timestamp entry to log and runs analysis 57 // TODO: make this thread safe. Each thread should have its own instance 58 // of PerformanceAnalysis. 59 void logTsEntry(timestamp_raw ts); 60 61 // FIXME: make peakdetector and storeOutlierData a single function 62 // Input: mOutlierData. Looks at time elapsed between outliers 63 // finds significant changes in the distribution 64 // writes timestamps of significant changes to mPeakTimestamps 65 void detectPeaks(); 66 67 // runs analysis on timestamp series before it is converted to a histogram 68 // finds outliers 69 // writes to mOutlierData <time elapsed since previous outlier, outlier timestamp> 70 void storeOutlierData(const std::vector<timestamp_raw> ×tamps); 71 72 // input: series of short histograms. Generates a string of analysis of the buffer periods 73 // TODO: WIP write more detailed analysis 74 // FIXME: move this data visualization to a separate class. Model/view/controller 75 void reportPerformance(String8 *body, int maxHeight = 10); 76 77 // TODO: delete this. temp for testing 78 void testFunction(); 79 80 // This function used to detect glitches in a time series 81 // TODO incorporate this into the analysis (currently unused) 82 void alertIfGlitch(const std::vector<timestamp_raw> &samples); 83 84 private: 85 86 // stores outlier analysis: <elapsed time between outliers in ms, outlier timestamp> 87 std::deque<std::pair<outlierInterval, timestamp>> mOutlierData; 88 89 // stores each timestamp at which a peak was detected 90 // a peak is a moment at which the average outlier interval changed significantly 91 std::deque<timestamp> mPeakTimestamps; 92 93 // TODO: turn these into circular buffers for better data flow 94 // FIFO of small histograms 95 // stores fixed-size short buffer period histograms with timestamp of first sample 96 std::deque<std::pair<timestamp, Histogram>> mRecentHists; 97 98 // FIFO of small histograms 99 // stores fixed-size long-term buffer period histograms with timestamp of first sample 100 std::deque<std::pair<timestamp, Histogram>> mLongTermHists; 101 102 // vector of timestamps, collected from NBLog for a (TODO) specific thread 103 // when a vector reaches its maximum size, the data is processed and flushed 104 std::vector<timestamp_raw> mTimeStampSeries; 105 106 static const int kMsPerSec = 1000; 107 108 // Parameters used when detecting outliers 109 // TODO: learn some of these from the data, delete unused ones 110 // FIXME: decide whether to make kPeriodMs static. 111 static const int kNumBuff = 3; // number of buffers considered in local history 112 int kPeriodMs; // current period length is ideally 4 ms 113 static const int kOutlierMs = 7; // values greater or equal to this cause glitches 114 // DAC processing time for 4 ms buffer 115 static constexpr double kRatio = 0.75; // estimate of CPU time as ratio of period length 116 int kPeriodMsCPU; // compute based on kPeriodLen and kRatio 117 118 // Peak detection: number of standard deviations from mean considered a significant change 119 static const int kStddevThreshold = 5; 120 121 // capacity allocated to data structures 122 // TODO: adjust all of these values 123 static const int kRecentHistsCapacity = 100; // number of short-term histograms stored in memory 124 static const int kShortHistSize = 50; // number of samples in a short-term histogram 125 static const int kOutlierSeriesSize = 100; // number of values stored in outlier array 126 static const int kPeakSeriesSize = 100; // number of values stored in peak array 127 static const int kLongTermHistsCapacity = 20; // number of long-term histogram stored in memory 128 // maximum elapsed time between first and last timestamp of a long-term histogram 129 static const int kMaxHistTimespanMs = 5 * kMsPerSec; 130 131 // these variables are stored in-class to ensure continuity while analyzing the timestamp 132 // series one short sequence at a time: the variables are not re-initialized every time. 133 // FIXME: create inner class for these variables and decide which other ones to add to it 134 double mPeakDetectorMean = -1; 135 double mPeakDetectorSd = -1; 136 // variables for storeOutlierData 137 uint64_t mElapsed = 0; 138 int64_t mPrevNs = -1; 139 140 }; 141 142 } // namespace ReportPerformance 143 144 } // namespace android 145 146 #endif // ANDROID_MEDIA_PERFORMANCEANALYSIS_H 147