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