| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 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 |  */ | 
| Yiwei Zhang | 91a8638 | 2018-11-15 14:44:40 -0800 | [diff] [blame] | 16 | #include "timestatsproto/TimeStatsHelper.h" | 
 | 17 |  | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 18 | #include <android-base/stringprintf.h> | 
| Yiwei Zhang | 91a8638 | 2018-11-15 14:44:40 -0800 | [diff] [blame] | 19 | #include <inttypes.h> | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 20 |  | 
 | 21 | #include <array> | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 22 |  | 
 | 23 | #define HISTOGRAM_SIZE 85 | 
 | 24 |  | 
 | 25 | using android::base::StringAppendF; | 
 | 26 | using android::base::StringPrintf; | 
 | 27 |  | 
 | 28 | namespace android { | 
 | 29 | namespace surfaceflinger { | 
 | 30 |  | 
 | 31 | // Time buckets for histogram, the calculated time deltas will be lower bounded | 
 | 32 | // to the buckets in this array. | 
 | 33 | static const std::array<int32_t, HISTOGRAM_SIZE> histogramConfig = | 
 | 34 |         {0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,  16, | 
 | 35 |          17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33, | 
 | 36 |          34,  36,  38,  40,  42,  44,  46,  48,  50,  54,  58,  62,  66,  70,  74,  78,  82, | 
 | 37 |          86,  90,  94,  98,  102, 106, 110, 114, 118, 122, 126, 130, 134, 138, 142, 146, 150, | 
 | 38 |          200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000}; | 
 | 39 |  | 
 | 40 | void TimeStatsHelper::Histogram::insert(int32_t delta) { | 
 | 41 |     if (delta < 0) return; | 
 | 42 |     // std::lower_bound won't work on out of range values | 
 | 43 |     if (delta > histogramConfig[HISTOGRAM_SIZE - 1]) { | 
| Yiwei Zhang | e5c49d5 | 2018-10-29 00:15:31 -0700 | [diff] [blame] | 44 |         hist[histogramConfig[HISTOGRAM_SIZE - 1]] += delta / histogramConfig[HISTOGRAM_SIZE - 1]; | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 45 |         return; | 
 | 46 |     } | 
 | 47 |     auto iter = std::lower_bound(histogramConfig.begin(), histogramConfig.end(), delta); | 
 | 48 |     hist[*iter]++; | 
 | 49 | } | 
 | 50 |  | 
| Yiwei Zhang | 91a8638 | 2018-11-15 14:44:40 -0800 | [diff] [blame] | 51 | int64_t TimeStatsHelper::Histogram::totalTime() const { | 
 | 52 |     int64_t ret = 0; | 
 | 53 |     for (const auto& ele : hist) { | 
 | 54 |         ret += ele.first * ele.second; | 
 | 55 |     } | 
 | 56 |     return ret; | 
 | 57 | } | 
 | 58 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 59 | float TimeStatsHelper::Histogram::averageTime() const { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 60 |     int64_t ret = 0; | 
 | 61 |     int64_t count = 0; | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 62 |     for (const auto& ele : hist) { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 63 |         count += ele.second; | 
 | 64 |         ret += ele.first * ele.second; | 
 | 65 |     } | 
 | 66 |     return static_cast<float>(ret) / count; | 
 | 67 | } | 
 | 68 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 69 | std::string TimeStatsHelper::Histogram::toString() const { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 70 |     std::string result; | 
 | 71 |     for (int32_t i = 0; i < HISTOGRAM_SIZE; ++i) { | 
 | 72 |         int32_t bucket = histogramConfig[i]; | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 73 |         int32_t count = (hist.count(bucket) == 0) ? 0 : hist.at(bucket); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 74 |         StringAppendF(&result, "%dms=%d ", bucket, count); | 
 | 75 |     } | 
 | 76 |     result.back() = '\n'; | 
 | 77 |     return result; | 
 | 78 | } | 
 | 79 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 80 | std::string TimeStatsHelper::TimeStatsLayer::toString() const { | 
| Yiwei Zhang | eaeea06 | 2018-06-28 14:46:51 -0700 | [diff] [blame] | 81 |     std::string result = "\n"; | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 82 |     StringAppendF(&result, "layerName = %s\n", layerName.c_str()); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 83 |     StringAppendF(&result, "packageName = %s\n", packageName.c_str()); | 
| Yiwei Zhang | eaeea06 | 2018-06-28 14:46:51 -0700 | [diff] [blame] | 84 |     StringAppendF(&result, "totalFrames = %d\n", totalFrames); | 
 | 85 |     StringAppendF(&result, "droppedFrames = %d\n", droppedFrames); | 
| Alec Mouri | 91f6df3 | 2020-01-30 08:48:58 -0800 | [diff] [blame] | 86 |     StringAppendF(&result, "lateAcquireFrames = %d\n", lateAcquireFrames); | 
 | 87 |     StringAppendF(&result, "badDesiredPresentFrames = %d\n", badDesiredPresentFrames); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 88 |     const auto iter = deltas.find("present2present"); | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 89 |     if (iter != deltas.end()) { | 
| Yiwei Zhang | dd221b2 | 2020-06-12 11:06:19 -0700 | [diff] [blame] | 90 |         const float averageTime = iter->second.averageTime(); | 
 | 91 |         const float averageFPS = averageTime < 1.0f ? 0.0f : 1000.0f / averageTime; | 
 | 92 |         StringAppendF(&result, "averageFPS = %.3f\n", averageFPS); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 93 |     } | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 94 |     for (const auto& ele : deltas) { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 95 |         StringAppendF(&result, "%s histogram is as below:\n", ele.first.c_str()); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 96 |         result.append(ele.second.toString()); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 97 |     } | 
 | 98 |  | 
 | 99 |     return result; | 
 | 100 | } | 
 | 101 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 102 | std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 103 |     std::string result = "SurfaceFlinger TimeStats:\n"; | 
| Yiwei Zhang | 91a8638 | 2018-11-15 14:44:40 -0800 | [diff] [blame] | 104 |     StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStart); | 
 | 105 |     StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEnd); | 
| Yiwei Zhang | eaeea06 | 2018-06-28 14:46:51 -0700 | [diff] [blame] | 106 |     StringAppendF(&result, "totalFrames = %d\n", totalFrames); | 
 | 107 |     StringAppendF(&result, "missedFrames = %d\n", missedFrames); | 
 | 108 |     StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames); | 
| Vishnu Nair | 9b079a2 | 2020-01-21 14:36:08 -0800 | [diff] [blame] | 109 |     StringAppendF(&result, "clientCompositionReusedFrames = %d\n", clientCompositionReusedFrames); | 
| Alec Mouri | 8de697e | 2020-03-19 10:52:01 -0700 | [diff] [blame] | 110 |     StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitches); | 
| Alec Mouri | 8f7a010 | 2020-04-15 12:11:10 -0700 | [diff] [blame] | 111 |     StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChanges); | 
| Yiwei Zhang | 91a8638 | 2018-11-15 14:44:40 -0800 | [diff] [blame] | 112 |     StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime); | 
| Alec Mouri | fb571ea | 2019-01-24 18:42:10 -0800 | [diff] [blame] | 113 |     StringAppendF(&result, "displayConfigStats is as below:\n"); | 
 | 114 |     for (const auto& [fps, duration] : refreshRateStats) { | 
 | 115 |         StringAppendF(&result, "%dfps=%ldms ", fps, ns2ms(duration)); | 
 | 116 |     } | 
 | 117 |     result.back() = '\n'; | 
| Yiwei Zhang | 91a8638 | 2018-11-15 14:44:40 -0800 | [diff] [blame] | 118 |     StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime()); | 
| Yiwei Zhang | ce6ebc0 | 2018-10-20 12:42:38 -0700 | [diff] [blame] | 119 |     StringAppendF(&result, "presentToPresent histogram is as below:\n"); | 
 | 120 |     result.append(presentToPresent.toString()); | 
| Vishnu Nair | abf97fd | 2020-02-03 13:51:16 -0800 | [diff] [blame] | 121 |     const float averageFrameDuration = frameDuration.averageTime(); | 
 | 122 |     StringAppendF(&result, "averageFrameDuration = %.3f ms\n", | 
 | 123 |                   std::isnan(averageFrameDuration) ? 0.0f : averageFrameDuration); | 
| Alec Mouri | 9519bf1 | 2019-11-15 16:54:44 -0800 | [diff] [blame] | 124 |     StringAppendF(&result, "frameDuration histogram is as below:\n"); | 
 | 125 |     result.append(frameDuration.toString()); | 
| Vishnu Nair | abf97fd | 2020-02-03 13:51:16 -0800 | [diff] [blame] | 126 |     const float averageRenderEngineTiming = renderEngineTiming.averageTime(); | 
 | 127 |     StringAppendF(&result, "averageRenderEngineTiming = %.3f ms\n", | 
 | 128 |                   std::isnan(averageRenderEngineTiming) ? 0.0f : averageRenderEngineTiming); | 
| Alec Mouri | e4034bb | 2019-11-19 12:45:54 -0800 | [diff] [blame] | 129 |     StringAppendF(&result, "renderEngineTiming histogram is as below:\n"); | 
 | 130 |     result.append(renderEngineTiming.toString()); | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 131 |     const auto dumpStats = generateDumpStats(maxLayers); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 132 |     for (const auto& ele : dumpStats) { | 
 | 133 |         result.append(ele->toString()); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 134 |     } | 
 | 135 |  | 
 | 136 |     return result; | 
 | 137 | } | 
 | 138 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 139 | SFTimeStatsLayerProto TimeStatsHelper::TimeStatsLayer::toProto() const { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 140 |     SFTimeStatsLayerProto layerProto; | 
 | 141 |     layerProto.set_layer_name(layerName); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 142 |     layerProto.set_package_name(packageName); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 143 |     layerProto.set_total_frames(totalFrames); | 
| Yiwei Zhang | eaeea06 | 2018-06-28 14:46:51 -0700 | [diff] [blame] | 144 |     layerProto.set_dropped_frames(droppedFrames); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 145 |     for (const auto& ele : deltas) { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 146 |         SFTimeStatsDeltaProto* deltaProto = layerProto.add_deltas(); | 
 | 147 |         deltaProto->set_delta_name(ele.first); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 148 |         for (const auto& histEle : ele.second.hist) { | 
| Yiwei Zhang | 3bef395 | 2018-05-04 14:08:01 -0700 | [diff] [blame] | 149 |             SFTimeStatsHistogramBucketProto* histProto = deltaProto->add_histograms(); | 
| Yiwei Zhang | eaeea06 | 2018-06-28 14:46:51 -0700 | [diff] [blame] | 150 |             histProto->set_time_millis(histEle.first); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 151 |             histProto->set_frame_count(histEle.second); | 
 | 152 |         } | 
 | 153 |     } | 
 | 154 |     return layerProto; | 
 | 155 | } | 
 | 156 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 157 | SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto( | 
 | 158 |         std::optional<uint32_t> maxLayers) const { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 159 |     SFTimeStatsGlobalProto globalProto; | 
 | 160 |     globalProto.set_stats_start(statsStart); | 
 | 161 |     globalProto.set_stats_end(statsEnd); | 
 | 162 |     globalProto.set_total_frames(totalFrames); | 
 | 163 |     globalProto.set_missed_frames(missedFrames); | 
 | 164 |     globalProto.set_client_composition_frames(clientCompositionFrames); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 165 |     globalProto.set_display_on_time(displayOnTime); | 
| Alec Mouri | fb571ea | 2019-01-24 18:42:10 -0800 | [diff] [blame] | 166 |     for (const auto& ele : refreshRateStats) { | 
 | 167 |         SFTimeStatsDisplayConfigBucketProto* configBucketProto = | 
 | 168 |                 globalProto.add_display_config_stats(); | 
 | 169 |         SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config(); | 
 | 170 |         configProto->set_fps(ele.first); | 
 | 171 |         configBucketProto->set_duration_millis(ns2ms(ele.second)); | 
 | 172 |     } | 
| Yiwei Zhang | ce6ebc0 | 2018-10-20 12:42:38 -0700 | [diff] [blame] | 173 |     for (const auto& histEle : presentToPresent.hist) { | 
 | 174 |         SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present(); | 
 | 175 |         histProto->set_time_millis(histEle.first); | 
 | 176 |         histProto->set_frame_count(histEle.second); | 
 | 177 |     } | 
| Alec Mouri | 9519bf1 | 2019-11-15 16:54:44 -0800 | [diff] [blame] | 178 |     for (const auto& histEle : frameDuration.hist) { | 
 | 179 |         SFTimeStatsHistogramBucketProto* histProto = globalProto.add_frame_duration(); | 
 | 180 |         histProto->set_time_millis(histEle.first); | 
 | 181 |         histProto->set_frame_count(histEle.second); | 
 | 182 |     } | 
| Alec Mouri | e4034bb | 2019-11-19 12:45:54 -0800 | [diff] [blame] | 183 |     for (const auto& histEle : renderEngineTiming.hist) { | 
 | 184 |         SFTimeStatsHistogramBucketProto* histProto = globalProto.add_render_engine_timing(); | 
 | 185 |         histProto->set_time_millis(histEle.first); | 
 | 186 |         histProto->set_frame_count(histEle.second); | 
 | 187 |     } | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 188 |     const auto dumpStats = generateDumpStats(maxLayers); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 189 |     for (const auto& ele : dumpStats) { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 190 |         SFTimeStatsLayerProto* layerProto = globalProto.add_stats(); | 
 | 191 |         layerProto->CopyFrom(ele->toProto()); | 
 | 192 |     } | 
 | 193 |     return globalProto; | 
 | 194 | } | 
 | 195 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 196 | std::vector<TimeStatsHelper::TimeStatsLayer const*> | 
 | 197 | TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const { | 
 | 198 |     std::vector<TimeStatsLayer const*> dumpStats; | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 199 |     for (const auto& ele : stats) { | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 200 |         dumpStats.push_back(&ele.second); | 
 | 201 |     } | 
 | 202 |  | 
 | 203 |     std::sort(dumpStats.begin(), dumpStats.end(), | 
 | 204 |               [](TimeStatsHelper::TimeStatsLayer const* l, | 
 | 205 |                  TimeStatsHelper::TimeStatsLayer const* r) { | 
 | 206 |                   return l->totalFrames > r->totalFrames; | 
 | 207 |               }); | 
 | 208 |  | 
 | 209 |     if (maxLayers && (*maxLayers < dumpStats.size())) { | 
 | 210 |         dumpStats.resize(*maxLayers); | 
 | 211 |     } | 
 | 212 |     return dumpStats; | 
 | 213 | } | 
 | 214 |  | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 215 | } // namespace surfaceflinger | 
 | 216 | } // namespace android |