xref: /aosp_15_r20/external/mesa3d/src/intel/perf/i915/intel_perf.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2024 Intel Corporation
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "perf/i915/intel_perf.h"
7 
8 #include <sys/stat.h>
9 
10 #include "common/intel_gem.h"
11 #include "common/i915/intel_gem.h"
12 #include "dev/intel_debug.h"
13 #include "dev/intel_device_info.h"
14 #include "intel_perf_common.h"
15 #include "perf/intel_perf.h"
16 #include "perf/intel_perf_private.h"
17 #include "util/compiler.h"
18 
19 #include "drm-uapi/i915_drm.h"
20 
21 #include "perf/intel_perf_private.h"
22 
23 #define FILE_DEBUG_FLAG DEBUG_PERFMON
24 
i915_perf_get_oa_format(struct intel_perf_config * perf)25 uint64_t i915_perf_get_oa_format(struct intel_perf_config *perf)
26 {
27    if (perf->devinfo->verx10 <= 75)
28       return I915_OA_FORMAT_A45_B8_C8;
29    else if (perf->devinfo->verx10 <= 120)
30       return I915_OA_FORMAT_A32u40_A4u32_B8_C8;
31    else
32       return I915_OA_FORMAT_A24u40_A14u32_B8_C8;
33 }
34 
35 int
i915_perf_stream_open(struct intel_perf_config * perf_config,int drm_fd,uint32_t ctx_id,uint64_t metrics_set_id,uint64_t report_format,uint64_t period_exponent,bool hold_preemption,bool enable)36 i915_perf_stream_open(struct intel_perf_config *perf_config, int drm_fd,
37                       uint32_t ctx_id, uint64_t metrics_set_id,
38                       uint64_t report_format, uint64_t period_exponent,
39                       bool hold_preemption, bool enable)
40 {
41    uint64_t properties[DRM_I915_PERF_PROP_MAX * 2];
42    uint32_t p = 0;
43 
44    /* Single context sampling if valid context id. */
45    if (ctx_id != INTEL_PERF_INVALID_CTX_ID) {
46       properties[p++] = DRM_I915_PERF_PROP_CTX_HANDLE;
47       properties[p++] = ctx_id;
48    }
49 
50    /* Include OA reports in samples */
51    properties[p++] = DRM_I915_PERF_PROP_SAMPLE_OA;
52    properties[p++] = true;
53 
54    /* OA unit configuration */
55    properties[p++] = DRM_I915_PERF_PROP_OA_METRICS_SET;
56    properties[p++] = metrics_set_id;
57 
58    properties[p++] = DRM_I915_PERF_PROP_OA_FORMAT;
59    properties[p++] = report_format;
60 
61    properties[p++] = DRM_I915_PERF_PROP_OA_EXPONENT;
62    properties[p++] = period_exponent;
63 
64    if (hold_preemption) {
65       properties[p++] = DRM_I915_PERF_PROP_HOLD_PREEMPTION;
66       properties[p++] = true;
67    }
68 
69    /* If global SSEU is available, pin it to the default. This will ensure on
70     * Gfx11 for instance we use the full EU array. Initially when perf was
71     * enabled we would use only half on Gfx11 because of functional
72     * requirements.
73     *
74     * Not supported on Gfx12.5+.
75     */
76    if (intel_perf_has_global_sseu(perf_config) &&
77        perf_config->devinfo->verx10 < 125) {
78       properties[p++] = DRM_I915_PERF_PROP_GLOBAL_SSEU;
79       properties[p++] = (uintptr_t) perf_config->sseu;
80    }
81 
82    assert(p <= ARRAY_SIZE(properties));
83 
84    struct drm_i915_perf_open_param param = {
85       .flags = I915_PERF_FLAG_FD_CLOEXEC |
86                I915_PERF_FLAG_FD_NONBLOCK |
87                (enable ? 0 : I915_PERF_FLAG_DISABLED),
88       .num_properties = p / 2,
89       .properties_ptr = (uintptr_t) properties,
90    };
91    int fd = intel_ioctl(drm_fd, DRM_IOCTL_I915_PERF_OPEN, &param);
92    return fd > -1 ? fd : 0;
93 }
94 
95 static bool
i915_query_perf_config_supported(struct intel_perf_config * perf,int fd)96 i915_query_perf_config_supported(struct intel_perf_config *perf, int fd)
97 {
98    int32_t length = 0;
99    return !intel_i915_query_flags(fd, DRM_I915_QUERY_PERF_CONFIG,
100                                   DRM_I915_QUERY_PERF_CONFIG_LIST,
101                                   NULL, &length);
102 }
103 
104 static bool
i915_query_perf_config_data(struct intel_perf_config * perf,int fd,const char * guid,struct drm_i915_perf_oa_config * config)105 i915_query_perf_config_data(struct intel_perf_config *perf,
106                             int fd, const char *guid,
107                             struct drm_i915_perf_oa_config *config)
108 {
109    char data[sizeof(struct drm_i915_query_perf_config) +
110              sizeof(struct drm_i915_perf_oa_config)] = {};
111    struct drm_i915_query_perf_config *i915_query = (void *)data;
112    struct drm_i915_perf_oa_config *i915_config = (void *)data + sizeof(*i915_query);
113 
114    memcpy(i915_query->uuid, guid, sizeof(i915_query->uuid));
115    memcpy(i915_config, config, sizeof(*config));
116 
117    int32_t item_length = sizeof(data);
118    if (intel_i915_query_flags(fd, DRM_I915_QUERY_PERF_CONFIG,
119                               DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID,
120                               i915_query, &item_length))
121       return false;
122 
123    memcpy(config, i915_config, sizeof(*config));
124 
125    return true;
126 }
127 
128 struct intel_perf_registers *
i915_perf_load_configurations(struct intel_perf_config * perf_cfg,int fd,const char * guid)129 i915_perf_load_configurations(struct intel_perf_config *perf_cfg, int fd, const char *guid)
130 {
131    struct drm_i915_perf_oa_config i915_config = { 0, };
132    if (!i915_query_perf_config_data(perf_cfg, fd, guid, &i915_config))
133       return NULL;
134 
135    struct intel_perf_registers *config = rzalloc(NULL, struct intel_perf_registers);
136    config->n_flex_regs = i915_config.n_flex_regs;
137    config->flex_regs = rzalloc_array(config, struct intel_perf_query_register_prog, config->n_flex_regs);
138    config->n_mux_regs = i915_config.n_mux_regs;
139    config->mux_regs = rzalloc_array(config, struct intel_perf_query_register_prog, config->n_mux_regs);
140    config->n_b_counter_regs = i915_config.n_boolean_regs;
141    config->b_counter_regs = rzalloc_array(config, struct intel_perf_query_register_prog, config->n_b_counter_regs);
142 
143    /*
144     * struct intel_perf_query_register_prog maps exactly to the tuple of
145     * (register offset, register value) returned by the i915.
146     */
147    i915_config.flex_regs_ptr = to_const_user_pointer(config->flex_regs);
148    i915_config.mux_regs_ptr = to_const_user_pointer(config->mux_regs);
149    i915_config.boolean_regs_ptr = to_const_user_pointer(config->b_counter_regs);
150    if (!i915_query_perf_config_data(perf_cfg, fd, guid, &i915_config)) {
151       ralloc_free(config);
152       return NULL;
153    }
154 
155    return config;
156 }
157 
158 static int
i915_perf_version(int drm_fd)159 i915_perf_version(int drm_fd)
160 {
161    int tmp = 0;
162    intel_gem_get_param(drm_fd, I915_PARAM_PERF_REVISION, &tmp);
163    return tmp;
164 }
165 
166 static void
i915_get_sseu(int drm_fd,struct drm_i915_gem_context_param_sseu * sseu)167 i915_get_sseu(int drm_fd, struct drm_i915_gem_context_param_sseu *sseu)
168 {
169    struct drm_i915_gem_context_param arg = {
170       .param = I915_CONTEXT_PARAM_SSEU,
171       .size = sizeof(*sseu),
172       .value = (uintptr_t) sseu
173    };
174 
175    intel_ioctl(drm_fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &arg);
176 }
177 
178 bool
i915_oa_metrics_available(struct intel_perf_config * perf,int fd,bool use_register_snapshots)179 i915_oa_metrics_available(struct intel_perf_config *perf, int fd, bool use_register_snapshots)
180 {
181    int version = i915_perf_version(fd);
182    bool i915_perf_oa_available = false;
183    struct stat sb;
184 
185    if (i915_query_perf_config_supported(perf, fd))
186       perf->features_supported |= INTEL_PERF_FEATURE_QUERY_PERF;
187 
188    if (version >= 4)
189       perf->features_supported |= INTEL_PERF_FEATURE_GLOBAL_SSEU;
190    if (version >= 3)
191       perf->features_supported |= INTEL_PERF_FEATURE_HOLD_PREEMPTION;
192 
193    /* Record the default SSEU configuration. */
194    perf->sseu = rzalloc(perf, struct drm_i915_gem_context_param_sseu);
195    if (!perf->sseu)
196       return false;
197 
198    i915_get_sseu(fd, perf->sseu);
199 
200    /* The existence of this sysctl parameter implies the kernel supports
201     * the i915 perf interface.
202     */
203    if (stat("/proc/sys/dev/i915/perf_stream_paranoid", &sb) == 0) {
204 
205       /* If _paranoid == 1 then on Gfx8+ we won't be able to access OA
206        * metrics unless running as root.
207        */
208       if (perf->devinfo->platform == INTEL_PLATFORM_HSW)
209          i915_perf_oa_available = true;
210       else {
211          uint64_t paranoid = 1;
212 
213          read_file_uint64("/proc/sys/dev/i915/perf_stream_paranoid", &paranoid);
214 
215          if (paranoid == 0 || geteuid() == 0)
216             i915_perf_oa_available = true;
217       }
218    }
219 
220    return i915_perf_oa_available;
221 }
222 
223 int
i915_perf_stream_read_samples(struct intel_perf_config * perf_config,int perf_stream_fd,uint8_t * buffer,size_t buffer_len)224 i915_perf_stream_read_samples(struct intel_perf_config *perf_config,
225                               int perf_stream_fd, uint8_t *buffer,
226                               size_t buffer_len)
227 {
228    const size_t sample_header_size = perf_config->oa_sample_size +
229                                      sizeof(struct intel_perf_record_header);
230    int len;
231 
232    if (buffer_len < sample_header_size)
233       return -ENOSPC;
234 
235    do {
236       len = read(perf_stream_fd, buffer, buffer_len);
237    } while (len < 0 && errno == EINTR);
238 
239    if (len <= 0)
240       return len < 0 ? -errno : 0;
241 
242    /* works as long drm_i915_perf_record_header and intel_perf_record_header
243     * definition matches
244     */
245    return len;
246 }
247 
248 uint64_t
i915_add_config(struct intel_perf_config * perf,int fd,const struct intel_perf_registers * config,const char * guid)249 i915_add_config(struct intel_perf_config *perf, int fd,
250                 const struct intel_perf_registers *config,
251                 const char *guid)
252 {
253    struct drm_i915_perf_oa_config i915_config = { 0, };
254 
255    memcpy(i915_config.uuid, guid, sizeof(i915_config.uuid));
256 
257    i915_config.n_mux_regs = config->n_mux_regs;
258    i915_config.mux_regs_ptr = to_const_user_pointer(config->mux_regs);
259 
260    i915_config.n_boolean_regs = config->n_b_counter_regs;
261    i915_config.boolean_regs_ptr = to_const_user_pointer(config->b_counter_regs);
262 
263    i915_config.n_flex_regs = config->n_flex_regs;
264    i915_config.flex_regs_ptr = to_const_user_pointer(config->flex_regs);
265 
266    int ret = intel_ioctl(fd, DRM_IOCTL_I915_PERF_ADD_CONFIG, &i915_config);
267    return ret > 0 ? ret : 0;
268 }
269 
270 int
i915_remove_config(struct intel_perf_config * perf,int fd,uint64_t config_id)271 i915_remove_config(struct intel_perf_config *perf, int fd, uint64_t config_id)
272 {
273    return intel_ioctl(fd, DRM_IOCTL_I915_PERF_REMOVE_CONFIG, &config_id);
274 }
275 
276 bool
i915_has_dynamic_config_support(struct intel_perf_config * perf,int fd)277 i915_has_dynamic_config_support(struct intel_perf_config *perf, int fd)
278 {
279    return i915_remove_config(perf, fd, UINT64_MAX) < 0 && errno == ENOENT;
280 }
281 
282 int
i915_perf_stream_set_state(int perf_stream_fd,bool enable)283 i915_perf_stream_set_state(int perf_stream_fd, bool enable)
284 {
285    unsigned long uapi = enable ? I915_PERF_IOCTL_ENABLE : I915_PERF_IOCTL_DISABLE;
286 
287    return intel_ioctl(perf_stream_fd, uapi, 0);
288 }
289 
290 int
i915_perf_stream_set_metrics_id(int perf_stream_fd,uint64_t metrics_set_id)291 i915_perf_stream_set_metrics_id(int perf_stream_fd, uint64_t metrics_set_id)
292 {
293    return intel_ioctl(perf_stream_fd, I915_PERF_IOCTL_CONFIG,
294                       (void *)(uintptr_t)metrics_set_id);
295 }
296