| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef LIB_ESCHER_PROFILING_TIMESTAMP_PROFILER_H_ |
| #define LIB_ESCHER_PROFILING_TIMESTAMP_PROFILER_H_ |
| |
| #include <vector> |
| |
| #include "lib/escher/forward_declarations.h" |
| #include "lib/escher/vk/vulkan_context.h" |
| #include "src/lib/fxl/memory/ref_counted.h" |
| |
| namespace escher { |
| |
| class TimestampProfiler : public fxl::RefCountedThreadSafe<TimestampProfiler> { |
| public: |
| TimestampProfiler(vk::Device device, float timestamp_period); |
| ~TimestampProfiler(); |
| |
| // Add a Vulkan timestamp-query that will mark the time that all previous |
| // commands in |cmd_buf| have finished the pipeline stage specified by |
| // |flags|. For example, use eVertexShader to mark the time that vertex |
| // shaders have been applied to all vertices from previous draw-calls. |
| // |
| // |name| needs to be a global constant. The trace engine that ultimately |
| // consumes Result structs caches it, so if the contents were overwritten the |
| // records would be inaccurate. |
| // |
| // NOTE: you should understand the caveats in the Vulkan spec regarding the |
| // accuracy of these timestamps. For example, many implementations will treat |
| // any set of flags as equivalent to eBottomOfPipe. |
| void AddTimestamp(impl::CommandBuffer* cmd_buf, |
| vk::PipelineStageFlagBits flags, const char* name); |
| |
| struct Result { |
| uint64_t raw_nanoseconds; // nanoseconds according to some timebase. |
| uint64_t time; // microseconds elapsed since the first timestamp. |
| uint64_t elapsed; // microseconds elapsed since the previous timestamp. |
| const char* name; |
| }; |
| |
| struct TraceEvent { |
| uint64_t start_ticks; // tick that the event(s) started |
| uint64_t end_ticks; // tick that the event(s) ended |
| std::vector<const char*> names; // all trace event names for the time range |
| }; |
| |
| // GetQueryResults() returns the raw events generated by a series of |
| // AddTimeStamp() calls. |
| std::vector<Result> GetQueryResults(); |
| |
| // Transforms a vector of Results into a vector of TraceEvents more suitable |
| // for the trace system to use. |
| // |
| // NOTE: Currently only supported on Fuchsia. |
| static std::vector<TraceEvent> ProcessTraceEvents( |
| const std::vector<Result>& timestamps); |
| |
| // Uses VTHREAD trace macros to register all GPU work represented in |
| // |trace_events|. |trace_events| should be returned from a call to |
| // ProcessTraceEvents() |trace_literal| is the name that the event will take |
| // and should be a string literal. |
| static void TraceGpuQueryResults(const std::vector<TraceEvent>& trace_events, |
| uint64_t frame_number, |
| uint64_t escher_frame_number, |
| const char* trace_literal, |
| const char* gpu_vthread_literal, |
| uint64_t gpu_vthread_id); |
| |
| static void LogGpuQueryResults(uint64_t escher_frame_number, |
| const std::vector<Result>& timestamps); |
| |
| private: |
| // Each QueryRange keeps track of current usage of a separate vk::QueryPool. |
| // A new pool (and hence a new QueryRange) is used whenever: |
| // - the capacity of the previous pool is reached. |
| // - a different CommandBuffer is passed to AddTimestamp(). |
| struct QueryRange { |
| vk::QueryPool pool; |
| vk::CommandBuffer command_buffer; |
| uint32_t start_index; // within the pool |
| uint32_t count; |
| }; |
| |
| QueryRange* ObtainRange(impl::CommandBuffer* cmd_buf); |
| QueryRange* CreateRange(impl::CommandBuffer* cmd_buf); |
| QueryRange* CreateRangeAndPool(impl::CommandBuffer* cmd_buf); |
| |
| std::vector<QueryRange> ranges_; |
| std::vector<vk::QueryPool> pools_; |
| |
| // Remembers timestamp names, and will eventually be filled in with timestamp |
| // values before returning results. |
| std::vector<Result> results_; |
| |
| uint32_t query_count_ = 0; |
| uint32_t current_pool_index_ = 0; |
| |
| const vk::Device device_; |
| const float timestamp_period_; |
| }; |
| |
| } // namespace escher |
| |
| #endif // LIB_ESCHER_PROFILING_TIMESTAMP_PROFILER_H_ |