| 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 |