Home | History | Annotate | Download | only in timestatsproto
      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 #include <android-base/stringprintf.h>
     17 #include <timestatsproto/TimeStatsHelper.h>
     18 
     19 #include <array>
     20 
     21 #define HISTOGRAM_SIZE 85
     22 
     23 using android::base::StringAppendF;
     24 using android::base::StringPrintf;
     25 
     26 namespace android {
     27 namespace surfaceflinger {
     28 
     29 // Time buckets for histogram, the calculated time deltas will be lower bounded
     30 // to the buckets in this array.
     31 static const std::array<int32_t, HISTOGRAM_SIZE> histogramConfig =
     32         {0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,  16,
     33          17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,
     34          34,  36,  38,  40,  42,  44,  46,  48,  50,  54,  58,  62,  66,  70,  74,  78,  82,
     35          86,  90,  94,  98,  102, 106, 110, 114, 118, 122, 126, 130, 134, 138, 142, 146, 150,
     36          200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000};
     37 
     38 void TimeStatsHelper::Histogram::insert(int32_t delta) {
     39     if (delta < 0) return;
     40     // std::lower_bound won't work on out of range values
     41     if (delta > histogramConfig[HISTOGRAM_SIZE - 1]) {
     42         hist[histogramConfig[HISTOGRAM_SIZE - 1]]++;
     43         return;
     44     }
     45     auto iter = std::lower_bound(histogramConfig.begin(), histogramConfig.end(), delta);
     46     hist[*iter]++;
     47 }
     48 
     49 float TimeStatsHelper::Histogram::averageTime() const {
     50     int64_t ret = 0;
     51     int64_t count = 0;
     52     for (auto& ele : hist) {
     53         count += ele.second;
     54         ret += ele.first * ele.second;
     55     }
     56     return static_cast<float>(ret) / count;
     57 }
     58 
     59 std::string TimeStatsHelper::Histogram::toString() const {
     60     std::string result;
     61     for (int32_t i = 0; i < HISTOGRAM_SIZE; ++i) {
     62         int32_t bucket = histogramConfig[i];
     63         int32_t count = (hist.count(bucket) == 0) ? 0 : hist.at(bucket);
     64         StringAppendF(&result, "%dms=%d ", bucket, count);
     65     }
     66     result.back() = '\n';
     67     return result;
     68 }
     69 
     70 std::string TimeStatsHelper::TimeStatsLayer::toString() const {
     71     std::string result = "";
     72     StringAppendF(&result, "layerName = %s\n", layerName.c_str());
     73     StringAppendF(&result, "packageName = %s\n", packageName.c_str());
     74     StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
     75     StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
     76     StringAppendF(&result, "totalFrames= %d\n", totalFrames);
     77     auto iter = deltas.find("present2present");
     78     if (iter != deltas.end()) {
     79         StringAppendF(&result, "averageFPS = %.3f\n", 1000.0 / iter->second.averageTime());
     80     }
     81     for (auto& ele : deltas) {
     82         StringAppendF(&result, "%s histogram is as below:\n", ele.first.c_str());
     83         StringAppendF(&result, "%s", ele.second.toString().c_str());
     84     }
     85 
     86     return result;
     87 }
     88 
     89 std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const {
     90     std::string result = "SurfaceFlinger TimeStats:\n";
     91     StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
     92     StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
     93     StringAppendF(&result, "totalFrames= %d\n", totalFrames);
     94     StringAppendF(&result, "missedFrames= %d\n", missedFrames);
     95     StringAppendF(&result, "clientCompositionFrames= %d\n", clientCompositionFrames);
     96     StringAppendF(&result, "TimeStats for each layer is as below:\n");
     97     const auto dumpStats = generateDumpStats(maxLayers);
     98     for (auto& ele : dumpStats) {
     99         StringAppendF(&result, "%s", ele->toString().c_str());
    100     }
    101 
    102     return result;
    103 }
    104 
    105 SFTimeStatsLayerProto TimeStatsHelper::TimeStatsLayer::toProto() const {
    106     SFTimeStatsLayerProto layerProto;
    107     layerProto.set_layer_name(layerName);
    108     layerProto.set_package_name(packageName);
    109     layerProto.set_stats_start(statsStart);
    110     layerProto.set_stats_end(statsEnd);
    111     layerProto.set_total_frames(totalFrames);
    112     for (auto& ele : deltas) {
    113         SFTimeStatsDeltaProto* deltaProto = layerProto.add_deltas();
    114         deltaProto->set_delta_name(ele.first);
    115         for (auto& histEle : ele.second.hist) {
    116             SFTimeStatsHistogramBucketProto* histProto = deltaProto->add_histograms();
    117             histProto->set_render_millis(histEle.first);
    118             histProto->set_frame_count(histEle.second);
    119         }
    120     }
    121     return layerProto;
    122 }
    123 
    124 SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto(
    125         std::optional<uint32_t> maxLayers) const {
    126     SFTimeStatsGlobalProto globalProto;
    127     globalProto.set_stats_start(statsStart);
    128     globalProto.set_stats_end(statsEnd);
    129     globalProto.set_total_frames(totalFrames);
    130     globalProto.set_missed_frames(missedFrames);
    131     globalProto.set_client_composition_frames(clientCompositionFrames);
    132     const auto dumpStats = generateDumpStats(maxLayers);
    133     for (auto& ele : dumpStats) {
    134         SFTimeStatsLayerProto* layerProto = globalProto.add_stats();
    135         layerProto->CopyFrom(ele->toProto());
    136     }
    137     return globalProto;
    138 }
    139 
    140 std::vector<TimeStatsHelper::TimeStatsLayer const*>
    141 TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
    142     std::vector<TimeStatsLayer const*> dumpStats;
    143     for (auto& ele : stats) {
    144         dumpStats.push_back(&ele.second);
    145     }
    146 
    147     std::sort(dumpStats.begin(), dumpStats.end(),
    148               [](TimeStatsHelper::TimeStatsLayer const* l,
    149                  TimeStatsHelper::TimeStatsLayer const* r) {
    150                   return l->totalFrames > r->totalFrames;
    151               });
    152 
    153     if (maxLayers && (*maxLayers < dumpStats.size())) {
    154         dumpStats.resize(*maxLayers);
    155     }
    156     return dumpStats;
    157 }
    158 
    159 } // namespace surfaceflinger
    160 } // namespace android
    161