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 #ifndef ANDROID_MEDIA_PERFORMANCEANALYSIS_H
18 #define ANDROID_MEDIA_PERFORMANCEANALYSIS_H
19 
20 #include <deque>
21 #include <map>
22 #include <vector>
23 
24 #include <media/nblog/ReportPerformance.h>
25 
26 namespace android {
27 
28 namespace ReportPerformance {
29 
30 class PerformanceAnalysis;
31 
32 // a map of PerformanceAnalysis instances
33 // The outer key is for the thread, the inner key for the source file location.
34 using PerformanceAnalysisMap = std::map<int, std::map<log_hash_t, PerformanceAnalysis>>;
35 
36 class PerformanceAnalysis {
37     // This class stores and analyzes audio processing wakeup timestamps from NBLog
38     // FIXME: currently, all performance data is stored in deques. Turn these into circular
39     // buffers.
40     // TODO: add a mutex.
41 public:
42 
PerformanceAnalysis()43     PerformanceAnalysis() {};
44 
45     friend void dump(int fd, int indent,
46                      PerformanceAnalysisMap &threadPerformanceAnalysis);
47 
48     // Called in the case of an audio on/off event, e.g., EVENT_AUDIO_STATE.
49     // Used to discard idle time intervals
50     void handleStateChange();
51 
52     // Writes wakeup timestamp entry to log and runs analysis
53     void logTsEntry(timestamp ts);
54 
55     // FIXME: make peakdetector and storeOutlierData a single function
56     // Input: mOutlierData. Looks at time elapsed between outliers
57     // finds significant changes in the distribution
58     // writes timestamps of significant changes to mPeakTimestamps
59     bool detectAndStorePeak(msInterval delta, timestamp ts);
60 
61     // stores timestamps of intervals above a threshold: these are assumed outliers.
62     // writes to mOutlierData <time elapsed since previous outlier, outlier timestamp>
63     bool detectAndStoreOutlier(const msInterval diffMs);
64 
65     // Generates a string of analysis of the buffer periods and prints to console
66     // FIXME: move this data visualization to a separate class. Model/view/controller
67     void reportPerformance(String8 *body, int author, log_hash_t hash,
68                            int maxHeight = 10);
69 
70 private:
71 
72     // TODO use a circular buffer for the deques and vectors below
73 
74     // stores outlier analysis:
75     // <elapsed time between outliers in ms, outlier beginning timestamp>
76     std::deque<std::pair<msInterval, timestamp>> mOutlierData;
77 
78     // stores each timestamp at which a peak was detected
79     // a peak is a moment at which the average outlier interval changed significantly
80     std::deque<timestamp> mPeakTimestamps;
81 
82     // stores buffer period histograms with timestamp of first sample
83     std::deque<std::pair<timestamp, Histogram>> mHists;
84 
85     // Parameters used when detecting outliers
86     struct BufferPeriod {
87         double    mMean = -1;          // average time between audio processing wakeups
88         double    mOutlierFactor = -1; // values > mMean * mOutlierFactor are outliers
89         double    mOutlier = -1;       // this is set to mMean * mOutlierFactor
90         timestamp mPrevTs = -1;        // previous timestamp
91     } mBufferPeriod;
92 
93     // capacity allocated to data structures
94     struct MaxLength {
95         size_t Hists; // number of histograms stored in memory
96         size_t Outliers; // number of values stored in outlier array
97         size_t Peaks; // number of values stored in peak array
98         int HistTimespanMs; // maximum histogram timespan
99     };
100     // These values allow for 10 hours of data allowing for a glitch and a peak
101     // as often as every 3 seconds
102     static constexpr MaxLength kMaxLength = {.Hists = 60, .Outliers = 12000,
103             .Peaks = 12000, .HistTimespanMs = 10 * kSecPerMin * kMsPerSec };
104 
105     // these variables ensure continuity while analyzing the timestamp
106     // series one sample at a time.
107     // TODO: change this to a running variance/mean class
108     struct OutlierDistribution {
109         msInterval mMean = 0;         // sample mean since previous peak
110         msInterval mSd = 0;           // sample sd since previous peak
111         msInterval mElapsed = 0;      // time since previous detected outlier
112         const int  kMaxDeviation = 5; // standard deviations from the mean threshold
113         msInterval mTypicalDiff = 0;  // global mean of outliers
114         double     mN = 0;            // length of sequence since the last peak
115         double     mM2 = 0;           // used to calculate sd
116     } mOutlierDistribution;
117 };
118 
119 void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis);
120 void dumpLine(int fd, int indent, const String8 &body);
121 
122 } // namespace ReportPerformance
123 
124 }   // namespace android
125 
126 #endif  // ANDROID_MEDIA_PERFORMANCEANALYSIS_H
127