Home | History | Annotate | Download | only in nbaio
      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> &timestamps);
     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