-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] GPUTracer for Metal. #46846
Changes from 7 commits
cf77065
78a4d15
e3ae43d
d7186e7
172a87b
bd37576
8e1c67b
0b46742
3caf282
0d3b630
0d1da88
076eeb7
212fe99
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <Metal/Metal.h> | ||
|
|
||
| #include <memory> | ||
| #include <optional> | ||
| #include "impeller/base/thread.h" | ||
| #include "impeller/base/thread_safety.h" | ||
| #include "impeller/geometry/scalar.h" | ||
|
|
||
| namespace impeller { | ||
|
|
||
| class ContextMTL; | ||
|
|
||
| /// @brief Approximate the GPU frame time by computing a difference between the | ||
| /// smallest | ||
| /// GPUStartTime and largest GPUEndTime for all cmd buffers submitted in | ||
| /// a frame workload. | ||
| class GPUTracerMTL : public std::enable_shared_from_this<GPUTracerMTL> { | ||
| public: | ||
| GPUTracerMTL() = default; | ||
|
|
||
| ~GPUTracerMTL() = default; | ||
|
|
||
| /// @brief Record that the current frame has ended. Any additional cmd buffers | ||
| /// will be | ||
| /// attributed to the "next" frame. | ||
| void MarkFrameEnd(); | ||
|
|
||
| /// @brief Record the current cmd buffer GPU execution timestamps into an | ||
| /// aggregate | ||
| /// frame workload metric. | ||
| void RecordCmdBuffer(id<MTLCommandBuffer> buffer); | ||
|
|
||
| private: | ||
| struct GPUTraceState { | ||
| Scalar smallest_timestamp = std::numeric_limits<float>::max(); | ||
| Scalar largest_timestamp = 0; | ||
| size_t pending_buffers = 0; | ||
| }; | ||
|
|
||
| [[maybe_unused]] mutable Mutex trace_state_mutex_; | ||
| [[maybe_unused]] GPUTraceState trace_states_[16] IPLR_GUARDED_BY( | ||
| trace_state_mutex_); | ||
| [[maybe_unused]] size_t current_state_ IPLR_GUARDED_BY(trace_state_mutex_) = | ||
| 0u; | ||
| }; | ||
|
|
||
| } // namespace impeller |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| #include <Metal/Metal.h> | ||
| #include "fml/trace_event.h" | ||
| #include "impeller/renderer/backend/metal/context_mtl.h" | ||
| #include "impeller/renderer/backend/metal/formats_mtl.h" | ||
|
|
||
| #include <memory> | ||
|
|
||
| #include "impeller/renderer/backend/metal/gpu_tracer_mtl.h" | ||
|
|
||
| namespace impeller { | ||
|
|
||
| void GPUTracerMTL::MarkFrameEnd() { | ||
| #ifdef IMPELLER_DEBUG | ||
| if (@available(ios 10.3, tvos 10.2, macos 10.15, macCatalyst 13.0, *)) { | ||
| Lock lock(trace_state_mutex_); | ||
| current_state_ = (current_state_ + 1) % 16; | ||
| } | ||
| #endif // IMPELLER_DEBUG | ||
| } | ||
|
|
||
| void GPUTracerMTL::RecordCmdBuffer(id<MTLCommandBuffer> buffer) { | ||
| #ifdef IMPELLER_DEBUG | ||
| if (@available(ios 10.3, tvos 10.2, macos 10.15, macCatalyst 13.0, *)) { | ||
| Lock lock(trace_state_mutex_); | ||
| auto current_state = current_state_; | ||
| trace_states_[current_state].pending_buffers += 1; | ||
|
|
||
| auto weak_self = weak_from_this(); | ||
| [buffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this has some issues with GPUTracerMTL being deleted (or retained), but I'm not quite sure how to solve that with object-c / c++ interop.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed, thanks @gaaclarke ! |
||
| auto self = weak_self.lock(); | ||
| if (!self) { | ||
| return; | ||
| } | ||
| Lock lock(self->trace_state_mutex_); | ||
| auto& state = self->trace_states_[current_state]; | ||
| state.pending_buffers--; | ||
| state.smallest_timestamp = std::min( | ||
| state.smallest_timestamp, static_cast<Scalar>(buffer.GPUStartTime)); | ||
| state.largest_timestamp = std::max( | ||
| state.largest_timestamp, static_cast<Scalar>(buffer.GPUEndTime)); | ||
|
|
||
| if (state.pending_buffers == 0) { | ||
| auto gpu_ms = | ||
| (state.largest_timestamp - state.smallest_timestamp) * 1000; | ||
| state.smallest_timestamp = std::numeric_limits<float>::max(); | ||
| state.largest_timestamp = 0; | ||
| FML_TRACE_COUNTER("flutter", "GPUTracer", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like it should be a constant somewhere so that MTL and VK use the same one always
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where would you want this? I can put it in core?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Im gonna punt on this - the trace event will probably change a few times |
||
| reinterpret_cast<int64_t>(this), // Trace Counter ID | ||
| "FrameTimeMS", gpu_ms); | ||
| } | ||
| }]; | ||
| } | ||
| #endif // IMPELLER_DEBUG | ||
| } | ||
|
|
||
| } // namespace impeller | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit - rather than guarding each method, just don't even allocate this outside of debug?