xref: /aosp_15_r20/external/mesa3d/src/util/perf/u_perfetto_renderpass.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2023 Google LLC
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "perfetto.h"
25 
26 #include "util/hash_table.h"
27 #include "util/perf/u_trace.h"
28 #include "util/ralloc.h"
29 
30 using perfetto::DataSource;
31 template <typename DataSourceType, typename DataSourceTraits>
32 class MesaRenderpassDataSource
33     : public perfetto::DataSource<DataSourceType, DataSourceTraits> {
34 
35  public:
36    typedef typename perfetto::DataSource<DataSourceType,
37                                          DataSourceTraits>::TraceContext
38       TraceContext;
39 
OnSetup(const perfetto::DataSourceBase::SetupArgs &)40    void OnSetup(const perfetto::DataSourceBase::SetupArgs &) override
41    {
42       // Use this callback to apply any custom configuration to your data
43       // source based on the TraceConfig in SetupArgs.
44       debug_markers = NULL;
45    }
46 
OnStart(const perfetto::DataSourceBase::StartArgs &)47    void OnStart(const perfetto::DataSourceBase::StartArgs &) override
48    {
49       debug_markers = _mesa_hash_table_create(NULL, _mesa_hash_string,
50                                               _mesa_key_string_equal);
51       // This notification can be used to initialize the GPU driver, enable
52       // counters, etc. StartArgs will contains the DataSourceDescriptor,
53       // which can be extended.
54       u_trace_perfetto_start();
55       PERFETTO_LOG("Tracing started");
56    }
57 
OnStop(const perfetto::DataSourceBase::StopArgs &)58    void OnStop(const perfetto::DataSourceBase::StopArgs &) override
59    {
60       PERFETTO_LOG("Tracing stopped");
61 
62       // Undo any initialization done in OnStart.
63       u_trace_perfetto_stop();
64       // TODO we should perhaps block until queued traces are flushed?
65 
66       static_cast<DataSourceType *>(this)->Trace([](auto ctx) {
67          auto packet = ctx.NewTracePacket();
68          packet->Finalize();
69          ctx.Flush();
70       });
71 
72       ralloc_free(debug_markers);
73    }
74 
75    /* Emits a clock sync trace event.  Perfetto uses periodic clock events
76     * like this to sync up our GPU render stages with the CPU on the same
77     * timeline, since clocks always drift over time.  Note that perfetto
78     * relies on gpu_ts being monotonic, and will perform badly if it goes
79     * backwards -- see tu_perfetto.cc for an example implemntation of handling
80     * going backwards.
81     */
EmitClockSync(TraceContext & ctx,uint64_t cpu_ts,uint64_t gpu_ts,uint32_t gpu_clock_id)82    static void EmitClockSync(TraceContext &ctx,
83                              uint64_t cpu_ts,
84                              uint64_t gpu_ts,
85                              uint32_t gpu_clock_id)
86    {
87       auto packet = ctx.NewTracePacket();
88 
89       packet->set_timestamp_clock_id(
90          perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
91       packet->set_timestamp(cpu_ts);
92 
93       auto event = packet->set_clock_snapshot();
94 
95       {
96          auto clock = event->add_clocks();
97 
98          clock->set_clock_id(
99             perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
100          clock->set_timestamp(cpu_ts);
101       }
102 
103       {
104          auto clock = event->add_clocks();
105 
106          clock->set_clock_id(gpu_clock_id);
107          clock->set_timestamp(gpu_ts);
108       }
109    }
110 
111    /* Returns a stage iid to use for a command stream or queue annotation.
112     *
113     * Using a new stage lets the annotation string show up right on the track
114     * event in the UI, rather than needing to click into the event to find the
115     * name in the metadata.  Intended for use with
116     * vkCmdBeginDebugUtilsLabelEXT() and glPushDebugGroup().
117     *
118     * Note that SEQ_INCREMENTAL_STATE_CLEARED must have been set in the
119     * sequence before this is called.
120     */
debug_marker_stage(TraceContext & ctx,const char * name)121    uint64_t debug_marker_stage(TraceContext &ctx, const char *name)
122    {
123       struct hash_entry *entry = _mesa_hash_table_search(debug_markers, name);
124       const uint64_t dynamic_iid_base = 1ull << 32;
125 
126       if (entry) {
127          return dynamic_iid_base + (uint32_t) (uintptr_t) entry->data;
128       } else {
129          uint64_t iid = dynamic_iid_base + debug_markers->entries;
130 
131          auto packet = ctx.NewTracePacket();
132          auto interned_data = packet->set_interned_data();
133 
134          auto desc = interned_data->add_gpu_specifications();
135          desc->set_iid(iid);
136          desc->set_name(name);
137 
138          /* We only track the entry count in entry->data, because the
139           * dynamic_iid_base would get lost on 32-bit builds.
140           */
141          _mesa_hash_table_insert(debug_markers,
142                                  ralloc_strdup(debug_markers, name),
143                                  (void *) (uintptr_t) debug_markers->entries);
144 
145          return iid;
146       }
147    }
148 
149  private:
150    /* Hash table of application generated events (string -> iid) (use
151     * tctx.GetDataSourceLocked()->debug_marker_stage() to get a stage iid)
152     */
153    struct hash_table *debug_markers;
154 };
155 
156 /* Begin the C API section. */
157