Refactor: Pull tracing out of TimeStats.
The tracing in TimeStats ended up having no actual overlap with current
TimeStats functionality. This CL pulls all tracing related code out
into its own class.
Test: atest libsurfaceflinger_unittest and manually inspected traces.
Run trace with:
{ adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/trace <<EOF
buffers: {
size_kb: 1280
}
data_sources: {
config {
name: "android.surfaceflinger.frame"
}
}
duration_ms: 3000
EOF
} && adb pull /data/misc/perfetto-traces/trace ~/Desktop/trace
Fixes: 140298240
Change-Id: I52d80d46eb8dee8979b02416ab7a758b7e58dfd1
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 438f8f3..51bf78a 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -139,6 +139,7 @@
"DisplayHardware/VirtualDisplaySurface.cpp",
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
+ "FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
"Layer.cpp",
"LayerProtoHelper.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index a8bdb79..90a02b3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -51,6 +51,7 @@
#include "Colorizer.h"
#include "DisplayDevice.h"
+#include "FrameTracer/FrameTracer.h"
#include "LayerRejecter.h"
#include "TimeStats/TimeStats.h"
@@ -71,7 +72,9 @@
BufferLayer::~BufferLayer() {
mFlinger->deleteTextureAsync(mTextureName);
- mFlinger->mTimeStats->onDestroy(getSequence());
+ const int32_t layerID = getSequence();
+ mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
void BufferLayer::useSurfaceDamage() {
@@ -314,17 +317,17 @@
if (presentFence->isValid()) {
mFlinger->mTimeStats->setPresentFence(layerID, mCurrentFrameNumber, presentFence);
- mFlinger->mTimeStats->traceFence(layerID, getCurrentBufferId(), mCurrentFrameNumber,
- presentFence, TimeStats::FrameEvent::PRESENT_FENCE);
+ mFlinger->mFrameTracer->traceFence(layerID, getCurrentBufferId(), mCurrentFrameNumber,
+ presentFence, FrameTracer::FrameEvent::PRESENT_FENCE);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
} else if (displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId);
mFlinger->mTimeStats->setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
- mFlinger->mTimeStats->traceTimestamp(layerID, getCurrentBufferId(), mCurrentFrameNumber,
- actualPresentTime,
- TimeStats::FrameEvent::PRESENT_FENCE);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, getCurrentBufferId(), mCurrentFrameNumber,
+ actualPresentTime,
+ FrameTracer::FrameEvent::PRESENT_FENCE);
mFrameTracker.setActualPresentTime(actualPresentTime);
}
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 6cad3c7..4da39e4 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -29,6 +29,7 @@
#include "LayerRejecter.h"
#include "SurfaceInterceptor.h"
+#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -48,9 +49,9 @@
// Prevent tracing the same release multiple times.
if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
- mFlinger->mTimeStats->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
- std::make_shared<FenceTime>(releaseFence),
- TimeStats::FrameEvent::RELEASE_FENCE);
+ mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
+ std::make_shared<FenceTime>(releaseFence),
+ FrameTracer::FrameEvent::RELEASE_FENCE);
mPreviousReleasedFrameNumber = mPreviousFrameNumber;
}
}
@@ -337,6 +338,7 @@
mQueueItems.clear();
mQueuedFrames = 0;
mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
// Once we have hit this state, the shadow queue may no longer
@@ -366,12 +368,12 @@
uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId();
mFlinger->mTimeStats->setAcquireFence(layerID, currentFrameNumber,
mQueueItems[0].mFenceTime);
- mFlinger->mTimeStats->traceFence(layerID, bufferID, currentFrameNumber,
- mQueueItems[0].mFenceTime,
- TimeStats::FrameEvent::ACQUIRE_FENCE);
+ mFlinger->mFrameTracer->traceFence(layerID, bufferID, currentFrameNumber,
+ mQueueItems[0].mFenceTime,
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
mFlinger->mTimeStats->setLatchTime(layerID, currentFrameNumber, latchTime);
- mFlinger->mTimeStats->traceTimestamp(layerID, bufferID, currentFrameNumber, latchTime,
- TimeStats::FrameEvent::LATCH);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, currentFrameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
mQueueItems.removeAt(0);
}
@@ -429,9 +431,9 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
const int32_t layerID = getSequence();
- mFlinger->mTimeStats->traceNewLayer(layerID, getName().c_str());
- mFlinger->mTimeStats->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber,
- systemTime(), TimeStats::FrameEvent::POST);
+ mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber,
+ systemTime(), FrameTracer::FrameEvent::POST);
ATRACE_CALL();
// Add this buffer from our internal queue tracker
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4a8261d..e7d1b63 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -32,6 +32,7 @@
#include "BufferStateLayer.h"
#include "ColorLayer.h"
+#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -90,9 +91,9 @@
// Prevent tracing the same release multiple times.
if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
- mFlinger->mTimeStats->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
- std::make_shared<FenceTime>(releaseFence),
- TimeStats::FrameEvent::RELEASE_FENCE);
+ mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
+ std::make_shared<FenceTime>(releaseFence),
+ FrameTracer::FrameEvent::RELEASE_FENCE);
mPreviousReleasedFrameNumber = mPreviousFrameNumber;
}
}
@@ -236,9 +237,9 @@
const int32_t layerID = getSequence();
mFlinger->mTimeStats->setPostTime(layerID, mFrameNumber, getName().c_str(), postTime);
- mFlinger->mTimeStats->traceNewLayer(layerID, getName().c_str());
- mFlinger->mTimeStats->traceTimestamp(layerID, buffer->getId(), mFrameNumber, postTime,
- TimeStats::FrameEvent::POST);
+ mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerID, buffer->getId(), mFrameNumber, postTime,
+ FrameTracer::FrameEvent::POST);
mCurrentState.desiredPresentTime = desiredPresentTime;
if (mFlinger->mUseSmart90ForVideo) {
@@ -569,17 +570,18 @@
status_t err = bindTextureImage();
if (err != NO_ERROR) {
mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
return BAD_VALUE;
}
}
const uint64_t bufferID = getCurrentBufferId();
mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, getCurrentFenceTime());
- mFlinger->mTimeStats->traceFence(layerID, bufferID, mFrameNumber, getCurrentFenceTime(),
- TimeStats::FrameEvent::ACQUIRE_FENCE);
+ mFlinger->mFrameTracer->traceFence(layerID, bufferID, mFrameNumber, getCurrentFenceTime(),
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
mFlinger->mTimeStats->setLatchTime(layerID, mFrameNumber, latchTime);
- mFlinger->mTimeStats->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime,
- TimeStats::FrameEvent::LATCH);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
mCurrentStateModified = false;
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
new file mode 100644
index 0000000..7cbb8d8
--- /dev/null
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "FrameTracer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "FrameTracer.h"
+
+#include <android-base/stringprintf.h>
+
+#include <algorithm>
+
+PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::FrameTracer::FrameTracerDataSource);
+
+namespace android {
+
+void FrameTracer::initialize() {
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kSystemBackend;
+ perfetto::Tracing::Initialize(args);
+ registerDataSource();
+}
+
+void FrameTracer::registerDataSource() {
+ perfetto::DataSourceDescriptor dsd;
+ dsd.set_name(kFrameTracerDataSource);
+ FrameTracerDataSource::Register(dsd);
+}
+
+void FrameTracer::traceNewLayer(int32_t layerID, const std::string& layerName) {
+ FrameTracerDataSource::Trace([this, layerID, &layerName](FrameTracerDataSource::TraceContext) {
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ mTraceTracker[layerID].layerName = layerName;
+ }
+ });
+}
+
+void FrameTracer::traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ nsecs_t timestamp, FrameEvent::BufferEventType type,
+ nsecs_t duration) {
+ FrameTracerDataSource::Trace([this, layerID, bufferID, frameNumber, timestamp, type,
+ duration](FrameTracerDataSource::TraceContext ctx) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ return;
+ }
+
+ // Handle any pending fences for this buffer.
+ tracePendingFencesLocked(ctx, layerID, bufferID);
+
+ // Complete current trace.
+ traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
+ });
+}
+
+void FrameTracer::traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& fence,
+ FrameEvent::BufferEventType type, nsecs_t startTime) {
+ FrameTracerDataSource::Trace([this, layerID, bufferID, frameNumber, &fence, type,
+ startTime](FrameTracerDataSource::TraceContext ctx) {
+ const nsecs_t signalTime = fence->getSignalTime();
+ if (signalTime != Fence::SIGNAL_TIME_INVALID) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ return;
+ }
+
+ // Handle any pending fences for this buffer.
+ tracePendingFencesLocked(ctx, layerID, bufferID);
+
+ if (signalTime != Fence::SIGNAL_TIME_PENDING) {
+ traceSpanLocked(ctx, layerID, bufferID, frameNumber, type, startTime, signalTime);
+ } else {
+ mTraceTracker[layerID].pendingFences[bufferID].push_back(
+ {.frameNumber = frameNumber,
+ .type = type,
+ .fence = fence,
+ .startTime = startTime});
+ }
+ }
+ });
+}
+
+void FrameTracer::tracePendingFencesLocked(FrameTracerDataSource::TraceContext& ctx,
+ int32_t layerID, uint64_t bufferID) {
+ if (mTraceTracker[layerID].pendingFences.count(bufferID)) {
+ auto& pendingFences = mTraceTracker[layerID].pendingFences[bufferID];
+ for (size_t i = 0; i < pendingFences.size(); ++i) {
+ auto& pendingFence = pendingFences[i];
+
+ nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
+ if (pendingFence.fence && pendingFence.fence->isValid()) {
+ signalTime = pendingFence.fence->getSignalTime();
+ if (signalTime == Fence::SIGNAL_TIME_PENDING) {
+ continue;
+ }
+ }
+
+ if (signalTime != Fence::SIGNAL_TIME_INVALID &&
+ systemTime() - signalTime < kFenceSignallingDeadline) {
+ traceSpanLocked(ctx, layerID, bufferID, pendingFence.frameNumber, pendingFence.type,
+ pendingFence.startTime, signalTime);
+ }
+
+ pendingFences.erase(pendingFences.begin() + i);
+ --i;
+ }
+ }
+}
+
+void FrameTracer::traceLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
+ FrameEvent::BufferEventType type, nsecs_t duration) {
+ auto packet = ctx.NewTracePacket();
+ packet->set_timestamp(timestamp);
+ auto* event = packet->set_graphics_frame_event()->set_buffer_event();
+ event->set_buffer_id(static_cast<uint32_t>(bufferID));
+ event->set_frame_number(frameNumber);
+ event->set_type(type);
+
+ if (mTraceTracker.find(layerID) != mTraceTracker.end() &&
+ !mTraceTracker[layerID].layerName.empty()) {
+ const std::string& layerName = mTraceTracker[layerID].layerName;
+ event->set_layer_name(layerName.c_str(), layerName.size());
+ }
+
+ if (duration > 0) {
+ event->set_duration_ns(duration);
+ }
+}
+
+void FrameTracer::traceSpanLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber,
+ FrameEvent::BufferEventType type, nsecs_t startTime,
+ nsecs_t endTime) {
+ nsecs_t timestamp = endTime;
+ nsecs_t duration = 0;
+ if (startTime > 0 && startTime < endTime) {
+ timestamp = startTime;
+ duration = endTime - startTime;
+ }
+ traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
+}
+
+void FrameTracer::onDestroy(int32_t layerID) {
+ std::lock_guard<std::mutex> traceLock(mTraceMutex);
+ mTraceTracker.erase(layerID);
+}
+
+std::string FrameTracer::miniDump() {
+ std::string result = "FrameTracer miniDump:\n";
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ android::base::StringAppendF(&result, "Number of layers currently being traced is %zu\n",
+ mTraceTracker.size());
+ return result;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.h b/services/surfaceflinger/FrameTracer/FrameTracer.h
new file mode 100644
index 0000000..d34ad81
--- /dev/null
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <perfetto/trace/android/graphics_frame_event.pbzero.h>
+#include <perfetto/tracing.h>
+#include <ui/FenceTime.h>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace android {
+
+class FrameTracer {
+public:
+ class FrameTracerDataSource : public perfetto::DataSource<FrameTracerDataSource> {
+ virtual void OnSetup(const SetupArgs&) override{};
+ virtual void OnStart(const StartArgs&) override{};
+ virtual void OnStop(const StopArgs&) override{};
+ };
+
+ using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent;
+
+ ~FrameTracer() = default;
+
+ // Sets up the perfetto tracing backend and data source.
+ void initialize();
+ // Registers the data source with the perfetto backend. Called as part of initialize()
+ // and should not be called manually outside of tests. Public to allow for substituting a
+ // perfetto::kInProcessBackend in tests.
+ void registerDataSource();
+ // Starts tracking a new layer for tracing. Needs to be called once before traceTimestamp() or
+ // traceFence() for each layer.
+ void traceNewLayer(int32_t layerID, const std::string& layerName);
+ // Creates a trace point at the timestamp provided.
+ void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
+ FrameEvent::BufferEventType type, nsecs_t duration = 0);
+ // Creates a trace point after the provided fence has been signalled. If a startTime is provided
+ // the trace will have be timestamped from startTime until fence signalling time. If no
+ // startTime is provided, a durationless trace point will be created timestamped at fence
+ // signalling time. If the fence hasn't signalled yet, the trace point will be created the next
+ // time after signalling a trace call for this buffer occurs.
+ void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& fence, FrameEvent::BufferEventType type,
+ nsecs_t startTime = 0);
+
+ // Takes care of cleanup when a layer is destroyed.
+ void onDestroy(int32_t layerID);
+
+ std::string miniDump();
+
+ static constexpr char kFrameTracerDataSource[] = "android.surfaceflinger.frame";
+
+ // The maximum amount of time a fence has to signal before it is discarded.
+ // Used to avoid fences from previous traces generating new trace points in later ones.
+ // Public for testing.
+ static constexpr nsecs_t kFenceSignallingDeadline = 60'000'000'000; // 60 seconds
+
+private:
+ struct PendingFence {
+ uint64_t frameNumber;
+ FrameEvent::BufferEventType type;
+ std::shared_ptr<FenceTime> fence;
+ nsecs_t startTime;
+ };
+
+ struct TraceRecord {
+ std::string layerName;
+ using BufferID = uint64_t;
+ std::unordered_map<BufferID, std::vector<PendingFence>> pendingFences;
+ };
+
+ // Checks if any pending fences for a layer and buffer have signalled and, if they have, creates
+ // trace points for them.
+ void tracePendingFencesLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID);
+ // Creates a trace point by translating a start time and an end time to a timestamp and
+ // duration. If startTime is later than end time it sets end time as the timestamp and the
+ // duration to 0. Used by traceFence().
+ void traceSpanLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber, FrameEvent::BufferEventType type,
+ nsecs_t startTime, nsecs_t endTime);
+ void traceLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID,
+ uint64_t frameNumber, nsecs_t timestamp, FrameEvent::BufferEventType type,
+ nsecs_t duration = 0);
+
+ std::mutex mTraceMutex;
+ std::unordered_map<int32_t, TraceRecord> mTraceTracker;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5121835..106d505 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -57,6 +57,7 @@
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
+#include "FrameTracer/FrameTracer.h"
#include "LayerProtoHelper.h"
#include "LayerRejecter.h"
#include "MonitoredProducer.h"
@@ -1343,7 +1344,9 @@
void Layer::onDisconnect() {
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.onDisconnect();
- mFlinger->mTimeStats->onDestroy(getSequence());
+ const int32_t layerID = getSequence();
+ mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6543089..e8902b3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -98,6 +98,7 @@
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "Effects/Daltonizer.h"
+#include "FrameTracer/FrameTracer.h"
#include "RegionSamplingThread.h"
#include "Scheduler/DispSync.h"
#include "Scheduler/DispSyncSource.h"
@@ -257,6 +258,7 @@
: mFactory(factory),
mInterceptor(mFactory.createSurfaceInterceptor(this)),
mTimeStats(mFactory.createTimeStats()),
+ mFrameTracer(std::make_unique<FrameTracer>()),
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
mPhaseOffsets(mFactory.createPhaseOffsets()) {}
@@ -513,7 +515,7 @@
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
- mTimeStats->initializeTracing();
+ mFrameTracer->initialize();
// wait patiently for the window manager death
const String16 name("window");
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8408ef5..c7cc07e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -94,6 +94,7 @@
class RefreshRateOverlay;
class RegionSamplingThread;
class TimeStats;
+class FrameTracer;
namespace compositionengine {
class DisplaySurface;
@@ -996,6 +997,7 @@
bool mTracingEnabled = false;
bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false;
const std::shared_ptr<TimeStats> mTimeStats;
+ const std::unique_ptr<FrameTracer> mFrameTracer;
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount = 0;
std::atomic<uint32_t> mHwcFrameMissedCount = 0;
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 9e1d503..2080a38 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -2,12 +2,9 @@
name: "libtimestats",
defaults: ["surfaceflinger_defaults"],
srcs: [
- "TimeStats.cpp"
+ "TimeStats.cpp",
],
export_include_dirs: ["."],
- static_libs: [
- "libperfetto_client_experimental",
- ],
shared_libs: [
"libtimestats_proto",
"libui",
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index b66e4cf..b01fa81 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -30,141 +30,10 @@
#include <algorithm>
#include <regex>
-PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::impl::TimeStats::TimeStatsDataSource);
-
namespace android {
namespace impl {
-void TimeStats::initializeTracing() {
- perfetto::TracingInitArgs args;
- args.backends = perfetto::kSystemBackend;
- perfetto::Tracing::Initialize(args);
- registerTracingDataSource();
-}
-
-void TimeStats::registerTracingDataSource() {
- perfetto::DataSourceDescriptor dsd;
- dsd.set_name(kTimeStatsDataSource);
- TimeStatsDataSource::Register(dsd);
-}
-
-void TimeStats::traceNewLayer(int32_t layerID, const std::string& layerName) {
- TimeStatsDataSource::Trace([this, layerID, &layerName](TimeStatsDataSource::TraceContext) {
- if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
- std::lock_guard<std::mutex> lock(mTraceMutex);
- mTraceTracker[layerID].layerName = layerName;
- }
- });
-}
-
-void TimeStats::traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- nsecs_t timestamp, FrameEvent::BufferEventType type,
- nsecs_t duration) {
- TimeStatsDataSource::Trace([this, layerID, bufferID, frameNumber, timestamp, type,
- duration](TimeStatsDataSource::TraceContext ctx) {
- std::lock_guard<std::mutex> lock(mTraceMutex);
- if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
- return;
- }
-
- // Handle any pending fences for this buffer.
- tracePendingFencesLocked(ctx, layerID, bufferID);
-
- // Complete current trace.
- traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
- });
-}
-
-void TimeStats::traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& fence,
- FrameEvent::BufferEventType type, nsecs_t startTime) {
- TimeStatsDataSource::Trace([this, layerID, bufferID, frameNumber, &fence, type,
- startTime](TimeStatsDataSource::TraceContext ctx) {
- const nsecs_t signalTime = fence->getSignalTime();
- if (signalTime != Fence::SIGNAL_TIME_INVALID) {
- std::lock_guard<std::mutex> lock(mTraceMutex);
- if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
- return;
- }
-
- // Handle any pending fences for this buffer.
- tracePendingFencesLocked(ctx, layerID, bufferID);
-
- if (signalTime != Fence::SIGNAL_TIME_PENDING) {
- traceSpanLocked(ctx, layerID, bufferID, frameNumber, type, startTime, signalTime);
- } else {
- mTraceTracker[layerID].pendingFences[bufferID].push_back(
- {.frameNumber = frameNumber,
- .type = type,
- .fence = fence,
- .startTime = startTime});
- }
- }
- });
-}
-
-void TimeStats::tracePendingFencesLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID) {
- if (mTraceTracker[layerID].pendingFences.count(bufferID)) {
- auto& pendingFences = mTraceTracker[layerID].pendingFences[bufferID];
- for (size_t i = 0; i < pendingFences.size(); ++i) {
- auto& pendingFence = pendingFences[i];
-
- nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
- if (pendingFence.fence && pendingFence.fence->isValid()) {
- signalTime = pendingFence.fence->getSignalTime();
- if (signalTime == Fence::SIGNAL_TIME_PENDING) {
- continue;
- }
- }
-
- if (signalTime != Fence::SIGNAL_TIME_INVALID &&
- systemTime() - signalTime < kFenceSignallingDeadline) {
- traceSpanLocked(ctx, layerID, bufferID, pendingFence.frameNumber, pendingFence.type,
- pendingFence.startTime, signalTime);
- }
-
- pendingFences.erase(pendingFences.begin() + i);
- --i;
- }
- }
-}
-
-void TimeStats::traceLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
- FrameEvent::BufferEventType type, nsecs_t duration) {
- auto packet = ctx.NewTracePacket();
- packet->set_timestamp(timestamp);
- auto* event = packet->set_graphics_frame_event()->set_buffer_event();
- event->set_buffer_id(static_cast<uint32_t>(bufferID));
- event->set_frame_number(frameNumber);
- event->set_type(type);
-
- if (mTraceTracker.find(layerID) != mTraceTracker.end() &&
- !mTraceTracker[layerID].layerName.empty()) {
- const std::string& layerName = mTraceTracker[layerID].layerName;
- event->set_layer_name(layerName.c_str(), layerName.size());
- }
-
- if (duration > 0) {
- event->set_duration_ns(duration);
- }
-}
-
-void TimeStats::traceSpanLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID, uint64_t frameNumber,
- FrameEvent::BufferEventType type, nsecs_t startTime,
- nsecs_t endTime) {
- nsecs_t timestamp = endTime;
- nsecs_t duration = 0;
- if (startTime > 0 && startTime < endTime) {
- timestamp = startTime;
- duration = endTime - startTime;
- }
- traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
-}
-
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
ATRACE_CALL();
@@ -207,8 +76,6 @@
mTimeStatsTracker.size());
android::base::StringAppendF(&result, "Number of layers in the stats pool is %zu\n",
mTimeStats.stats.size());
- android::base::StringAppendF(&result, "Number of layers currently being traced is %zu\n",
- mTraceTracker.size());
return result;
}
@@ -542,15 +409,8 @@
void TimeStats::onDestroy(int32_t layerID) {
ATRACE_CALL();
ALOGV("[%d]-onDestroy", layerID);
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStatsTracker.erase(layerID);
- }
-
- {
- std::lock_guard<std::mutex> traceLock(mTraceMutex);
- mTraceTracker.erase(layerID);
- }
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTimeStatsTracker.erase(layerID);
}
void TimeStats::removeTimeRecord(int32_t layerID, uint64_t frameNumber) {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 470137a..9ebc1ad 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -17,8 +17,6 @@
#pragma once
#include <hardware/hwcomposer_defs.h>
-#include <perfetto/trace/android/graphics_frame_event.pbzero.h>
-#include <perfetto/tracing.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
#include <ui/FenceTime.h>
@@ -36,32 +34,8 @@
class TimeStats {
public:
- using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent;
-
virtual ~TimeStats() = default;
- // Sets up the perfetto tracing backend and data source.
- virtual void initializeTracing() = 0;
- // Registers the data source with the perfetto backend. Called as part of initializeTracing()
- // and should not be called manually outside of tests. Public to allow for substituting a
- // perfetto::kInProcessBackend in tests.
- virtual void registerTracingDataSource() = 0;
- // Starts tracking a new layer for tracing. Needs to be called once before traceTimestamp() or
- // traceFence() for each layer.
- virtual void traceNewLayer(int32_t layerID, const std::string& layerName) = 0;
- // Creates a trace point at the timestamp provided.
- virtual void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- nsecs_t timestamp, FrameEvent::BufferEventType type,
- nsecs_t duration = 0) = 0;
- // Creates a trace point after the provided fence has been signalled. If a startTime is provided
- // the trace will have be timestamped from startTime until fence signalling time. If no
- // startTime is provided, a durationless trace point will be created timestamped at fence
- // signalling time. If the fence hasn't signalled yet, the trace point will be created the next
- // time after signalling a trace call for this buffer occurs.
- virtual void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& fence,
- FrameEvent::BufferEventType type, nsecs_t startTime = 0) = 0;
-
virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
virtual bool isEnabled() = 0;
virtual std::string miniDump() = 0;
@@ -89,13 +63,6 @@
// Source of truth is RefrehRateStats.
virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
-
- static constexpr char kTimeStatsDataSource[] = "android.surfaceflinger.timestats";
-
- // The maximum amount of time a fence has to signal before it is discarded.
- // Used to avoid fence's from previous traces generating new trace points in later ones.
- // Public for testing.
- static constexpr nsecs_t kFenceSignallingDeadline = 60'000'000'000; // 60 seconds
};
namespace impl {
@@ -117,13 +84,6 @@
std::shared_ptr<FenceTime> presentFence;
};
- struct PendingFence {
- uint64_t frameNumber;
- FrameEvent::BufferEventType type;
- std::shared_ptr<FenceTime> fence;
- nsecs_t startTime;
- };
-
struct LayerRecord {
std::string layerName;
// This is the index in timeRecords, at which the timestamps for that
@@ -135,12 +95,6 @@
std::deque<TimeRecord> timeRecords;
};
- struct TraceRecord {
- std::string layerName;
- using BufferID = uint64_t;
- std::unordered_map<BufferID, std::vector<PendingFence>> pendingFences;
- };
-
struct PowerTime {
int32_t powerMode = HWC_POWER_MODE_OFF;
nsecs_t prevTime = 0;
@@ -152,23 +106,8 @@
};
public:
- class TimeStatsDataSource : public perfetto::DataSource<TimeStatsDataSource> {
- virtual void OnSetup(const SetupArgs&) override{};
- virtual void OnStart(const StartArgs&) override { ALOGV("TimeStats trace started"); };
- virtual void OnStop(const StopArgs&) override { ALOGV("TimeStats trace stopped"); };
- };
-
TimeStats() = default;
- void initializeTracing() override;
- void registerTracingDataSource() override;
- void traceNewLayer(int32_t layerID, const std::string& layerName) override;
- void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
- FrameEvent::BufferEventType type, nsecs_t duration = 0) override;
- void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& fence, FrameEvent::BufferEventType type,
- nsecs_t startTime = 0) override;
-
void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
bool isEnabled() override;
std::string miniDump() override;
@@ -200,20 +139,6 @@
static const size_t MAX_NUM_TIME_RECORDS = 64;
private:
- // Checks if any pending fences for a layer and buffer have signalled and, if they have, creates
- // trace points for them.
- void tracePendingFencesLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID);
- // Creates a trace point by translating a start time and an end time to a timestamp and
- // duration. If startTime is later than end time it sets end time as the timestamp and the
- // duration to 0. Used by traceFence().
- void traceSpanLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID,
- uint64_t frameNumber, FrameEvent::BufferEventType type, nsecs_t startTime,
- nsecs_t endTime);
- void traceLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID,
- uint64_t frameNumber, nsecs_t timestamp, FrameEvent::BufferEventType type,
- nsecs_t duration = 0);
-
bool recordReadyLocked(int32_t layerID, TimeRecord* timeRecord);
void flushAvailableRecordsToStatsLocked(int32_t layerID);
void flushPowerTimeLocked();
@@ -232,9 +157,6 @@
PowerTime mPowerTime;
GlobalRecord mGlobalRecord;
- std::mutex mTraceMutex;
- std::unordered_map<int32_t, TraceRecord> mTraceTracker;
-
static const size_t MAX_NUM_LAYER_RECORDS = 200;
static const size_t MAX_NUM_LAYER_STATS = 200;
};
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 0eedf9b..8d98af6 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -51,6 +51,7 @@
"RefreshRateStatsTest.cpp",
"RegionSamplingTest.cpp",
"TimeStatsTest.cpp",
+ "FrameTracerTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockDisplay.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
@@ -63,6 +64,7 @@
"mock/MockNativeWindowSurface.cpp",
"mock/MockSurfaceInterceptor.cpp",
"mock/MockTimeStats.cpp",
+ "mock/MockFrameTracer.cpp",
"mock/system/window/MockNativeWindow.cpp",
],
static_libs: [
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
new file mode 100644
index 0000000..b5af591
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <FrameTracer/FrameTracer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <perfetto/trace/trace.pb.h>
+
+#include "libsurfaceflinger_unittest_main.h"
+
+using namespace google::protobuf;
+
+namespace android {
+namespace {
+
+class FrameTracerTest : public testing::Test {
+public:
+ FrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ // Need to initialize tracing in process for testing, and only once per test suite.
+ static bool wasInitialized = false;
+ if (!wasInitialized) {
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kInProcessBackend;
+ perfetto::Tracing::Initialize(args);
+ wasInitialized = true;
+ }
+ }
+
+ ~FrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ void SetUp() override {
+ mFrameTracer = std::make_unique<FrameTracer>();
+ mFrameTracer->registerDataSource();
+ }
+
+ void TearDown() override { mFrameTracer.reset(); }
+
+ // Each tracing session can be used for a single block of Start -> Stop.
+ static std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest() {
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name(FrameTracer::kFrameTracerDataSource);
+
+ auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+ tracingSession->Setup(cfg);
+ return tracingSession;
+ }
+
+ std::unique_ptr<FrameTracer> mFrameTracer;
+ FenceToFenceTimeMap fenceFactory;
+};
+
+TEST_F(FrameTracerTest, traceNewLayerStartsTrackingLayerWhenTracing) {
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ tracingSession->StopBlocking();
+}
+
+TEST_F(FrameTracerTest, onDestroyRemovesTheTrackedLayer) {
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const int32_t secondLayerID = 6;
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceNewLayer(secondLayerID, layerName);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 2\n");
+ tracingSession->StopBlocking();
+
+ mFrameTracer->onDestroy(layerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ mFrameTracer->onDestroy(layerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ mFrameTracer->onDestroy(secondLayerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+}
+
+TEST_F(FrameTracerTest, canTraceAfterAddingLayer) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 1;
+ const uint32_t bufferID = 2;
+ const uint64_t frameNumber = 3;
+ const nsecs_t timestamp = 4;
+ const nsecs_t duration = 5;
+ const auto type = FrameTracer::FrameEvent::POST;
+
+ {
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+
+ mFrameTracer->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
+ // Create second trace packet to finalize the previous one.
+ mFrameTracer->traceTimestamp(layerID, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+ }
+
+ {
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
+ // Create second trace packet to finalize the previous one.
+ mFrameTracer->traceTimestamp(layerID, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 1);
+
+ const auto& packet = trace.packet().Get(0);
+ ASSERT_TRUE(packet.has_timestamp());
+ EXPECT_EQ(packet.timestamp(), timestamp);
+ ASSERT_TRUE(packet.has_graphics_frame_event());
+ const auto& frame_event = packet.graphics_frame_event();
+ ASSERT_TRUE(frame_event.has_buffer_event());
+ const auto& buffer_event = frame_event.buffer_event();
+ ASSERT_TRUE(buffer_event.has_buffer_id());
+ EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+ ASSERT_TRUE(buffer_event.has_frame_number());
+ EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+ ASSERT_TRUE(buffer_event.has_type());
+ EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+ ASSERT_TRUE(buffer_event.has_duration_ns());
+ EXPECT_EQ(buffer_event.duration_ns(), duration);
+ }
+}
+
+TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+ {
+ auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING);
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ // Trace.
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
+ // Create extra trace packet to (hopefully not) trigger and finalize the fence packet.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+ }
+
+ {
+ auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
+ const nsecs_t timestamp = systemTime();
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp);
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above.
+
+ const auto& packet = trace.packet().Get(1);
+ ASSERT_TRUE(packet.has_timestamp());
+ EXPECT_EQ(packet.timestamp(), timestamp);
+ ASSERT_TRUE(packet.has_graphics_frame_event());
+ const auto& frame_event = packet.graphics_frame_event();
+ ASSERT_TRUE(frame_event.has_buffer_event());
+ const auto& buffer_event = frame_event.buffer_event();
+ ASSERT_TRUE(buffer_event.has_buffer_id());
+ EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+ ASSERT_TRUE(buffer_event.has_frame_number());
+ EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+ ASSERT_TRUE(buffer_event.has_type());
+ EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+ EXPECT_FALSE(buffer_event.has_duration_ns());
+ }
+}
+
+TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ // traceFence called after fence signalled.
+ const nsecs_t signalTime1 = systemTime();
+ const nsecs_t startTime1 = signalTime1 + 100000;
+ auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
+
+ // traceFence called before fence signalled.
+ const nsecs_t signalTime2 = systemTime();
+ const nsecs_t startTime2 = signalTime2 + 100000;
+ auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2);
+
+ const auto& packet1 = trace.packet().Get(0);
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), signalTime1);
+ ASSERT_TRUE(packet1.has_graphics_frame_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+ ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+
+ const auto& packet2 = trace.packet().Get(1);
+ ASSERT_TRUE(packet2.has_timestamp());
+ EXPECT_EQ(packet2.timestamp(), signalTime2);
+ ASSERT_TRUE(packet2.has_graphics_frame_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+ ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+}
+
+TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+ const nsecs_t signalTime = systemTime() - FrameTracer::kFenceSignallingDeadline;
+
+ auto tracingSession = getTracingSessionForTest();
+ auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence, type);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime);
+ // Create extra trace packet to trigger and finalize any previous fence packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+}
+
+TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+ const nsecs_t duration = 1234;
+
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ // traceFence called after fence signalled.
+ const nsecs_t signalTime1 = systemTime();
+ const nsecs_t startTime1 = signalTime1 - duration;
+ auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
+
+ // traceFence called before fence signalled.
+ const nsecs_t signalTime2 = systemTime();
+ const nsecs_t startTime2 = signalTime2 - duration;
+ auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2);
+
+ const auto& packet1 = trace.packet().Get(0);
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), startTime1);
+ ASSERT_TRUE(packet1.has_graphics_frame_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+ const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
+ EXPECT_EQ(buffer_event1.duration_ns(), duration);
+
+ const auto& packet2 = trace.packet().Get(1);
+ ASSERT_TRUE(packet2.has_timestamp());
+ EXPECT_EQ(packet2.timestamp(), startTime2);
+ ASSERT_TRUE(packet2.has_graphics_frame_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+ const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
+ EXPECT_EQ(buffer_event2.duration_ns(), duration);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index f01e603..ffacbfe 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -20,8 +20,8 @@
#include <TimeStats/TimeStats.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+
#include <log/log.h>
-#include <perfetto/trace/trace.pb.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -109,15 +109,6 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
-
- // Need to initialize tracing in process for testing, and only once per test suite.
- static bool wasInitialized = false;
- if (!wasInitialized) {
- perfetto::TracingInitArgs args;
- args.backends = perfetto::kInProcessBackend;
- perfetto::Tracing::Initialize(args);
- wasInitialized = true;
- }
}
~TimeStatsTest() {
@@ -126,13 +117,6 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
- void SetUp() override {
- mTimeStats = std::make_unique<impl::TimeStats>();
- mTimeStats->registerTracingDataSource();
- }
-
- void TearDown() override { mTimeStats.reset(); }
-
std::string inputCommand(InputCommand cmd, bool useProto);
void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts);
@@ -147,22 +131,8 @@
}
}
- // Each tracing session can be used for a single block of Start -> Stop.
- static std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest() {
- perfetto::TraceConfig cfg;
- cfg.set_duration_ms(500);
- cfg.add_buffers()->set_size_kb(1024);
- auto* ds_cfg = cfg.add_data_sources()->mutable_config();
- ds_cfg->set_name(TimeStats::kTimeStatsDataSource);
-
- auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
- tracingSession->Setup(cfg);
- return tracingSession;
- }
-
std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
- std::unique_ptr<TimeStats> mTimeStats;
- FenceToFenceTimeMap fenceFactory;
+ std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
};
std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -239,330 +209,6 @@
return distr(mRandomEngine);
}
-TEST_F(TimeStatsTest, traceNewLayerStartsTrackingLayerWhenTracing) {
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- mTimeStats->traceNewLayer(layerID, layerName);
-
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
- mTimeStats->traceNewLayer(layerID, layerName);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n");
- tracingSession->StopBlocking();
-}
-
-TEST_F(TimeStatsTest, onDestroyRemovesTheTrackedLayer) {
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const int32_t secondLayerID = 6;
-
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceNewLayer(secondLayerID, layerName);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 2\n");
- tracingSession->StopBlocking();
-
- mTimeStats->onDestroy(layerID);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n");
- mTimeStats->onDestroy(layerID);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n");
- mTimeStats->onDestroy(secondLayerID);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-}
-
-TEST_F(TimeStatsTest, canTraceAfterAddingLayer) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 1;
- const uint32_t bufferID = 2;
- const uint64_t frameNumber = 3;
- const nsecs_t timestamp = 4;
- const nsecs_t duration = 5;
- const auto type = TimeStats::FrameEvent::POST;
-
- {
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
-
- mTimeStats->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
- // Create second trace packet to finalize the previous one.
- mTimeStats->traceTimestamp(layerID, 0, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- EXPECT_EQ(raw_trace.size(), 0);
- }
-
- {
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
-
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
- // Create second trace packet to finalize the previous one.
- mTimeStats->traceTimestamp(layerID, 0, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 1);
-
- const auto& packet = trace.packet().Get(0);
- ASSERT_TRUE(packet.has_timestamp());
- EXPECT_EQ(packet.timestamp(), timestamp);
- ASSERT_TRUE(packet.has_graphics_frame_event());
- const auto& frame_event = packet.graphics_frame_event();
- ASSERT_TRUE(frame_event.has_buffer_event());
- const auto& buffer_event = frame_event.buffer_event();
- ASSERT_TRUE(buffer_event.has_buffer_id());
- EXPECT_EQ(buffer_event.buffer_id(), bufferID);
- ASSERT_TRUE(buffer_event.has_frame_number());
- EXPECT_EQ(buffer_event.frame_number(), frameNumber);
- ASSERT_TRUE(buffer_event.has_type());
- EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
- ASSERT_TRUE(buffer_event.has_duration_ns());
- EXPECT_EQ(buffer_event.duration_ns(), duration);
- }
-}
-
-TEST_F(TimeStatsTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
-
- {
- auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING);
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- // Trace.
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
- // Create extra trace packet to (hopefully not) trigger and finalize the fence packet.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- EXPECT_EQ(raw_trace.size(), 0);
- }
-
- {
- auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
- const nsecs_t timestamp = systemTime();
- fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp);
- // Create extra trace packet to trigger and finalize fence trace packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above.
-
- const auto& packet = trace.packet().Get(1);
- ASSERT_TRUE(packet.has_timestamp());
- EXPECT_EQ(packet.timestamp(), timestamp);
- ASSERT_TRUE(packet.has_graphics_frame_event());
- const auto& frame_event = packet.graphics_frame_event();
- ASSERT_TRUE(frame_event.has_buffer_event());
- const auto& buffer_event = frame_event.buffer_event();
- ASSERT_TRUE(buffer_event.has_buffer_id());
- EXPECT_EQ(buffer_event.buffer_id(), bufferID);
- ASSERT_TRUE(buffer_event.has_frame_number());
- EXPECT_EQ(buffer_event.frame_number(), frameNumber);
- ASSERT_TRUE(buffer_event.has_type());
- EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
- EXPECT_FALSE(buffer_event.has_duration_ns());
- }
-}
-
-TEST_F(TimeStatsTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
-
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
-
- // traceFence called after fence signalled.
- const nsecs_t signalTime1 = systemTime();
- const nsecs_t startTime1 = signalTime1 + 100000;
- auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
-
- // traceFence called before fence signalled.
- const nsecs_t signalTime2 = systemTime();
- const nsecs_t startTime2 = signalTime2 + 100000;
- auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
-
- // Create extra trace packet to trigger and finalize fence trace packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 2);
-
- const auto& packet1 = trace.packet().Get(0);
- ASSERT_TRUE(packet1.has_timestamp());
- EXPECT_EQ(packet1.timestamp(), signalTime1);
- ASSERT_TRUE(packet1.has_graphics_frame_event());
- ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
- ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
-
- const auto& packet2 = trace.packet().Get(1);
- ASSERT_TRUE(packet2.has_timestamp());
- EXPECT_EQ(packet2.timestamp(), signalTime2);
- ASSERT_TRUE(packet2.has_graphics_frame_event());
- ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
- ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
-}
-
-TEST_F(TimeStatsTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
- const nsecs_t signalTime = systemTime() - TimeStats::kFenceSignallingDeadline;
-
- auto tracingSession = getTracingSessionForTest();
- auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence, type);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime);
- // Create extra trace packet to trigger and finalize any previous fence packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- EXPECT_EQ(raw_trace.size(), 0);
-}
-
-TEST_F(TimeStatsTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
- const nsecs_t duration = 1234;
-
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
-
- // traceFence called after fence signalled.
- const nsecs_t signalTime1 = systemTime();
- const nsecs_t startTime1 = signalTime1 - duration;
- auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
-
- // traceFence called before fence signalled.
- const nsecs_t signalTime2 = systemTime();
- const nsecs_t startTime2 = signalTime2 - duration;
- auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
-
- // Create extra trace packet to trigger and finalize fence trace packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 2);
-
- const auto& packet1 = trace.packet().Get(0);
- ASSERT_TRUE(packet1.has_timestamp());
- EXPECT_EQ(packet1.timestamp(), startTime1);
- ASSERT_TRUE(packet1.has_graphics_frame_event());
- ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
- ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
- const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
- EXPECT_EQ(buffer_event1.duration_ns(), duration);
-
- const auto& packet2 = trace.packet().Get(1);
- ASSERT_TRUE(packet2.has_timestamp());
- EXPECT_EQ(packet2.timestamp(), startTime2);
- ASSERT_TRUE(packet2.has_graphics_frame_event());
- ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
- ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
- const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
- EXPECT_EQ(buffer_event2.duration_ns(), duration);
-}
-
TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_TRUE(mTimeStats->isEnabled());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
new file mode 100644
index 0000000..358dfdb
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mock/MockFrameTracer.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+FrameTracer::FrameTracer() = default;
+FrameTracer::~FrameTracer() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
new file mode 100644
index 0000000..f768b81
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "FrameTracer/FrameTracer.h"
+
+namespace android {
+namespace mock {
+
+class FrameTracer : public android::FrameTracer {
+public:
+ FrameTracer();
+ ~FrameTracer();
+
+ MOCK_METHOD0(initialize, void());
+ MOCK_METHOD0(registerDataSource, void());
+ MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&));
+ MOCK_METHOD6(traceTimestamp,
+ void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t));
+ MOCK_METHOD6(traceFence,
+ void(int32_t, uint64_t, uint64_t, const std::shared_ptr<FenceTime>&,
+ FrameEvent::BufferEventType, nsecs_t));
+ MOCK_METHOD0(miniDump, std::string());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 542c70a..b1634a8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -28,14 +28,6 @@
TimeStats();
~TimeStats() override;
- MOCK_METHOD0(initializeTracing, void());
- MOCK_METHOD0(registerTracingDataSource, void());
- MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&));
- MOCK_METHOD6(traceTimestamp,
- void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t));
- MOCK_METHOD6(traceFence,
- void(int32_t, uint64_t, uint64_t, const std::shared_ptr<FenceTime>&,
- FrameEvent::BufferEventType, nsecs_t));
MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
MOCK_METHOD0(isEnabled, bool());
MOCK_METHOD0(miniDump, std::string());