History

drm/xe: Correlate engine and cpu timestamps with better accuracy

Perf measurements rely on CPU and engine timestamps to correlate events of interest across these time domains. Current mechanisms get these timestamps separately and the calculated delta between these timestamps lack enough accuracy. To improve the accuracy of these time measurements to within a few us, add a query that returns the engine and cpu timestamps captured as close to each other as possible. Mesa MR: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24591 v2: - Fix kernel-doc warnings (CI) - Document input params and group them together (Jose) - s/cs/engine/ (Jose) - Remove padding in the query (Ashutosh)

Umesh Nerlige Ramappa committed 3 years ago

Commit 7793d001 parent 61d63a52 files · +218 −24Browse files

Unified · Split

2 files
  1. drivers/gpu/drm/xe/xe_query.c +138 −0
  2. include/uapi/drm/xe_drm.h +80 −24
drivers/gpu/drm/xe/xe_query.c+138−0
@@ -6,10 +6,12 @@ · 5 unmodified lines
6#include "xe_query.h"6#include "xe_query.h"
7 7
8#include <linux/nospec.h>8#include <linux/nospec.h>
9#include <linux/sched/clock.h>
9 10
10#include <drm/ttm/ttm_placement.h>11#include <drm/ttm/ttm_placement.h>
11#include <drm/xe_drm.h>12#include <drm/xe_drm.h>
12 13
14#include "regs/xe_engine_regs.h"
13#include "xe_bo.h"15#include "xe_bo.h"
14#include "xe_device.h"16#include "xe_device.h"
15#include "xe_exec_queue.h"17#include "xe_exec_queue.h"
@@ -17,6 +19,7 @@ · 1 unmodified line
17#include "xe_gt.h"19#include "xe_gt.h"
18#include "xe_guc_hwconfig.h"20#include "xe_guc_hwconfig.h"
19#include "xe_macros.h"21#include "xe_macros.h"
22#include "xe_mmio.h"
20#include "xe_ttm_vram_mgr.h"23#include "xe_ttm_vram_mgr.h"
21 24
22static const u16 xe_to_user_engine_class[] = {25static const u16 xe_to_user_engine_class[] = {
@@ -27,6 +30,14 @@ static const u16 xe_to_user_engine_class[] = { · 4 unmodified lines
27 [XE_ENGINE_CLASS_COMPUTE] = DRM_XE_ENGINE_CLASS_COMPUTE,30 [XE_ENGINE_CLASS_COMPUTE] = DRM_XE_ENGINE_CLASS_COMPUTE,
28};31};
29 32
33static const enum xe_engine_class user_to_xe_engine_class[] = {
34 [DRM_XE_ENGINE_CLASS_RENDER] = XE_ENGINE_CLASS_RENDER,
35 [DRM_XE_ENGINE_CLASS_COPY] = XE_ENGINE_CLASS_COPY,
36 [DRM_XE_ENGINE_CLASS_VIDEO_DECODE] = XE_ENGINE_CLASS_VIDEO_DECODE,
37 [DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE] = XE_ENGINE_CLASS_VIDEO_ENHANCE,
38 [DRM_XE_ENGINE_CLASS_COMPUTE] = XE_ENGINE_CLASS_COMPUTE,
39};
40
30static size_t calc_hw_engine_info_size(struct xe_device *xe)41static size_t calc_hw_engine_info_size(struct xe_device *xe)
31{42{
32 struct xe_hw_engine *hwe;43 struct xe_hw_engine *hwe;
@@ -45,6 +56,132 @@ static size_t calc_hw_engine_info_size(struct xe_device *xe) · 12 unmodified lines
45 return i * sizeof(struct drm_xe_engine_class_instance);56 return i * sizeof(struct drm_xe_engine_class_instance);
46}57}
47 58
59typedef u64 (*__ktime_func_t)(void);
60static __ktime_func_t __clock_id_to_func(clockid_t clk_id)
61{
62 /*
63 * Use logic same as the perf subsystem to allow user to select the
64 * reference clock id to be used for timestamps.
65 */
66 switch (clk_id) {
67 case CLOCK_MONOTONIC:
68 return &ktime_get_ns;
69 case CLOCK_MONOTONIC_RAW:
70 return &ktime_get_raw_ns;
71 case CLOCK_REALTIME:
72 return &ktime_get_real_ns;
73 case CLOCK_BOOTTIME:
74 return &ktime_get_boottime_ns;
75 case CLOCK_TAI:
76 return &ktime_get_clocktai_ns;
77 default:
78 return NULL;
79 }
80}
81
82static void
83__read_timestamps(struct xe_gt *gt,
84 struct xe_reg lower_reg,
85 struct xe_reg upper_reg,
86 u64 *engine_ts,
87 u64 *cpu_ts,
88 u64 *cpu_delta,
89 __ktime_func_t cpu_clock)
90{
91 u32 upper, lower, old_upper, loop = 0;
92
93 upper = xe_mmio_read32(gt, upper_reg);
94 do {
95 *cpu_delta = local_clock();
96 *cpu_ts = cpu_clock();
97 lower = xe_mmio_read32(gt, lower_reg);
98 *cpu_delta = local_clock() - *cpu_delta;
99 old_upper = upper;
100 upper = xe_mmio_read32(gt, upper_reg);
101 } while (upper != old_upper && loop++ < 2);
102
103 *engine_ts = (u64)upper << 32 | lower;
104}
105
106static int
107query_engine_cycles(struct xe_device *xe,
108 struct drm_xe_device_query *query)
109{
110 struct drm_xe_query_engine_cycles __user *query_ptr;
111 struct drm_xe_engine_class_instance *eci;
112 struct drm_xe_query_engine_cycles resp;
113 size_t size = sizeof(resp);
114 __ktime_func_t cpu_clock;
115 struct xe_hw_engine *hwe;
116 struct xe_gt *gt;
117
118 if (query->size == 0) {
119 query->size = size;
120 return 0;
121 } else if (XE_IOCTL_DBG(xe, query->size != size)) {
122 return -EINVAL;
123 }
124
125 query_ptr = u64_to_user_ptr(query->data);
126 if (copy_from_user(&resp, query_ptr, size))
127 return -EFAULT;
128
129 cpu_clock = __clock_id_to_func(resp.clockid);
130 if (!cpu_clock)
131 return -EINVAL;
132
133 eci = &resp.eci;
134 if (eci->gt_id > XE_MAX_GT_PER_TILE)
135 return -EINVAL;
136
137 gt = xe_device_get_gt(xe, eci->gt_id);
138 if (!gt)
139 return -EINVAL;
140
141 if (eci->engine_class >= ARRAY_SIZE(user_to_xe_engine_class))
142 return -EINVAL;
143
144 hwe = xe_gt_hw_engine(gt, user_to_xe_engine_class[eci->engine_class],
145 eci->engine_instance, true);
146 if (!hwe)
147 return -EINVAL;
148
149 resp.engine_frequency = gt->info.clock_freq;
150
151 xe_device_mem_access_get(xe);
152 xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
153
154 __read_timestamps(gt,
155 RING_TIMESTAMP(hwe->mmio_base),
156 RING_TIMESTAMP_UDW(hwe->mmio_base),
157 &resp.engine_cycles,
158 &resp.cpu_timestamp,
159 &resp.cpu_delta,
160 cpu_clock);
161
162 xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
163 xe_device_mem_access_put(xe);
164 resp.width = 36;
165
166 /* Only write to the output fields of user query */
167 if (put_user(resp.engine_frequency, &query_ptr->engine_frequency))
168 return -EFAULT;
169
170 if (put_user(resp.cpu_timestamp, &query_ptr->cpu_timestamp))
171 return -EFAULT;
172
173 if (put_user(resp.cpu_delta, &query_ptr->cpu_delta))
174 return -EFAULT;
175
176 if (put_user(resp.engine_cycles, &query_ptr->engine_cycles))
177 return -EFAULT;
178
179 if (put_user(resp.width, &query_ptr->width))
180 return -EFAULT;
181
182 return 0;
183}
184
48static int query_engines(struct xe_device *xe,185static int query_engines(struct xe_device *xe,
49 struct drm_xe_device_query *query)186 struct drm_xe_device_query *query)
50{187{
@@ -369,6 +506,7 @@ static int (* const xe_query_funcs[])(struct xe_device *xe, · 318 unmodified lines
369 query_gts,506 query_gts,
370 query_hwconfig,507 query_hwconfig,
371 query_gt_topology,508 query_gt_topology,
509 query_engine_cycles,
372};510};
373 511
374int xe_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file)512int xe_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
include/uapi/drm/xe_drm.h+80−24
@@ -128,6 +128,25 @@ struct xe_user_extension { · 127 unmodified lines
128#define DRM_IOCTL_XE_WAIT_USER_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_WAIT_USER_FENCE, struct drm_xe_wait_user_fence)128#define DRM_IOCTL_XE_WAIT_USER_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_WAIT_USER_FENCE, struct drm_xe_wait_user_fence)
129#define DRM_IOCTL_XE_VM_MADVISE DRM_IOW(DRM_COMMAND_BASE + DRM_XE_VM_MADVISE, struct drm_xe_vm_madvise)129#define DRM_IOCTL_XE_VM_MADVISE DRM_IOW(DRM_COMMAND_BASE + DRM_XE_VM_MADVISE, struct drm_xe_vm_madvise)
130 130
131/** struct drm_xe_engine_class_instance - instance of an engine class */
132struct drm_xe_engine_class_instance {
133#define DRM_XE_ENGINE_CLASS_RENDER 0
134#define DRM_XE_ENGINE_CLASS_COPY 1
135#define DRM_XE_ENGINE_CLASS_VIDEO_DECODE 2
136#define DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE 3
137#define DRM_XE_ENGINE_CLASS_COMPUTE 4
138 /*
139 * Kernel only class (not actual hardware engine class). Used for
140 * creating ordered queues of VM bind operations.
141 */
142#define DRM_XE_ENGINE_CLASS_VM_BIND 5
143 __u16 engine_class;
144
145 __u16 engine_instance;
146 __u16 gt_id;
147 __u16 rsvd;
148};
149
131/**150/**
132 * enum drm_xe_memory_class - Supported memory classes.151 * enum drm_xe_memory_class - Supported memory classes.
133 */152 */
@@ -219,6 +238,60 @@ struct drm_xe_query_mem_region { · 85 unmodified lines
219 __u64 reserved[6];238 __u64 reserved[6];
220};239};
221 240
241/**
242 * struct drm_xe_query_engine_cycles - correlate CPU and GPU timestamps
243 *
244 * If a query is made with a struct drm_xe_device_query where .query is equal to
245 * DRM_XE_DEVICE_QUERY_ENGINE_CYCLES, then the reply uses struct drm_xe_query_engine_cycles
246 * in .data. struct drm_xe_query_engine_cycles is allocated by the user and
247 * .data points to this allocated structure.
248 *
249 * The query returns the engine cycles and the frequency that can
250 * be used to calculate the engine timestamp. In addition the
251 * query returns a set of cpu timestamps that indicate when the command
252 * streamer cycle count was captured.
253 */
254struct drm_xe_query_engine_cycles {
255 /**
256 * @eci: This is input by the user and is the engine for which command
257 * streamer cycles is queried.
258 */
259 struct drm_xe_engine_class_instance eci;
260
261 /**
262 * @clockid: This is input by the user and is the reference clock id for
263 * CPU timestamp. For definition, see clock_gettime(2) and
264 * perf_event_open(2). Supported clock ids are CLOCK_MONOTONIC,
265 * CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME, CLOCK_TAI.
266 */
267 __s32 clockid;
268
269 /** @width: Width of the engine cycle counter in bits. */
270 __u32 width;
271
272 /**
273 * @engine_cycles: Engine cycles as read from its register
274 * at 0x358 offset.
275 */
276 __u64 engine_cycles;
277
278 /** @engine_frequency: Frequency of the engine cycles in Hz. */
279 __u64 engine_frequency;
280
281 /**
282 * @cpu_timestamp: CPU timestamp in ns. The timestamp is captured before
283 * reading the engine_cycles register using the reference clockid set by the
284 * user.
285 */
286 __u64 cpu_timestamp;
287
288 /**
289 * @cpu_delta: Time delta in ns captured around reading the lower dword
290 * of the engine_cycles register.
291 */
292 __u64 cpu_delta;
293};
294
222/**295/**
223 * struct drm_xe_query_mem_usage - describe memory regions and usage296 * struct drm_xe_query_mem_usage - describe memory regions and usage
224 *297 *
@@ -385,12 +458,13 @@ struct drm_xe_device_query { · 160 unmodified lines
385 /** @extensions: Pointer to the first extension struct, if any */458 /** @extensions: Pointer to the first extension struct, if any */
386 __u64 extensions;459 __u64 extensions;
387 460
388#define DRM_XE_DEVICE_QUERY_ENGINES 0461#define DRM_XE_DEVICE_QUERY_ENGINES 0
389#define DRM_XE_DEVICE_QUERY_MEM_USAGE 1462#define DRM_XE_DEVICE_QUERY_MEM_USAGE 1
390#define DRM_XE_DEVICE_QUERY_CONFIG 2463#define DRM_XE_DEVICE_QUERY_CONFIG 2
391#define DRM_XE_DEVICE_QUERY_GTS 3464#define DRM_XE_DEVICE_QUERY_GTS 3
392#define DRM_XE_DEVICE_QUERY_HWCONFIG 4465#define DRM_XE_DEVICE_QUERY_HWCONFIG 4
393#define DRM_XE_DEVICE_QUERY_GT_TOPOLOGY 5466#define DRM_XE_DEVICE_QUERY_GT_TOPOLOGY 5
467#define DRM_XE_DEVICE_QUERY_ENGINE_CYCLES 6
394 /** @query: The type of data to query */468 /** @query: The type of data to query */
395 __u32 query;469 __u32 query;
396 470
@@ -732,24 +806,6 @@ struct drm_xe_exec_queue_set_property { · 335 unmodified lines
732 __u64 reserved[2];806 __u64 reserved[2];
733};807};
734 808
735/** struct drm_xe_engine_class_instance - instance of an engine class */
736struct drm_xe_engine_class_instance {
737#define DRM_XE_ENGINE_CLASS_RENDER 0
738#define DRM_XE_ENGINE_CLASS_COPY 1
739#define DRM_XE_ENGINE_CLASS_VIDEO_DECODE 2
740#define DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE 3
741#define DRM_XE_ENGINE_CLASS_COMPUTE 4
742 /*
743 * Kernel only class (not actual hardware engine class). Used for
744 * creating ordered queues of VM bind operations.
745 */
746#define DRM_XE_ENGINE_CLASS_VM_BIND 5
747 __u16 engine_class;
748
749 __u16 engine_instance;
750 __u16 gt_id;
751};
752
753struct drm_xe_exec_queue_create {809struct drm_xe_exec_queue_create {
754#define XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY 0810#define XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY 0
755 /** @extensions: Pointer to the first extension struct, if any */811 /** @extensions: Pointer to the first extension struct, if any */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t