SF TimeStats: add global present to present histogram
Bug: b/79872109
Test: dumpsys SurfaceFlinger --timestats <options>
Change-Id: Iab8c01d66c69a04a89f7e9313e53ff961ce0175c
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fa6ef25..d3f3460 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1909,6 +1909,8 @@
mTimeStats.incrementClientCompositionFrames();
}
+ mTimeStats.setPresentFenceGlobal(presentFenceTime);
+
if (display && getHwComposer().isConnected(display->getId()) &&
display->getPowerMode() == HWC_POWER_MODE_OFF) {
return;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index c14d93b..f754d47 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -479,6 +479,54 @@
mPowerTime.powerMode = powerMode;
}
+void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
+ ATRACE_CALL();
+
+ while (!mGlobalRecord.presentFences.empty()) {
+ const nsecs_t curPresentTime = mGlobalRecord.presentFences.front()->getSignalTime();
+ if (curPresentTime == Fence::SIGNAL_TIME_PENDING) break;
+
+ if (curPresentTime == Fence::SIGNAL_TIME_INVALID) {
+ ALOGE("GlobalPresentFence is invalid!");
+ mGlobalRecord.prevPresentTime = 0;
+ mGlobalRecord.presentFences.pop_front();
+ continue;
+ }
+
+ ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
+ mGlobalRecord.presentFences.front()->getSignalTime());
+
+ const int32_t presentToPresentMs = msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
+ ALOGV("Global present2present[%d]", presentToPresentMs);
+
+ mTimeStats.presentToPresent.insert(presentToPresentMs);
+ mGlobalRecord.prevPresentTime = curPresentTime;
+ mGlobalRecord.presentFences.pop_front();
+ }
+}
+
+void TimeStats::setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (presentFence == nullptr) {
+ mGlobalRecord.prevPresentTime = 0;
+ return;
+ }
+
+ if (mGlobalRecord.presentFences.size() == MAX_NUM_TIME_RECORDS) {
+ // The front presentFence must be trapped in pending status in this
+ // case. Try dequeuing the front one to recover.
+ ALOGE("GlobalPresentFences is already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
+ mGlobalRecord.prevPresentTime = 0;
+ mGlobalRecord.presentFences.pop_front();
+ }
+
+ mGlobalRecord.presentFences.emplace_back(presentFence);
+ flushAvailableGlobalRecordsToStatsLocked();
+}
+
void TimeStats::enable() {
if (mEnabled.load()) return;
@@ -514,6 +562,7 @@
mTimeStats.missedFrames = 0;
mTimeStats.clientCompositionFrames = 0;
mTimeStats.displayOnTime = 0;
+ mTimeStats.presentToPresent.hist.clear();
mPowerTime.prevTime = systemTime();
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 87e21a7..c78d84e 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -73,6 +73,11 @@
nsecs_t prevTime = 0;
};
+ struct GlobalRecord {
+ nsecs_t prevPresentTime = 0;
+ std::deque<std::shared_ptr<FenceTime>> presentFences;
+ };
+
public:
static TimeStats& getInstance();
void parseArgs(bool asProto, const Vector<String16>& args, size_t& index, String8& result);
@@ -99,6 +104,7 @@
void removeTimeRecord(const std::string& layerName, uint64_t frameNumber);
void setPowerMode(int32_t powerMode);
+ void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence);
private:
TimeStats() = default;
@@ -106,6 +112,7 @@
bool recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord);
void flushAvailableRecordsToStatsLocked(const std::string& layerName);
void flushPowerTimeLocked();
+ void flushAvailableGlobalRecordsToStatsLocked();
void enable();
void disable();
@@ -118,6 +125,7 @@
TimeStatsHelper::TimeStatsGlobal mTimeStats;
std::unordered_map<std::string, LayerRecord> mTimeStatsTracker;
PowerTime mPowerTime;
+ GlobalRecord mGlobalRecord;
};
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index ec41a62..c701224 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -93,6 +93,8 @@
StringAppendF(&result, "missedFrames = %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
StringAppendF(&result, "displayOnTime = %lld ms\n", static_cast<long long int>(displayOnTime));
+ StringAppendF(&result, "presentToPresent histogram is as below:\n");
+ result.append(presentToPresent.toString());
const auto dumpStats = generateDumpStats(maxLayers);
for (const auto& ele : dumpStats) {
result.append(ele->toString());
@@ -128,6 +130,11 @@
globalProto.set_missed_frames(missedFrames);
globalProto.set_client_composition_frames(clientCompositionFrames);
globalProto.set_display_on_time(displayOnTime);
+ for (const auto& histEle : presentToPresent.hist) {
+ SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
+ histProto->set_time_millis(histEle.first);
+ histProto->set_frame_count(histEle.second);
+ }
const auto dumpStats = generateDumpStats(maxLayers);
for (const auto& ele : dumpStats) {
SFTimeStatsLayerProto* layerProto = globalProto.add_stats();
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 939e137..7d0fe79 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -58,6 +58,7 @@
int32_t missedFrames = 0;
int32_t clientCompositionFrames = 0;
int64_t displayOnTime = 0;
+ Histogram presentToPresent;
std::unordered_map<std::string, TimeStatsLayer> stats;
std::string toString(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index f584496..377612a 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -25,7 +25,7 @@
// changes to these messages, and keep google3 side proto messages in sync if
// the end to end pipeline needs to be updated.
-// Next tag: 8
+// Next tag: 9
message SFTimeStatsGlobalProto {
// The stats start time in UTC as seconds since January 1, 1970
optional int64 stats_start = 1;
@@ -39,6 +39,8 @@
optional int32 client_composition_frames = 5;
// Primary display on time in milliseconds.
optional int64 display_on_time = 7;
+ // Present to present histogram.
+ repeated SFTimeStatsHistogramBucketProto present_to_present = 8;
// Stats per layer. Apps could have multiple layers.
repeated SFTimeStatsLayerProto stats = 6;
}