summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/TimeStats/TimeStats.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/TimeStats/TimeStats.cpp')
-rw-r--r--services/surfaceflinger/TimeStats/TimeStats.cpp532
1 files changed, 160 insertions, 372 deletions
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 7c1f21f9e4..37194c6355 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -14,14 +14,18 @@
* limitations under the License.
*/
-#include <unordered_map>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
#undef LOG_TAG
#define LOG_TAG "TimeStats"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include "TimeStats.h"
+
#include <android-base/stringprintf.h>
+#include <android/util/ProtoOutputStream.h>
#include <log/log.h>
-#include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -29,131 +33,100 @@
#include <algorithm>
#include <chrono>
-#include "TimeStats.h"
-#include "timestatsproto/TimeStatsHelper.h"
-
namespace android {
namespace impl {
-namespace {
+AStatsManager_PullAtomCallbackReturn TimeStats::pullAtomCallback(int32_t atom_tag,
+ AStatsEventList* data,
+ void* cookie) {
+ impl::TimeStats* timeStats = reinterpret_cast<impl::TimeStats*>(cookie);
+ AStatsManager_PullAtomCallbackReturn result = AStatsManager_PULL_SKIP;
+ if (atom_tag == android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) {
+ result = timeStats->populateGlobalAtom(data);
+ } else if (atom_tag == android::util::SURFACEFLINGER_STATS_LAYER_INFO) {
+ result = timeStats->populateLayerAtom(data);
+ }
+
+ // Enable timestats now. The first full pull for a given build is expected to
+ // have empty or very little stats, as stats are first enabled after the
+ // first pull is completed for either the global or layer stats.
+ timeStats->enable();
+ return result;
+}
-FrameTimingHistogram histogramToProto(const std::unordered_map<int32_t, int32_t>& histogram,
- size_t maxPulledHistogramBuckets) {
+namespace {
+// Histograms align with the order of fields in SurfaceflingerStatsLayerInfo.
+const std::array<std::string, 6> kHistogramNames = {
+ "present2present", "post2present", "acquire2present",
+ "latch2present", "desired2present", "post2acquire",
+};
+
+std::string histogramToProtoByteString(const std::unordered_map<int32_t, int32_t>& histogram,
+ size_t maxPulledHistogramBuckets) {
auto buckets = std::vector<std::pair<int32_t, int32_t>>(histogram.begin(), histogram.end());
std::sort(buckets.begin(), buckets.end(),
[](std::pair<int32_t, int32_t>& left, std::pair<int32_t, int32_t>& right) {
return left.second > right.second;
});
- FrameTimingHistogram histogramProto;
+ util::ProtoOutputStream proto;
int histogramSize = 0;
for (const auto& bucket : buckets) {
if (++histogramSize > maxPulledHistogramBuckets) {
break;
}
- histogramProto.add_time_millis_buckets((int32_t)bucket.first);
- histogramProto.add_frame_counts((int64_t)bucket.second);
- }
- return histogramProto;
-}
-
-SurfaceflingerStatsLayerInfo_GameMode gameModeToProto(int32_t gameMode) {
- switch (gameMode) {
- case TimeStatsHelper::GameModeUnsupported:
- return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSUPPORTED;
- case TimeStatsHelper::GameModeStandard:
- return SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD;
- case TimeStatsHelper::GameModePerformance:
- return SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE;
- case TimeStatsHelper::GameModeBattery:
- return SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY;
- default:
- return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSPECIFIED;
+ proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
+ 1 /* field id */,
+ (int32_t)bucket.first);
+ proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+ 2 /* field id */,
+ (int64_t)bucket.second);
}
-}
-SurfaceflingerStatsLayerInfo_SetFrameRateVote frameRateVoteToProto(
- const TimeStats::SetFrameRateVote& setFrameRateVote) {
- using FrameRateCompatibilityEnum =
- SurfaceflingerStatsLayerInfo::SetFrameRateVote::FrameRateCompatibility;
- using SeamlessnessEnum = SurfaceflingerStatsLayerInfo::SetFrameRateVote::Seamlessness;
-
- SurfaceflingerStatsLayerInfo_SetFrameRateVote proto;
- proto.set_frame_rate(setFrameRateVote.frameRate);
- proto.set_frame_rate_compatibility(
- static_cast<FrameRateCompatibilityEnum>(setFrameRateVote.frameRateCompatibility));
- proto.set_seamlessness(static_cast<SeamlessnessEnum>(setFrameRateVote.seamlessness));
- return proto;
+ std::string byteString;
+ proto.serializeToString(&byteString);
+ return byteString;
}
} // namespace
-bool TimeStats::populateGlobalAtom(std::string* pulledData) {
+AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mTimeStats.statsStartLegacy == 0) {
- return false;
+ if (mTimeStats.statsStart == 0) {
+ return AStatsManager_PULL_SKIP;
}
flushPowerTimeLocked();
- SurfaceflingerStatsGlobalInfoWrapper atomList;
- for (const auto& globalSlice : mTimeStats.stats) {
- SurfaceflingerStatsGlobalInfo* atom = atomList.add_atom();
- atom->set_total_frames(mTimeStats.totalFramesLegacy);
- atom->set_missed_frames(mTimeStats.missedFramesLegacy);
- atom->set_client_composition_frames(mTimeStats.clientCompositionFramesLegacy);
- atom->set_display_on_millis(mTimeStats.displayOnTimeLegacy);
- atom->set_animation_millis(mTimeStats.presentToPresentLegacy.totalTime());
- atom->set_event_connection_count(mTimeStats.displayEventConnectionsCountLegacy);
- *atom->mutable_frame_duration() =
- histogramToProto(mTimeStats.frameDurationLegacy.hist, mMaxPulledHistogramBuckets);
- *atom->mutable_render_engine_timing() =
- histogramToProto(mTimeStats.renderEngineTimingLegacy.hist,
- mMaxPulledHistogramBuckets);
- atom->set_total_timeline_frames(globalSlice.second.jankPayload.totalFrames);
- atom->set_total_janky_frames(globalSlice.second.jankPayload.totalJankyFrames);
- atom->set_total_janky_frames_with_long_cpu(globalSlice.second.jankPayload.totalSFLongCpu);
- atom->set_total_janky_frames_with_long_gpu(globalSlice.second.jankPayload.totalSFLongGpu);
- atom->set_total_janky_frames_sf_unattributed(
- globalSlice.second.jankPayload.totalSFUnattributed);
- atom->set_total_janky_frames_app_unattributed(
- globalSlice.second.jankPayload.totalAppUnattributed);
- atom->set_total_janky_frames_sf_scheduling(
- globalSlice.second.jankPayload.totalSFScheduling);
- atom->set_total_jank_frames_sf_prediction_error(
- globalSlice.second.jankPayload.totalSFPredictionError);
- atom->set_total_jank_frames_app_buffer_stuffing(
- globalSlice.second.jankPayload.totalAppBufferStuffing);
- atom->set_display_refresh_rate_bucket(globalSlice.first.displayRefreshRateBucket);
- *atom->mutable_sf_deadline_misses() =
- histogramToProto(globalSlice.second.displayDeadlineDeltas.hist,
- mMaxPulledHistogramBuckets);
- *atom->mutable_sf_prediction_errors() =
- histogramToProto(globalSlice.second.displayPresentDeltas.hist,
- mMaxPulledHistogramBuckets);
- atom->set_render_rate_bucket(globalSlice.first.renderRateBucket);
- }
- // Always clear data.
+ AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
+ mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
+ std::string frameDurationBytes =
+ histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
+ frameDurationBytes.size());
+ std::string renderEngineTimingBytes =
+ histogramToProtoByteString(mTimeStats.renderEngineTiming.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(),
+ renderEngineTimingBytes.size());
+ mStatsDelegate->statsEventBuild(event);
clearGlobalLocked();
- return atomList.SerializeToString(pulledData);
+ return AStatsManager_PULL_SUCCESS;
}
-bool TimeStats::populateLayerAtom(std::string* pulledData) {
+AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) {
std::lock_guard<std::mutex> lock(mMutex);
- std::vector<TimeStatsHelper::TimeStatsLayer*> dumpStats;
- uint32_t numLayers = 0;
- for (const auto& globalSlice : mTimeStats.stats) {
- numLayers += globalSlice.second.stats.size();
- }
-
- dumpStats.reserve(numLayers);
-
- for (auto& globalSlice : mTimeStats.stats) {
- for (auto& layerSlice : globalSlice.second.stats) {
- dumpStats.push_back(&layerSlice.second);
- }
+ std::vector<TimeStatsHelper::TimeStatsLayer const*> dumpStats;
+ for (const auto& ele : mTimeStats.stats) {
+ dumpStats.push_back(&ele.second);
}
std::sort(dumpStats.begin(), dumpStats.end(),
@@ -166,74 +139,44 @@ bool TimeStats::populateLayerAtom(std::string* pulledData) {
dumpStats.resize(mMaxPulledLayers);
}
- SurfaceflingerStatsLayerInfoWrapper atomList;
- for (auto& layer : dumpStats) {
- SurfaceflingerStatsLayerInfo* atom = atomList.add_atom();
- atom->set_layer_name(layer->layerName);
- atom->set_total_frames(layer->totalFrames);
- atom->set_dropped_frames(layer->droppedFrames);
- const auto& present2PresentHist = layer->deltas.find("present2present");
- if (present2PresentHist != layer->deltas.cend()) {
- *atom->mutable_present_to_present() =
- histogramToProto(present2PresentHist->second.hist, mMaxPulledHistogramBuckets);
- }
- const auto& post2presentHist = layer->deltas.find("post2present");
- if (post2presentHist != layer->deltas.cend()) {
- *atom->mutable_post_to_present() =
- histogramToProto(post2presentHist->second.hist, mMaxPulledHistogramBuckets);
- }
- const auto& acquire2presentHist = layer->deltas.find("acquire2present");
- if (acquire2presentHist != layer->deltas.cend()) {
- *atom->mutable_acquire_to_present() =
- histogramToProto(acquire2presentHist->second.hist, mMaxPulledHistogramBuckets);
- }
- const auto& latch2presentHist = layer->deltas.find("latch2present");
- if (latch2presentHist != layer->deltas.cend()) {
- *atom->mutable_latch_to_present() =
- histogramToProto(latch2presentHist->second.hist, mMaxPulledHistogramBuckets);
- }
- const auto& desired2presentHist = layer->deltas.find("desired2present");
- if (desired2presentHist != layer->deltas.cend()) {
- *atom->mutable_desired_to_present() =
- histogramToProto(desired2presentHist->second.hist, mMaxPulledHistogramBuckets);
- }
- const auto& post2acquireHist = layer->deltas.find("post2acquire");
- if (post2acquireHist != layer->deltas.cend()) {
- *atom->mutable_post_to_acquire() =
- histogramToProto(post2acquireHist->second.hist, mMaxPulledHistogramBuckets);
+ for (const auto& layer : dumpStats) {
+ AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
+ mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_LAYER_INFO);
+ mStatsDelegate->statsEventWriteString8(event, layer->layerName.c_str());
+ mStatsDelegate->statsEventWriteInt64(event, layer->totalFrames);
+ mStatsDelegate->statsEventWriteInt64(event, layer->droppedFrames);
+
+ for (const auto& name : kHistogramNames) {
+ const auto& histogram = layer->deltas.find(name);
+ if (histogram == layer->deltas.cend()) {
+ mStatsDelegate->statsEventWriteByteArray(event, nullptr, 0);
+ } else {
+ std::string bytes = histogramToProtoByteString(histogram->second.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)bytes.c_str(),
+ bytes.size());
+ }
}
- atom->set_late_acquire_frames(layer->lateAcquireFrames);
- atom->set_bad_desired_present_frames(layer->badDesiredPresentFrames);
- atom->set_uid(layer->uid);
- atom->set_total_timeline_frames(layer->jankPayload.totalFrames);
- atom->set_total_janky_frames(layer->jankPayload.totalJankyFrames);
- atom->set_total_janky_frames_with_long_cpu(layer->jankPayload.totalSFLongCpu);
- atom->set_total_janky_frames_with_long_gpu(layer->jankPayload.totalSFLongGpu);
- atom->set_total_janky_frames_sf_unattributed(layer->jankPayload.totalSFUnattributed);
- atom->set_total_janky_frames_app_unattributed(layer->jankPayload.totalAppUnattributed);
- atom->set_total_janky_frames_sf_scheduling(layer->jankPayload.totalSFScheduling);
- atom->set_total_jank_frames_sf_prediction_error(layer->jankPayload.totalSFPredictionError);
- atom->set_total_jank_frames_app_buffer_stuffing(layer->jankPayload.totalAppBufferStuffing);
- atom->set_display_refresh_rate_bucket(layer->displayRefreshRateBucket);
- atom->set_render_rate_bucket(layer->renderRateBucket);
- *atom->mutable_set_frame_rate_vote() = frameRateVoteToProto(layer->setFrameRateVote);
- *atom->mutable_app_deadline_misses() =
- histogramToProto(layer->deltas["appDeadlineDeltas"].hist,
- mMaxPulledHistogramBuckets);
- atom->set_game_mode(gameModeToProto(layer->gameMode));
- }
+ mStatsDelegate->statsEventWriteInt64(event, layer->lateAcquireFrames);
+ mStatsDelegate->statsEventWriteInt64(event, layer->badDesiredPresentFrames);
- // Always clear data.
+ mStatsDelegate->statsEventBuild(event);
+ }
clearLayersLocked();
- return atomList.SerializeToString(pulledData);
+ return AStatsManager_PULL_SUCCESS;
}
-TimeStats::TimeStats() : TimeStats(std::nullopt, std::nullopt) {}
+TimeStats::TimeStats() : TimeStats(nullptr, std::nullopt, std::nullopt) {}
-TimeStats::TimeStats(std::optional<size_t> maxPulledLayers,
+TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate,
+ std::optional<size_t> maxPulledLayers,
std::optional<size_t> maxPulledHistogramBuckets) {
+ if (statsDelegate != nullptr) {
+ mStatsDelegate = std::move(statsDelegate);
+ }
+
if (maxPulledLayers) {
mMaxPulledLayers = *maxPulledLayers;
}
@@ -243,19 +186,18 @@ TimeStats::TimeStats(std::optional<size_t> maxPulledLayers,
}
}
-bool TimeStats::onPullAtom(const int atomId, std::string* pulledData) {
- bool success = false;
- if (atomId == 10062) { // SURFACEFLINGER_STATS_GLOBAL_INFO
- success = populateGlobalAtom(pulledData);
- } else if (atomId == 10063) { // SURFACEFLINGER_STATS_LAYER_INFO
- success = populateLayerAtom(pulledData);
- }
+TimeStats::~TimeStats() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mStatsDelegate->clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ mStatsDelegate->clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO);
+}
- // Enable timestats now. The first full pull for a given build is expected to
- // have empty or very little stats, as stats are first enabled after the
- // first pull is completed for either the global or layer stats.
- enable();
- return success;
+void TimeStats::onBootFinished() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mStatsDelegate->setStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ nullptr, TimeStats::pullAtomCallback, this);
+ mStatsDelegate->setStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ nullptr, TimeStats::pullAtomCallback, this);
}
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
@@ -309,7 +251,7 @@ void TimeStats::incrementTotalFrames() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.totalFramesLegacy++;
+ mTimeStats.totalFrames++;
}
void TimeStats::incrementMissedFrames() {
@@ -318,7 +260,7 @@ void TimeStats::incrementMissedFrames() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.missedFramesLegacy++;
+ mTimeStats.missedFrames++;
}
void TimeStats::incrementClientCompositionFrames() {
@@ -327,7 +269,7 @@ void TimeStats::incrementClientCompositionFrames() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionFramesLegacy++;
+ mTimeStats.clientCompositionFrames++;
}
void TimeStats::incrementClientCompositionReusedFrames() {
@@ -336,7 +278,7 @@ void TimeStats::incrementClientCompositionReusedFrames() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionReusedFramesLegacy++;
+ mTimeStats.clientCompositionReusedFrames++;
}
void TimeStats::incrementRefreshRateSwitches() {
@@ -345,7 +287,7 @@ void TimeStats::incrementRefreshRateSwitches() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.refreshRateSwitchesLegacy++;
+ mTimeStats.refreshRateSwitches++;
}
void TimeStats::incrementCompositionStrategyChanges() {
@@ -354,7 +296,7 @@ void TimeStats::incrementCompositionStrategyChanges() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.compositionStrategyChangesLegacy++;
+ mTimeStats.compositionStrategyChanges++;
}
void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
@@ -363,20 +305,16 @@ void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.displayEventConnectionsCountLegacy =
- std::max(mTimeStats.displayEventConnectionsCountLegacy, count);
-}
-
-static int32_t toMs(nsecs_t nanos) {
- int64_t millis =
- std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::nanoseconds(nanos))
- .count();
- millis = std::clamp(millis, int64_t(INT32_MIN), int64_t(INT32_MAX));
- return static_cast<int32_t>(millis);
+ mTimeStats.displayEventConnectionsCount =
+ std::max(mTimeStats.displayEventConnectionsCount, count);
}
static int32_t msBetween(nsecs_t start, nsecs_t end) {
- return toMs(end - start);
+ int64_t delta = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::nanoseconds(end - start))
+ .count();
+ delta = std::clamp(delta, int64_t(INT32_MIN), int64_t(INT32_MAX));
+ return static_cast<int32_t>(delta);
}
void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) {
@@ -384,7 +322,7 @@ void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) {
std::lock_guard<std::mutex> lock(mMutex);
if (mPowerTime.powerMode == PowerMode::ON) {
- mTimeStats.frameDurationLegacy.insert(msBetween(startTime, endTime));
+ mTimeStats.frameDuration.insert(msBetween(startTime, endTime));
}
}
@@ -447,52 +385,23 @@ bool TimeStats::recordReadyLocked(int32_t layerId, TimeRecord* timeRecord) {
return true;
}
-static int32_t clampToNearestBucket(Fps fps, size_t bucketWidth) {
- return std::round(fps.getValue() / bucketWidth) * bucketWidth;
-}
-
-void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
- std::optional<Fps> renderRate,
- SetFrameRateVote frameRateVote,
- int32_t gameMode) {
+void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) {
ATRACE_CALL();
- ALOGV("[%d]-flushAvailableRecordsToStatsLocked", layerId);
LayerRecord& layerRecord = mTimeStatsTracker[layerId];
TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
- const int32_t refreshRateBucket =
- clampToNearestBucket(displayRefreshRate, REFRESH_RATE_BUCKET_WIDTH);
- const int32_t renderRateBucket =
- clampToNearestBucket(renderRate ? *renderRate : displayRefreshRate,
- RENDER_RATE_BUCKET_WIDTH);
while (!timeRecords.empty()) {
if (!recordReadyLocked(layerId, &timeRecords[0])) break;
ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerId,
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
if (prevTimeRecord.ready) {
- uid_t uid = layerRecord.uid;
const std::string& layerName = layerRecord.layerName;
- TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
- if (!mTimeStats.stats.count(timelineKey)) {
- mTimeStats.stats[timelineKey].key = timelineKey;
+ if (!mTimeStats.stats.count(layerName)) {
+ mTimeStats.stats[layerName].layerName = layerName;
}
-
- TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey];
-
- TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName, gameMode};
- if (!displayStats.stats.count(layerKey)) {
- displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
- displayStats.stats[layerKey].renderRateBucket = renderRateBucket;
- displayStats.stats[layerKey].uid = uid;
- displayStats.stats[layerKey].layerName = layerName;
- displayStats.stats[layerKey].gameMode = gameMode;
- }
- if (frameRateVote.frameRate > 0.0f) {
- displayStats.stats[layerKey].setFrameRateVote = frameRateVote;
- }
- TimeStatsHelper::TimeStatsLayer& timeStatsLayer = displayStats.stats[layerKey];
+ TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[layerName];
timeStatsLayer.totalFrames++;
timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames;
@@ -553,22 +462,8 @@ static bool layerNameIsValid(const std::string& layerName) {
layerName.compare(0, kMinLenLayerName, kPopupWindowPrefix) != 0;
}
-bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName,
- int32_t gameMode) {
- uint32_t layerRecords = 0;
- for (const auto& record : mTimeStats.stats) {
- if (record.second.stats.count({uid, layerName, gameMode}) > 0) {
- return true;
- }
-
- layerRecords += record.second.stats.size();
- }
-
- return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
-}
-
void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
- uid_t uid, nsecs_t postTime, int32_t gameMode) {
+ nsecs_t postTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
@@ -576,14 +471,12 @@ void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::st
postTime);
std::lock_guard<std::mutex> lock(mMutex);
- if (!canAddNewAggregatedStats(uid, layerName, gameMode)) {
+ if (!mTimeStats.stats.count(layerName) && mTimeStats.stats.size() >= MAX_NUM_LAYER_STATS) {
return;
}
if (!mTimeStatsTracker.count(layerId) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS &&
layerNameIsValid(layerName)) {
- mTimeStatsTracker[layerId].uid = uid;
mTimeStatsTracker[layerId].layerName = layerName;
- mTimeStatsTracker[layerId].gameMode = gameMode;
}
if (!mTimeStatsTracker.count(layerId)) return;
LayerRecord& layerRecord = mTimeStatsTracker[layerId];
@@ -716,9 +609,7 @@ void TimeStats::setAcquireFence(int32_t layerId, uint64_t frameNumber,
}
}
-void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
- Fps displayRefreshRate, std::optional<Fps> renderRate,
- SetFrameRateVote frameRateVote, int32_t gameMode) {
+void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) {
if (!mEnabled.load()) return;
ATRACE_CALL();
@@ -737,14 +628,11 @@ void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t pr
layerRecord.waitData++;
}
- flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote,
- gameMode);
+ flushAvailableRecordsToStatsLocked(layerId);
}
void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& presentFence,
- Fps displayRefreshRate, std::optional<Fps> renderRate,
- SetFrameRateVote frameRateVote, int32_t gameMode) {
+ const std::shared_ptr<FenceTime>& presentFence) {
if (!mEnabled.load()) return;
ATRACE_CALL();
@@ -764,103 +652,7 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
layerRecord.waitData++;
}
- flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote,
- gameMode);
-}
-
-static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL |
- JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed |
- JankType::AppDeadlineMissed | JankType::PredictionError |
- JankType::SurfaceFlingerScheduling;
-
-template <class T>
-static void updateJankPayload(T& t, int32_t reasons) {
- t.jankPayload.totalFrames++;
-
- if (reasons & kValidJankyReason) {
- t.jankPayload.totalJankyFrames++;
- if ((reasons & JankType::SurfaceFlingerCpuDeadlineMissed) != 0) {
- t.jankPayload.totalSFLongCpu++;
- }
- if ((reasons & JankType::SurfaceFlingerGpuDeadlineMissed) != 0) {
- t.jankPayload.totalSFLongGpu++;
- }
- if ((reasons & JankType::DisplayHAL) != 0) {
- t.jankPayload.totalSFUnattributed++;
- }
- if ((reasons & JankType::AppDeadlineMissed) != 0) {
- t.jankPayload.totalAppUnattributed++;
- }
- if ((reasons & JankType::PredictionError) != 0) {
- t.jankPayload.totalSFPredictionError++;
- }
- if ((reasons & JankType::SurfaceFlingerScheduling) != 0) {
- t.jankPayload.totalSFScheduling++;
- }
- }
-
- // We want to track BufferStuffing separately as it can provide info on latency issues
- if (reasons & JankType::BufferStuffing) {
- t.jankPayload.totalAppBufferStuffing++;
- }
-}
-
-void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
-
- // Only update layer stats if we're already tracking the layer in TimeStats.
- // Otherwise, continue tracking the statistic but use a default layer name instead.
- // As an implementation detail, we do this because this method is expected to be
- // called from FrameTimeline, whose jank classification includes transaction jank
- // that occurs without a buffer. But, in general those layer names are not suitable as
- // aggregation keys: e.g., it's normal and expected for Window Manager to include the hash code
- // for an animation leash. So while we can show that jank in dumpsys, aggregating based on the
- // layer blows up the stats size, so as a workaround drop those stats. This assumes that
- // TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that
- // the first jank record is not dropped.
-
- static const std::string kDefaultLayerName = "none";
- static constexpr int32_t kDefaultGameMode = TimeStatsHelper::GameModeUnsupported;
-
- const int32_t refreshRateBucket =
- clampToNearestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH);
- const int32_t renderRateBucket =
- clampToNearestBucket(info.renderRate ? *info.renderRate : info.refreshRate,
- RENDER_RATE_BUCKET_WIDTH);
- const TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
-
- if (!mTimeStats.stats.count(timelineKey)) {
- mTimeStats.stats[timelineKey].key = timelineKey;
- }
-
- TimeStatsHelper::TimelineStats& timelineStats = mTimeStats.stats[timelineKey];
-
- updateJankPayload<TimeStatsHelper::TimelineStats>(timelineStats, info.reasons);
-
- TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName, info.gameMode};
- if (!timelineStats.stats.count(layerKey)) {
- layerKey = {info.uid, kDefaultLayerName, kDefaultGameMode};
- timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
- timelineStats.stats[layerKey].renderRateBucket = renderRateBucket;
- timelineStats.stats[layerKey].uid = info.uid;
- timelineStats.stats[layerKey].layerName = kDefaultLayerName;
- timelineStats.stats[layerKey].gameMode = kDefaultGameMode;
- }
-
- TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey];
- updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, info.reasons);
-
- if (info.reasons & kValidJankyReason) {
- // TimeStats Histograms only retain positive values, so we don't need to check if these
- // deadlines were really missed if we know that the frame had jank, since deadlines
- // that were met will be dropped.
- timelineStats.displayDeadlineDeltas.insert(toMs(info.displayDeadlineDelta));
- timelineStats.displayPresentDeltas.insert(toMs(info.displayPresentJitter));
- timeStatsLayer.deltas["appDeadlineDeltas"].insert(toMs(info.appDeadlineDelta));
- }
+ flushAvailableRecordsToStatsLocked(layerId);
}
void TimeStats::onDestroy(int32_t layerId) {
@@ -901,7 +693,7 @@ void TimeStats::flushPowerTimeLocked() {
switch (mPowerTime.powerMode) {
case PowerMode::ON:
- mTimeStats.displayOnTimeLegacy += elapsedTime;
+ mTimeStats.displayOnTime += elapsedTime;
break;
case PowerMode::OFF:
case PowerMode::DOZE:
@@ -930,10 +722,10 @@ void TimeStats::setPowerMode(PowerMode powerMode) {
void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mTimeStats.refreshRateStatsLegacy.count(fps)) {
- mTimeStats.refreshRateStatsLegacy[fps] += duration;
+ if (mTimeStats.refreshRateStats.count(fps)) {
+ mTimeStats.refreshRateStats[fps] += duration;
} else {
- mTimeStats.refreshRateStatsLegacy.insert({fps, duration});
+ mTimeStats.refreshRateStats.insert({fps, duration});
}
}
@@ -959,7 +751,7 @@ void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
- mTimeStats.presentToPresentLegacy.insert(presentToPresentMs);
+ mTimeStats.presentToPresent.insert(presentToPresentMs);
}
mGlobalRecord.prevPresentTime = curPresentTime;
@@ -986,7 +778,7 @@ void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
}
const int32_t renderEngineMs = msBetween(duration.startTime, endNs);
- mTimeStats.renderEngineTimingLegacy.insert(renderEngineMs);
+ mTimeStats.renderEngineTiming.insert(renderEngineMs);
mGlobalRecord.renderEngineDurations.pop_front();
}
@@ -1029,7 +821,7 @@ void TimeStats::enable() {
std::lock_guard<std::mutex> lock(mMutex);
mEnabled.store(true);
- mTimeStats.statsStartLegacy = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
mPowerTime.prevTime = systemTime();
ALOGD("Enabled");
}
@@ -1042,13 +834,12 @@ void TimeStats::disable() {
std::lock_guard<std::mutex> lock(mMutex);
flushPowerTimeLocked();
mEnabled.store(false);
- mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
ALOGD("Disabled");
}
void TimeStats::clearAll() {
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.stats.clear();
clearGlobalLocked();
clearLayersLocked();
}
@@ -1056,24 +847,21 @@ void TimeStats::clearAll() {
void TimeStats::clearGlobalLocked() {
ATRACE_CALL();
- mTimeStats.statsStartLegacy = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
- mTimeStats.statsEndLegacy = 0;
- mTimeStats.totalFramesLegacy = 0;
- mTimeStats.missedFramesLegacy = 0;
- mTimeStats.clientCompositionFramesLegacy = 0;
- mTimeStats.clientCompositionReusedFramesLegacy = 0;
- mTimeStats.refreshRateSwitchesLegacy = 0;
- mTimeStats.compositionStrategyChangesLegacy = 0;
- mTimeStats.displayEventConnectionsCountLegacy = 0;
- mTimeStats.displayOnTimeLegacy = 0;
- mTimeStats.presentToPresentLegacy.hist.clear();
- mTimeStats.frameDurationLegacy.hist.clear();
- mTimeStats.renderEngineTimingLegacy.hist.clear();
- mTimeStats.refreshRateStatsLegacy.clear();
+ mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
+ mTimeStats.statsEnd = 0;
+ mTimeStats.totalFrames = 0;
+ mTimeStats.missedFrames = 0;
+ mTimeStats.clientCompositionFrames = 0;
+ mTimeStats.clientCompositionReusedFrames = 0;
+ mTimeStats.refreshRateSwitches = 0;
+ mTimeStats.compositionStrategyChanges = 0;
+ mTimeStats.displayEventConnectionsCount = 0;
+ mTimeStats.displayOnTime = 0;
+ mTimeStats.presentToPresent.hist.clear();
+ mTimeStats.frameDuration.hist.clear();
+ mTimeStats.renderEngineTiming.hist.clear();
+ mTimeStats.refreshRateStats.clear();
mPowerTime.prevTime = systemTime();
- for (auto& globalRecord : mTimeStats.stats) {
- globalRecord.second.clearGlobals();
- }
mGlobalRecord.prevPresentTime = 0;
mGlobalRecord.presentFences.clear();
ALOGD("Cleared global stats");
@@ -1083,10 +871,7 @@ void TimeStats::clearLayersLocked() {
ATRACE_CALL();
mTimeStatsTracker.clear();
-
- for (auto& globalRecord : mTimeStats.stats) {
- globalRecord.second.stats.clear();
- }
+ mTimeStats.stats.clear();
ALOGD("Cleared layer stats");
}
@@ -1098,11 +883,11 @@ void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, std::strin
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- if (mTimeStats.statsStartLegacy == 0) {
+ if (mTimeStats.statsStart == 0) {
return;
}
- mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
flushPowerTimeLocked();
@@ -1120,3 +905,6 @@ void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, std::strin
} // namespace impl
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"