| /* |
| * 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. |
| */ |
| |
| // 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 "FrameTracer" |
| #define ATRACE_TAG ATRACE_TAG_GRAPHICS |
| |
| #include "FrameTracer.h" |
| |
| #include <android-base/stringprintf.h> |
| #include <perfetto/common/builtin_clock.pbzero.h> |
| |
| #include <algorithm> |
| #include <mutex> |
| |
| PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::FrameTracer::FrameTracerDataSource); |
| |
| namespace android { |
| |
| void FrameTracer::initialize() { |
| std::call_once(mInitializationFlag, [this]() { |
| 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_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); |
| packet->set_timestamp(timestamp); |
| auto* event = packet->set_graphics_frame_event()->set_buffer_event(); |
| event->set_buffer_id(static_cast<uint32_t>(bufferID)); |
| if (frameNumber != UNSPECIFIED_FRAME_NUMBER) { |
| 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 |
| |
| // TODO(b/129481165): remove the #pragma below and fix conversion issues |
| #pragma clang diagnostic pop // ignored "-Wconversion" |