Plumb refresh and render rates into shared timeline
* Make the overridden frame rate from the Scheduler public so that
SurfaceFlinger can access it for each uid.
* Add the display refresh rate on each display frame
* Add the application rendering rate on each SurfaceFrame created
* If there is no application rendering rate, then set it to the display
refresh rate.
* Plumb all those metrics into TimeStats.
* Change global metrics to increment for every SurfaceFrame instead of
every DisplayFrame, so that the rendering rate dimension can be
accurately captured.
Bug: 172937287
Test: builds, boots, timestats dump
Change-Id: Icfd4cecfdfa5d6c434661cab91c624eb08e8baea
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 0fb748f..df7be1f 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -90,6 +90,8 @@
std::string TimeStatsHelper::TimeStatsLayer::toString() const {
std::string result = "\n";
+ StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket);
+ StringAppendF(&result, "renderRate = %d fps\n", renderRateBucket);
StringAppendF(&result, "uid = %d\n", uid);
StringAppendF(&result, "layerName = %s\n", layerName.c_str());
StringAppendF(&result, "packageName = %s\n", packageName.c_str());
@@ -115,35 +117,45 @@
std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const {
std::string result = "SurfaceFlinger TimeStats:\n";
- StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStart);
- StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEnd);
- StringAppendF(&result, "totalFrames = %d\n", totalFrames);
- StringAppendF(&result, "missedFrames = %d\n", missedFrames);
- StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
- StringAppendF(&result, "clientCompositionReusedFrames = %d\n", clientCompositionReusedFrames);
- StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitches);
- StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChanges);
- StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
- result.append("Global aggregated jank payload:\n");
- result.append(jankPayload.toString());
+ result.append("Legacy stats are as follows:\n");
+ StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStartLegacy);
+ StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEndLegacy);
+ StringAppendF(&result, "totalFrames = %d\n", totalFramesLegacy);
+ StringAppendF(&result, "missedFrames = %d\n", missedFramesLegacy);
+ StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFramesLegacy);
+ StringAppendF(&result, "clientCompositionReusedFrames = %d\n",
+ clientCompositionReusedFramesLegacy);
+ StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy);
+ StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy);
+ StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy);
StringAppendF(&result, "displayConfigStats is as below:\n");
- for (const auto& [fps, duration] : refreshRateStats) {
+ for (const auto& [fps, duration] : refreshRateStatsLegacy) {
StringAppendF(&result, "%dfps = %ldms\n", fps, ns2ms(duration));
}
result.back() = '\n';
- StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
+ StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresentLegacy.totalTime());
StringAppendF(&result, "presentToPresent histogram is as below:\n");
- result.append(presentToPresent.toString());
- const float averageFrameDuration = frameDuration.averageTime();
+ result.append(presentToPresentLegacy.toString());
+ const float averageFrameDuration = frameDurationLegacy.averageTime();
StringAppendF(&result, "averageFrameDuration = %.3f ms\n",
std::isnan(averageFrameDuration) ? 0.0f : averageFrameDuration);
StringAppendF(&result, "frameDuration histogram is as below:\n");
- result.append(frameDuration.toString());
- const float averageRenderEngineTiming = renderEngineTiming.averageTime();
+ result.append(frameDurationLegacy.toString());
+ const float averageRenderEngineTiming = renderEngineTimingLegacy.averageTime();
StringAppendF(&result, "averageRenderEngineTiming = %.3f ms\n",
std::isnan(averageRenderEngineTiming) ? 0.0f : averageRenderEngineTiming);
StringAppendF(&result, "renderEngineTiming histogram is as below:\n");
- result.append(renderEngineTiming.toString());
+ result.append(renderEngineTimingLegacy.toString());
+
+ result.append("\nGlobal aggregated jank payload (Timeline stats):");
+ for (const auto& ele : stats) {
+ result.append("\n");
+ StringAppendF(&result, "displayRefreshRate = %d fps\n",
+ ele.second.key.displayRefreshRateBucket);
+ StringAppendF(&result, "renderRate = %d fps\n", ele.second.key.renderRateBucket);
+ result.append(ele.second.jankPayload.toString());
+ }
+
const auto dumpStats = generateDumpStats(maxLayers);
for (const auto& ele : dumpStats) {
result.append(ele->toString());
@@ -173,30 +185,30 @@
SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto(
std::optional<uint32_t> maxLayers) const {
SFTimeStatsGlobalProto globalProto;
- globalProto.set_stats_start(statsStart);
- globalProto.set_stats_end(statsEnd);
- globalProto.set_total_frames(totalFrames);
- globalProto.set_missed_frames(missedFrames);
- globalProto.set_client_composition_frames(clientCompositionFrames);
- globalProto.set_display_on_time(displayOnTime);
- for (const auto& ele : refreshRateStats) {
+ globalProto.set_stats_start(statsStartLegacy);
+ globalProto.set_stats_end(statsEndLegacy);
+ globalProto.set_total_frames(totalFramesLegacy);
+ globalProto.set_missed_frames(missedFramesLegacy);
+ globalProto.set_client_composition_frames(clientCompositionFramesLegacy);
+ globalProto.set_display_on_time(displayOnTimeLegacy);
+ for (const auto& ele : refreshRateStatsLegacy) {
SFTimeStatsDisplayConfigBucketProto* configBucketProto =
globalProto.add_display_config_stats();
SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config();
configProto->set_fps(ele.first);
configBucketProto->set_duration_millis(ns2ms(ele.second));
}
- for (const auto& histEle : presentToPresent.hist) {
+ for (const auto& histEle : presentToPresentLegacy.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
}
- for (const auto& histEle : frameDuration.hist) {
+ for (const auto& histEle : frameDurationLegacy.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_frame_duration();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
}
- for (const auto& histEle : renderEngineTiming.hist) {
+ for (const auto& histEle : renderEngineTimingLegacy.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_render_engine_timing();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
@@ -212,8 +224,18 @@
std::vector<TimeStatsHelper::TimeStatsLayer const*>
TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
std::vector<TimeStatsLayer const*> dumpStats;
+
+ int numLayers = 0;
for (const auto& ele : stats) {
- dumpStats.push_back(&ele.second);
+ numLayers += ele.second.stats.size();
+ }
+
+ dumpStats.reserve(numLayers);
+
+ for (const auto& ele : stats) {
+ for (const auto& layerEle : ele.second.stats) {
+ dumpStats.push_back(&layerEle.second);
+ }
}
std::sort(dumpStats.begin(), dumpStats.end(),