| 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); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 86 | const auto iter = deltas.find("present2present"); | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 87 | if (iter != deltas.end()) { | 
|  | 88 | StringAppendF(&result, "averageFPS = %.3f\n", 1000.0 / iter->second.averageTime()); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 89 | } | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 90 | for (const auto& ele : deltas) { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 91 | StringAppendF(&result, "%s histogram is as below:\n", ele.first.c_str()); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 92 | result.append(ele.second.toString()); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 93 | } | 
|  | 94 |  | 
|  | 95 | return result; | 
|  | 96 | } | 
|  | 97 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 98 | std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 99 | std::string result = "SurfaceFlinger TimeStats:\n"; | 
| Yiwei Zhang | 91a8638 | 2018-11-15 14:44:40 -0800 | [diff] [blame] | 100 | StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStart); | 
|  | 101 | StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEnd); | 
| Yiwei Zhang | eaeea06 | 2018-06-28 14:46:51 -0700 | [diff] [blame] | 102 | StringAppendF(&result, "totalFrames = %d\n", totalFrames); | 
|  | 103 | StringAppendF(&result, "missedFrames = %d\n", missedFrames); | 
|  | 104 | StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames); | 
| Yiwei Zhang | 91a8638 | 2018-11-15 14:44:40 -0800 | [diff] [blame] | 105 | StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime); | 
| Alec Mouri | fb571ea | 2019-01-24 18:42:10 -0800 | [diff] [blame] | 106 | StringAppendF(&result, "displayConfigStats is as below:\n"); | 
|  | 107 | for (const auto& [fps, duration] : refreshRateStats) { | 
|  | 108 | StringAppendF(&result, "%dfps=%ldms ", fps, ns2ms(duration)); | 
|  | 109 | } | 
|  | 110 | result.back() = '\n'; | 
| Yiwei Zhang | 91a8638 | 2018-11-15 14:44:40 -0800 | [diff] [blame] | 111 | StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime()); | 
| Yiwei Zhang | ce6ebc0 | 2018-10-20 12:42:38 -0700 | [diff] [blame] | 112 | StringAppendF(&result, "presentToPresent histogram is as below:\n"); | 
|  | 113 | result.append(presentToPresent.toString()); | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 114 | const auto dumpStats = generateDumpStats(maxLayers); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 115 | for (const auto& ele : dumpStats) { | 
|  | 116 | result.append(ele->toString()); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 117 | } | 
|  | 118 |  | 
|  | 119 | return result; | 
|  | 120 | } | 
|  | 121 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 122 | SFTimeStatsLayerProto TimeStatsHelper::TimeStatsLayer::toProto() const { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 123 | SFTimeStatsLayerProto layerProto; | 
|  | 124 | layerProto.set_layer_name(layerName); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 125 | layerProto.set_package_name(packageName); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 126 | layerProto.set_total_frames(totalFrames); | 
| Yiwei Zhang | eaeea06 | 2018-06-28 14:46:51 -0700 | [diff] [blame] | 127 | layerProto.set_dropped_frames(droppedFrames); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 128 | for (const auto& ele : deltas) { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 129 | SFTimeStatsDeltaProto* deltaProto = layerProto.add_deltas(); | 
|  | 130 | deltaProto->set_delta_name(ele.first); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 131 | for (const auto& histEle : ele.second.hist) { | 
| Yiwei Zhang | 3bef395 | 2018-05-04 14:08:01 -0700 | [diff] [blame] | 132 | SFTimeStatsHistogramBucketProto* histProto = deltaProto->add_histograms(); | 
| Yiwei Zhang | eaeea06 | 2018-06-28 14:46:51 -0700 | [diff] [blame] | 133 | histProto->set_time_millis(histEle.first); | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 134 | histProto->set_frame_count(histEle.second); | 
|  | 135 | } | 
|  | 136 | } | 
|  | 137 | return layerProto; | 
|  | 138 | } | 
|  | 139 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 140 | SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto( | 
|  | 141 | std::optional<uint32_t> maxLayers) const { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 142 | SFTimeStatsGlobalProto globalProto; | 
|  | 143 | globalProto.set_stats_start(statsStart); | 
|  | 144 | globalProto.set_stats_end(statsEnd); | 
|  | 145 | globalProto.set_total_frames(totalFrames); | 
|  | 146 | globalProto.set_missed_frames(missedFrames); | 
|  | 147 | globalProto.set_client_composition_frames(clientCompositionFrames); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 148 | globalProto.set_display_on_time(displayOnTime); | 
| Alec Mouri | fb571ea | 2019-01-24 18:42:10 -0800 | [diff] [blame] | 149 | for (const auto& ele : refreshRateStats) { | 
|  | 150 | SFTimeStatsDisplayConfigBucketProto* configBucketProto = | 
|  | 151 | globalProto.add_display_config_stats(); | 
|  | 152 | SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config(); | 
|  | 153 | configProto->set_fps(ele.first); | 
|  | 154 | configBucketProto->set_duration_millis(ns2ms(ele.second)); | 
|  | 155 | } | 
| Yiwei Zhang | ce6ebc0 | 2018-10-20 12:42:38 -0700 | [diff] [blame] | 156 | for (const auto& histEle : presentToPresent.hist) { | 
|  | 157 | SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present(); | 
|  | 158 | histProto->set_time_millis(histEle.first); | 
|  | 159 | histProto->set_frame_count(histEle.second); | 
|  | 160 | } | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 161 | const auto dumpStats = generateDumpStats(maxLayers); | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 162 | for (const auto& ele : dumpStats) { | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 163 | SFTimeStatsLayerProto* layerProto = globalProto.add_stats(); | 
|  | 164 | layerProto->CopyFrom(ele->toProto()); | 
|  | 165 | } | 
|  | 166 | return globalProto; | 
|  | 167 | } | 
|  | 168 |  | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 169 | std::vector<TimeStatsHelper::TimeStatsLayer const*> | 
|  | 170 | TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const { | 
|  | 171 | std::vector<TimeStatsLayer const*> dumpStats; | 
| Yiwei Zhang | 3a226d2 | 2018-10-16 09:23:03 -0700 | [diff] [blame] | 172 | for (const auto& ele : stats) { | 
| Yiwei Zhang | 8a4015c | 2018-05-08 16:03:47 -0700 | [diff] [blame] | 173 | dumpStats.push_back(&ele.second); | 
|  | 174 | } | 
|  | 175 |  | 
|  | 176 | std::sort(dumpStats.begin(), dumpStats.end(), | 
|  | 177 | [](TimeStatsHelper::TimeStatsLayer const* l, | 
|  | 178 | TimeStatsHelper::TimeStatsLayer const* r) { | 
|  | 179 | return l->totalFrames > r->totalFrames; | 
|  | 180 | }); | 
|  | 181 |  | 
|  | 182 | if (maxLayers && (*maxLayers < dumpStats.size())) { | 
|  | 183 | dumpStats.resize(*maxLayers); | 
|  | 184 | } | 
|  | 185 | return dumpStats; | 
|  | 186 | } | 
|  | 187 |  | 
| Yiwei Zhang | 0102ad2 | 2018-05-02 17:37:17 -0700 | [diff] [blame] | 188 | } // namespace surfaceflinger | 
|  | 189 | } // namespace android |