1 /* 2 * Copyright (C) 2022 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 ANDROIDFW_RESOURCETIMER_H_ 18 #define ANDROIDFW_RESOURCETIMER_H_ 19 20 #include <time.h> 21 #include <atomic> 22 #include <vector> 23 24 #include <utils/Mutex.h> 25 #include <android-base/macros.h> 26 #include <androidfw/Util.h> 27 28 namespace android { 29 30 // ResourceTimer captures the duration of short functions. Durations are accumulated in registers 31 // and statistics are pulled back to the Java layer as needed. 32 // To monitor an API, first add it to the Counter enumeration. Then, inside the API, create an 33 // instance of ResourceTimer with the appropriate enumeral. The corresponding counter will be 34 // updated when the ResourceTimer destructor is called, normally at the end of the enclosing block. 35 class ResourceTimer { 36 public: 37 enum class Counter { 38 GetResourceValue, 39 RetrieveAttributes, 40 41 LastCounter = RetrieveAttributes, 42 }; 43 static const int counterSize = static_cast<int>(Counter::LastCounter) + 1; 44 static char const *toString(Counter); 45 46 // Start a timer for the specified counter. 47 ResourceTimer(Counter); 48 // The block is exiting. If the timer is active, record it. 49 ~ResourceTimer(); 50 // This records the elapsed time and disables further recording. Use this if the containing 51 // block includes extra processing that should not be included in the timer. The method is 52 // destructive in that the timer is no longer valid and further calls to record() will be 53 // ignored. 54 void record(); 55 // This cancels a timer. Elapsed time will neither be computed nor recorded. 56 void cancel(); 57 58 // A single timer contains the count of events and the cumulative time spent handling the 59 // events. It also includes the smallest value seen and 10 largest values seen. Finally, it 60 // includes a histogram of values that approximates a semi-log. 61 62 // The timer can compute percentiles of recorded events. For example, the p50 value is a time 63 // such that 50% of the readings are below the value and 50% are above the value. The 64 // granularity in the readings means that a percentile cannot always be computed. In this case, 65 // the percentile is reported as zero. (The simplest example is when there is a single 66 // reading.) Even if the value can be computed, it will not be exact. Therefore, a percentile 67 // is actually reported as two values: the lowest time at which it might be valid and the 68 // highest time at which it might be valid. 69 struct Timer { 70 static const size_t MaxLargest = 5; 71 72 // The construct zeros all the fields. The destructor releases memory allocated to the 73 // buckets. 74 Timer(); 75 ~Timer(); 76 77 // The following summary values are set to zero on a reset. All times are in ns. 78 79 // The total number of events recorded. 80 int count; 81 // The total duration of events. 82 int64_t total; 83 // The smallest event duration seen. This is guaranteed to be non-zero if count is greater 84 // than 0. 85 int mintime; 86 // The largest event duration seen. 87 int maxtime; 88 89 // The largest values seen. Element 0 is the largest value seen (and is the same as maxtime, 90 // above). Element 1 is the next largest, and so on. If count is less than MaxLargest, 91 // unused elements will be zero. 92 int largest[MaxLargest]; 93 94 // The p50 value is a time such that 50% of the readings are below that time and 50% of the 95 // readings. 96 97 // A single percentile is defined by the lowest value supported by the readings and the 98 // highest value supported by the readings. 99 struct Percentile { 100 // The nominal time (in ns) of the percentile. The true percentile is guaranteed to be less 101 // than or equal to this time. 102 int nominal; 103 // The actual percentile of the nominal time. 104 int nominal_actual; 105 // The time of the next lower bin. The true percentile is guaranteed to be greater than 106 // this time. 107 int floor; 108 // The actual percentile of the floor time. 109 int floor_actual; 110 111 // Fill in a percentile given the cumulative to the bin, the count in the current bin, the 112 // total count, the width of the bin, and the time of the bin. 113 void compute(int cumulative, int current, int count, int width, int time); 114 }; 115 116 // The structure that holds the percentiles. 117 struct { 118 Percentile p50; 119 Percentile p90; 120 Percentile p95; 121 Percentile p99; 122 } pvalues; 123 124 // Set all counters to zero. 125 void reset(); 126 // Record an event. The input time is in ns. 127 void record(int); 128 // Compute the percentiles. Percentiles are computed on demand, as the computation is too 129 // expensive to be done inline. 130 void compute(); 131 132 // Copy one timer to another. If reset is true then the src is reset immediately after the 133 // copy. The reset flag is exploited to make the copy faster. Any data in dst is lost. 134 static void copy(Timer &dst, Timer &src, bool reset); 135 136 private: 137 // Free any buckets. 138 void freeBuckets(); 139 140 // Readings are placed in bins, which are orgzanized into decades. The decade 0 covers 141 // [0,100) in steps of 1us. Decade 1 covers [0,1000) in steps of 10us. Decade 2 covers 142 // [0,10000) in steps of 100us. And so on. 143 144 // An event is placed in the first bin that can hold it. This means that events in the range 145 // of [0,100) are placed in the first decade, events in the range of [0,1000) are placed in 146 // the second decade, and so on. This also means that the first 10% of the bins are unused 147 // in each decade after the first. 148 149 // The design provides at least two significant digits across the range of [0,10000). 150 151 static const size_t MaxDimension = 4; 152 static const size_t MaxBuckets = 100; 153 154 // The range of each dimension. The lower value is always zero. 155 static const int range[MaxDimension]; 156 // The width of each bin, by dimension 157 static const int width[MaxDimension]; 158 159 // A histogram of the values seen. Centuries are allocated as needed, to minimize the memory 160 // impact. 161 int *buckets[MaxDimension]; 162 }; 163 164 // Fetch one Timer. The function has a short-circuit behavior: if the count is zero then 165 // destination count is set to zero and the function returns false. Otherwise, the destination 166 // is a copy of the source and the function returns true. This behavior lowers the cost of 167 // handling unused timers. 168 static bool copy(int src, Timer &dst, bool reset); 169 170 // Enable the timers. Timers are initially disabled. Enabling timers allocates memory for the 171 // counters. Timers cannot be disabled. 172 static void enable(); 173 174 private: 175 // An internal reset method. This does not take a lock. 176 static void reset(); 177 178 // Helper method to convert a counter into an enum. Presumably, this will be inlined into zero 179 // actual cpu instructions. toIndex(Counter c)180 static inline std::vector<unsigned int>::size_type toIndex(Counter c) { 181 return static_cast<std::vector<unsigned int>::size_type>(c); 182 } 183 184 // Every counter has an associated lock. The lock has been factored into a separate class to 185 // keep the Timer class a POD. 186 struct GuardedTimer { 187 Mutex lock_; 188 Timer timer_; 189 }; 190 191 // Scoped timer 192 struct ScopedTimer { 193 AutoMutex _l; 194 Timer &t; ScopedTimerScopedTimer195 ScopedTimer(GuardedTimer &g) : 196 _l(g.lock_), t(g.timer_) { 197 } 198 Timer *operator->() { 199 return &t; 200 } 201 Timer& operator*() { 202 return t; 203 } 204 }; 205 206 // An individual timer is active (or not), is tracking a specific API, and has a start time. 207 // The api and the start time are undefined if the timer is not active. 208 bool active_; 209 Counter api_; 210 struct timespec start_; 211 212 // The global enable flag. This is initially false and may be set true by the java runtime. 213 static std::atomic<bool> enabled_; 214 215 // The global timers. The memory for the timers is not allocated until the timers are enabled. 216 static std::atomic<GuardedTimer *> counter_; 217 }; 218 219 } // namespace android 220 221 #endif /* ANDROIDFW_RESOURCETIMER_H_ */ 222