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
26namespace android {
27
28namespace ReportPerformance {
29
30class PerformanceAnalysis;
31
32// a map of PerformanceAnalysis instances
33// The outer key is for the thread, the inner key for the source file location.
34using PerformanceAnalysisMap = std::map<int, std::map<log_hash_t, PerformanceAnalysis>>;
35
36class 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.
41public:
42
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
70private:
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
119void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis);
120void dumpLine(int fd, int indent, const String8 &body);
121
122} // namespace ReportPerformance
123
124}   // namespace android
125
126#endif  // ANDROID_MEDIA_PERFORMANCEANALYSIS_H
127