mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-19 15:48:19 +02:00
The kernel uses an updated buffer format for xe3p gpus when EU stall sampling, so this updates intel_monitor to use the correct formatting, leaving room for any future formatting updates. This also addresses an issue with not packing the formatted structure with the correct macro, which lead to incorrect offsets being used for parsing the buffer. BSpec: 79847 v2: Add BSpec reference number, suggested by Lionel Signed-off-by: Casey Bowman <casey.g.bowman@intel.com> Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40622>
220 lines
6.8 KiB
C
220 lines
6.8 KiB
C
/*
|
|
* Copyright 2024 Intel Corporation
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "intel_monitor_eustall.h"
|
|
|
|
#include <poll.h>
|
|
|
|
#include "util/u_qsort.h"
|
|
#include "util/xxhash.h"
|
|
|
|
static bool
|
|
oa_stream_ready(int fd)
|
|
{
|
|
struct pollfd pfd;
|
|
|
|
pfd.fd = fd;
|
|
pfd.events = POLLIN;
|
|
pfd.revents = 0;
|
|
|
|
if (poll(&pfd, 1, 0) < 0) {
|
|
fprintf(stderr, "IMON: Error polling OA stream\n");
|
|
return false;
|
|
}
|
|
|
|
if (!(pfd.revents & POLLIN))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Initialize eustall_cfg and enable eu stall profiling by
|
|
* opening stream with KMD. Return eustall_cfg.
|
|
*/
|
|
struct eustall_config*
|
|
eustall_setup(int drm_fd, struct intel_device_info *devinfo)
|
|
{
|
|
struct eustall_config *eustall_cfg = malloc(sizeof(struct eustall_config));
|
|
eustall_cfg->min_event_count = 1, /* min records to trigger data flush */
|
|
eustall_cfg->drm_fd = drm_fd;
|
|
eustall_cfg->fd = -1;
|
|
eustall_cfg->devinfo = devinfo;
|
|
|
|
eustall_cfg->result.accumulator =
|
|
_mesa_hash_table_create(NULL,
|
|
_mesa_hash_u64,
|
|
_mesa_key_u64_equal);
|
|
|
|
/* Arbitrarily large buffer for copying stall data into. */
|
|
eustall_cfg->buf_len = 64 * 1024 * 1024;
|
|
eustall_cfg->buf = malloc(eustall_cfg->buf_len);
|
|
|
|
return eustall_cfg;
|
|
}
|
|
|
|
static bool
|
|
init_stream(struct eustall_config *eustall_cfg)
|
|
{
|
|
eustall_cfg->record_size =
|
|
intel_perf_eustall_stream_record_size(eustall_cfg->devinfo,
|
|
eustall_cfg->drm_fd);
|
|
if (eustall_cfg->record_size <= 0) {
|
|
fprintf(stderr, "IMON: ERROR encountered querying record size."
|
|
" err=%i\n", eustall_cfg->record_size);
|
|
return false;
|
|
}
|
|
|
|
eustall_cfg->sample_rate =
|
|
intel_perf_eustall_stream_sample_rate(eustall_cfg->devinfo,
|
|
eustall_cfg->drm_fd);
|
|
if (eustall_cfg->sample_rate <= 0) {
|
|
fprintf(stderr, "IMON: ERROR encountered querying sampling rate."
|
|
" err=%i\n", eustall_cfg->sample_rate);
|
|
return false;
|
|
}
|
|
|
|
eustall_cfg->fd =
|
|
intel_perf_eustall_stream_open(eustall_cfg->devinfo,
|
|
eustall_cfg->drm_fd,
|
|
eustall_cfg->sample_rate,
|
|
eustall_cfg->min_event_count);
|
|
if (eustall_cfg->fd < 0) {
|
|
fprintf(stderr, "IMON: ERROR encountered while opening "
|
|
"eustall stream. err=%i\n", eustall_cfg->fd);
|
|
return false;
|
|
}
|
|
fprintf(stderr, "IMON: intel_perf_eustall_stream_open = %i\n",
|
|
eustall_cfg->fd);
|
|
|
|
int err = intel_perf_eustall_stream_set_state(eustall_cfg->devinfo,
|
|
eustall_cfg->fd, true);
|
|
if (err != 0) {
|
|
fprintf(stderr, "IMON: ERROR encountered while enabling stream."
|
|
" err=%i\n", err);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Sample all eustall data via KMD stream. Open stream on first call.
|
|
*/
|
|
bool
|
|
eustall_sample(void *cfg)
|
|
{
|
|
struct eustall_config *eustall_cfg = cfg;
|
|
bool overflow;
|
|
|
|
if (eustall_cfg->fd < 0 || eustall_cfg->record_size <= 0)
|
|
return init_stream(eustall_cfg);
|
|
|
|
while (oa_stream_ready(eustall_cfg->fd)) {
|
|
int bytes_read =
|
|
intel_perf_eustall_stream_read_samples(eustall_cfg->devinfo,
|
|
eustall_cfg->fd,
|
|
eustall_cfg->buf,
|
|
eustall_cfg->buf_len,
|
|
&overflow);
|
|
if (bytes_read <= 0) {
|
|
if (bytes_read < 0)
|
|
fprintf(stderr, "IMON: read_samples returned err=%i\n", bytes_read);
|
|
break;
|
|
}
|
|
|
|
if (overflow)
|
|
fprintf(stderr, "IMON: detected EU stall sampling buffer overflow. "
|
|
"Some stall data was lost.\n");
|
|
|
|
intel_perf_eustall_accumulate_results(&eustall_cfg->result,
|
|
eustall_cfg->buf,
|
|
eustall_cfg->buf + bytes_read,
|
|
eustall_cfg->record_size,
|
|
eustall_cfg->devinfo->ver);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int
|
|
compare_ip_addr(const void *a, const void *b)
|
|
{
|
|
const uint64_t *val_a = a;
|
|
const uint64_t *val_b = b;
|
|
return (int)(*val_a - *val_b);
|
|
}
|
|
|
|
/* Write all previously collected results to fd. Clear results.
|
|
*/
|
|
void
|
|
eustall_dump_results(void *cfg, FILE *file)
|
|
{
|
|
struct eustall_config *eustall_cfg = cfg;
|
|
struct hash_table *accumulator = eustall_cfg->result.accumulator;
|
|
uint64_t *ip_addr_keys = malloc(accumulator->size * sizeof(uint64_t));
|
|
uint32_t num_entries = accumulator->entries;
|
|
uint32_t i = 0;
|
|
|
|
/* Sort keys so ip_addr appear in order */
|
|
hash_table_foreach(accumulator, entry) {
|
|
struct intel_perf_query_eustall_event* data =
|
|
(struct intel_perf_query_eustall_event*)entry->data;
|
|
ip_addr_keys[i++] = data->ip_addr;
|
|
}
|
|
qsort(ip_addr_keys, accumulator->entries, sizeof(uint64_t), compare_ip_addr);
|
|
|
|
fprintf(file, "offset,tdr_count,other_count,control_count,pipestall_count,"
|
|
"send_count,dist_acc_count,sbid_count,sync_count,"
|
|
"inst_fetch_count,active_count,sum\n");
|
|
|
|
for (i = 0; i < num_entries; i++) {
|
|
struct hash_entry *entry =
|
|
_mesa_hash_table_search(accumulator, ip_addr_keys + i);
|
|
struct intel_perf_query_eustall_event *data =
|
|
(struct intel_perf_query_eustall_event*)entry->data;
|
|
|
|
uint64_t ip_addr = data->ip_addr << 3;
|
|
uint64_t sum = data->tdr_count + data->other_count +
|
|
data->control_count + data->pipestall_count + data->send_count +
|
|
data->dist_acc_count + data->sbid_count + data->sync_count +
|
|
data->inst_fetch_count + data->active_count;
|
|
|
|
fprintf(file,
|
|
"0x%08" PRIx64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ","
|
|
"%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ","
|
|
"%" PRIu64 ",%" PRIu64 "\n",
|
|
ip_addr, data->tdr_count, data->other_count, data->control_count,
|
|
data->pipestall_count, data->send_count, data->dist_acc_count,
|
|
data->sbid_count, data->sync_count, data->inst_fetch_count,
|
|
data->active_count, sum);
|
|
|
|
free(data);
|
|
_mesa_hash_table_remove(accumulator, entry);
|
|
}
|
|
free(ip_addr_keys);
|
|
}
|
|
|
|
static void
|
|
delete_entry(struct hash_entry *entry)
|
|
{
|
|
free(entry->data);
|
|
}
|
|
|
|
/* Close eustall stream and deconstruct eustall cfg.
|
|
*/
|
|
void
|
|
eustall_close(void *cfg)
|
|
{
|
|
struct eustall_config *eustall_cfg = cfg;
|
|
_mesa_hash_table_destroy(eustall_cfg->result.accumulator, delete_entry);
|
|
eustall_cfg->result.accumulator = NULL;
|
|
|
|
close(eustall_cfg->fd);
|
|
eustall_cfg->fd = -1;
|
|
|
|
free(eustall_cfg->buf);
|
|
eustall_cfg->buf = NULL;
|
|
|
|
free(eustall_cfg);
|
|
}
|