xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/radeonsi/si_perfetto.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2023 Advanced Micro Devices, Inc.
3  *
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #ifndef SI_PERFETTO_H
8 #define SI_PERFETTO_H
9 
10 #include <stdint.h>
11 
12 #include "util/macros.h"
13 #include "util/perf/u_trace.h"
14 #include "util/u_vector.h"
15 
16 #include "amd/common/ac_gpu_info.h"
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 /* Perfetto collects TracePackets from the application and/or drivers. It is the root object of a
23  * Perfetto trace. A Perfetto trace is a linear sequence of TracePackets.
24  * TracePackets contains timestamp and timestamp_clock_id along with lots of other data
25  * like gpu_counter_event and gpu_render_stage_event.
26  * gpu_render_stage_event contains data such as event_id, duration, gpu_id, stage_iid, context etc.
27  * So a render stage can be named as "draw" which will collect start timestamp and end timestamp
28  * along with other payload data of each draw call from OpenGL
29  */
30 
31 enum amd_ds_api {
32    AMD_DS_API_OPENGL,
33    AMD_DS_API_VULKAN,
34 };
35 
36 enum si_ds_queue_stage {
37    SI_DS_QUEUE_STAGE_QUEUE,
38    SI_DS_QUEUE_STAGE_COMPUTE,
39    SI_DS_QUEUE_STAGE_DRAW,
40    SI_DS_QUEUE_STAGE_N_STAGES,
41 };
42 
43 struct si_ds_device {
44    const struct radeon_info *info;
45 
46    /* API of this device */
47    enum amd_ds_api api;
48 
49    /* GPU identifier domain:bus:device:func:pci_id */
50    uint32_t gpu_id;
51 
52    /* Clock identifier for this device. */
53    uint32_t gpu_clock_id;
54 
55    /* The timestamp at the point where we first emitted the clock_sync..
56     * this  will be a *later* timestamp that the first GPU traces (since
57     * we capture the first clock_sync from the CPU *after* the first GPU
58     * tracepoints happen).  To avoid confusing perfetto we need to drop
59     * the GPU traces with timestamps before this.
60     */
61    uint64_t sync_gpu_ts;
62 
63    /* Next timestamp after which we should resend a clock correlation. */
64    uint64_t next_clock_sync_ns;
65 
66    /* Unique perfetto identifier for the context */
67    uint64_t iid;
68 
69    /* Event ID generator (manipulate only inside
70     * SIRenderpassDataSource::Trace)
71     */
72    uint64_t event_id;
73 
74    struct u_trace_context trace_context;
75 
76    /* List of si_ds_queue */
77    struct list_head queues;
78 };
79 
80 struct si_ds_stage {
81    /* Unique hw_queue IID */
82    uint64_t queue_iid;
83 
84    /* Unique stage IID */
85    uint64_t stage_iid;
86 
87    /* Start timestamp of the last work element. We have a array indexed by
88     * level so that we can track multi levels of events (like
89     * primary/secondary command buffers).
90     */
91    uint64_t start_ns[5];
92 
93    /* Current number of valid elements in start_ns */
94    uint32_t level;
95 };
96 
97 struct si_ds_queue {
98    struct list_head link;
99 
100    /* Device this queue belongs to */
101    struct si_ds_device *device;
102 
103    /* Unique name of the queue */
104    char name[80];
105 
106    /* Counter incremented on each si_ds_end_submit() call */
107    uint64_t submission_id;
108 
109    struct si_ds_stage stages[SI_DS_QUEUE_STAGE_N_STAGES];
110 };
111 
112 struct si_ds_flush_data {
113    struct si_ds_queue *queue;
114 
115    /* u_trace element in which we copy other traces in case we deal with
116     * reusable command buffers.
117     */
118    struct u_trace trace;
119 
120    /* Unique submission ID associated with the trace */
121    uint64_t submission_id;
122 };
123 
124 void si_driver_ds_init(void);
125 
126 void si_ds_device_init(struct si_ds_device *device, const struct radeon_info *devinfo,
127                        uint32_t gpu_id, enum amd_ds_api api);
128 void si_ds_device_fini(struct si_ds_device *device);
129 
130 struct si_ds_queue *si_ds_device_init_queue(struct si_ds_device *device, struct si_ds_queue *queue,
131                                             const char *fmt_name, ...);
132 
133 void si_ds_flush_data_init(struct si_ds_flush_data *data, struct si_ds_queue *queue,
134                            uint64_t submission_id);
135 
136 void si_ds_flush_data_fini(struct si_ds_flush_data *data);
137 
138 #ifdef HAVE_PERFETTO
139 uint64_t si_ds_begin_submit(struct si_ds_queue *queue);
140 void si_ds_end_submit(struct si_ds_queue *queue,
141                          uint64_t start_ts);
142 
143 #else
si_ds_begin_submit(struct si_ds_queue * queue)144 static inline uint64_t si_ds_begin_submit(struct si_ds_queue *queue)
145 {
146    return 0;
147 }
148 
si_ds_end_submit(struct si_ds_queue * queue,uint64_t start_ts)149 static inline void si_ds_end_submit(struct si_ds_queue *queue, uint64_t start_ts)
150 {
151 }
152 
153 #endif /* HAVE_PERFETTO */
154 
155 #ifdef __cplusplus
156 }
157 #endif
158 
159 #endif /* SI_PERFETTO_H */
160