[PATCH i-g-t v2] Add single engine busyness stats in GPUTOP

Kamil Konieczny kamil.konieczny at linux.intel.com
Mon Feb 17 14:46:24 UTC 2025


Hi Soham,
On 2025-02-14 at 22:02:00 +0530, Soham Purkait wrote:
> Add single engine busyness support in GPUTOP.
> This uses the PMU interface to display the
> busyness of each engine instances.

I didn't read all your patch, only looked in few places.

> 
> ENGINES         BUSY
> Render/3D/0   | 96.5% ███████████████████████████████████████▍|
> Blitter/0     | 91.6% █████████████████████████████████████   |
> Video/0       | 56.2% ███████████████████████████             |
> VideoEnhance/0| 97.7% ████████████████████████████████████████|
> Compute/0     | 48.5% ███████████████████████▍                |
> 
> v1 : fixed cosmetic issues
> 
> v2 : fix for refactoring GPUTOP into a
>      vendor-agnostic tool (Lucas)
> 
> ---
>  lib/igt_device_scan.c        |  82 ++++++++
>  lib/igt_device_scan.h        |   5 +

Please send changes to this lib in separate patch.

>  lib/igt_perf.c               |  53 ++++++
>  lib/igt_perf.h               |   2 +

Same here.

>  tools/gputop/common_gputop.c |  51 +++++
>  tools/gputop/common_gputop.h |  16 ++
>  tools/{ => gputop}/gputop.c  | 246 ++++++++++++++++++++----
>  tools/gputop/meson.build     |   6 +
>  tools/gputop/xe_gputop.c     | 359 +++++++++++++++++++++++++++++++++++
>  tools/gputop/xe_gputop.h     |  74 ++++++++
>  tools/meson.build            |   6 +-
>  11 files changed, 858 insertions(+), 42 deletions(-)
>  create mode 100644 tools/gputop/common_gputop.c
>  create mode 100644 tools/gputop/common_gputop.h
>  rename tools/{ => gputop}/gputop.c (65%)
>  create mode 100644 tools/gputop/meson.build
>  create mode 100644 tools/gputop/xe_gputop.c
>  create mode 100644 tools/gputop/xe_gputop.h
> 
> diff --git a/lib/igt_device_scan.c b/lib/igt_device_scan.c
> index 711bedc5c..c71db0094 100644
> --- a/lib/igt_device_scan.c
> +++ b/lib/igt_device_scan.c
> @@ -773,6 +773,9 @@ __copy_dev_to_card(struct igt_device *dev, struct igt_device_card *card)
>  	if (dev->drm_render != NULL)
>  		safe_strncpy(card->render, dev->drm_render,
>  			     sizeof(card->render));
> +	if (dev->driver != NULL)
> +		safe_strncpy(card->driver, dev->driver,
> +			     sizeof(card->driver));
>  
>  	if (dev->pci_slot_name != NULL)
>  		safe_strncpy(card->pci_slot_name, dev->pci_slot_name,
> @@ -820,6 +823,61 @@ static bool __find_first_intel_card_by_driver_name(struct igt_device_card *card,
>  	return false;
>  }
>  
> +/*
> + * Iterate over all igt_devices array and find all discrete/integrated card.
> + * @card: double pointer to igt_device_card structure, containing
> + * an array of igt_device_card structure upon successful return.
> + */
> +static int __find_all_intel_card_by_driver_name(struct igt_device_card **card,
> +						bool want_discrete, const char *drv_name)
> +{
> +	int count = 0;
> +	struct igt_device *dev;
> +	int is_integrated;
> +	struct igt_device_card *tmp;
> +	struct igt_device_card *crd =
> +		(struct igt_device_card *)calloc(1, sizeof(struct igt_device_card));
> +
> +	igt_assert(drv_name);
> +	memset(card, 0, sizeof(*card));
> +
> +	igt_list_for_each_entry(dev, &igt_devs.all, link) {
> +		if (!is_pci_subsystem(dev) || strcmp(dev->driver, drv_name))
> +			continue;
> +
> +		is_integrated = !strncmp(dev->pci_slot_name, INTEGRATED_I915_GPU_PCI_ID,
> +				PCI_SLOT_NAME_SIZE);
> +
> +		if (want_discrete && !is_integrated) {
> +			__copy_dev_to_card(dev, (crd + count));
> +			count++;
> +			tmp = realloc(crd, sizeof(struct igt_device_card) * (1 + count));
> +			if (!tmp) {
> +				free(crd);
> +				return -1;
> +			}
> +			crd = tmp;
> +
> +		} else if (!want_discrete && is_integrated) {
> +			__copy_dev_to_card(dev, (crd + count));
> +			count++;
> +			tmp = realloc(crd, sizeof(struct igt_device_card) * (1 + count));
> +			if (!tmp) {
> +				free(crd);
> +				return -1;
> +			}
> +			crd = tmp;
> +		}
> +	}
> +	if (count == 0) {
> +		free(crd);
> +		return 0;
> +	}
> +
> +	*card = crd;
> +	return count;
> +}
> +
>  bool igt_device_find_first_i915_discrete_card(struct igt_device_card *card)
>  {
>  	igt_assert(card);
> @@ -866,6 +924,30 @@ bool igt_device_find_xe_integrated_card(struct igt_device_card *card)
>  	return __find_first_intel_card_by_driver_name(card, false, "xe");
>  }
>  
> +int igt_device_find_all_xe_integrated_card(struct igt_device_card **card)
> +{
> +	igt_assert(card);
> +	return __find_all_intel_card_by_driver_name(card, false, "xe");
> +}
> +
> +int igt_device_find_all_i915_integrated_card(struct igt_device_card **card)
> +{
> +	igt_assert(card);
> +	return __find_all_intel_card_by_driver_name(card, false, "i915");
> +}
> +
> +int igt_device_find_all_xe_discrete_card(struct igt_device_card **card)
> +{
> +	igt_assert(card);
> +	return __find_all_intel_card_by_driver_name(card, true, "xe");
> +}
> +
> +int igt_device_find_all_i915_discrete_card(struct igt_device_card **card)
> +{
> +	igt_assert(card);
> +	return __find_all_intel_card_by_driver_name(card, true, "i915");
> +}
> +
>  static struct igt_device *igt_device_from_syspath(const char *syspath)
>  {
>  	struct igt_device *dev;
> diff --git a/lib/igt_device_scan.h b/lib/igt_device_scan.h
> index 92741fe3c..da107292a 100644
> --- a/lib/igt_device_scan.h
> +++ b/lib/igt_device_scan.h
> @@ -59,6 +59,7 @@ struct igt_device_card {
>  	char subsystem[NAME_MAX];
>  	char card[NAME_MAX];
>  	char render[NAME_MAX];
> +	char driver[NAME_MAX];
>  	char pci_slot_name[PCI_SLOT_NAME_SIZE+1];
>  	uint16_t pci_vendor, pci_device;
>  };
> @@ -92,6 +93,10 @@ bool igt_device_find_first_i915_discrete_card(struct igt_device_card *card);
>  bool igt_device_find_integrated_card(struct igt_device_card *card);
>  bool igt_device_find_first_xe_discrete_card(struct igt_device_card *card);
>  bool igt_device_find_xe_integrated_card(struct igt_device_card *card);
> +int igt_device_find_all_i915_discrete_card(struct igt_device_card **card);
> +int igt_device_find_all_i915_integrated_card(struct igt_device_card **card);
> +int igt_device_find_all_xe_integrated_card(struct igt_device_card **card);
> +int igt_device_find_all_xe_discrete_card(struct igt_device_card **card);
>  char *igt_device_get_pretty_name(struct igt_device_card *card, bool numeric);
>  int igt_open_card(struct igt_device_card *card);
>  int igt_open_render(struct igt_device_card *card);
> diff --git a/lib/igt_perf.c b/lib/igt_perf.c
> index 3866c6d77..3f2f3311f 100644
> --- a/lib/igt_perf.c
> +++ b/lib/igt_perf.c
> @@ -129,6 +129,59 @@ uint64_t igt_perf_type_id(const char *device)
>  	return strtoull(buf, NULL, 0);
>  }
>  
> +int igt_perf_format(const char *device, const char *name, char *buff, int buflen)
> +{
> +	char buf[NAME_MAX];
> +	ssize_t ret;
> +	int fd;
> +
> +	snprintf(buf, sizeof(buf),
> +		 "/sys/bus/event_source/devices/%s/format/%s", device, name);
> +
> +	fd = open(buf, O_RDONLY);
> +	if (fd < 0)
> +		return -1;
> +
> +	ret = read(fd, buff, buflen - 1);
> +	close(fd);
> +	if (ret < 1)
> +		return -1;
> +
> +	buf[ret] = '\0';
> +
> +	return 0;
> +}
> +
> +uint64_t xe_perf_event_config(int xe, const char *pmu_str)

Why 'xe_' prefix here? imho this should be 'igt_'

> +{
> +	char buf[150];
> +	ssize_t ret;
> +	int fd;
> +	uint64_t config;
> +	char device[30];
> +
> +	snprintf(buf, sizeof(buf),
> +		 "/sys/bus/event_source/devices/%s/events/%s",
> +		 xe_perf_device(xe, device, sizeof(device)),

This looks generic, not restricted to Xe driver.

> +		 pmu_str);
> +
> +	fd = open(buf, O_RDONLY);
> +	if (fd < 0)
> +		return 0;
> +
> +	ret = read(fd, buf, sizeof(buf) - 1);
> +	close(fd);
> +	if (ret < 1)
> +		return 0;
> +
> +	buf[ret] = '\0';
> +	ret = sscanf(buf, "event=0x%lx", &config);
> +	if (ret != 1)
> +		return 0;
> +
> +	return config;
> +}
> +
>  int igt_perf_events_dir(int i915)
>  {
>  	char buf[80];
> diff --git a/lib/igt_perf.h b/lib/igt_perf.h
> index 3d9ba2917..26b9ffa29 100644
> --- a/lib/igt_perf.h
> +++ b/lib/igt_perf.h
> @@ -54,9 +54,11 @@ perf_event_open(struct perf_event_attr *attr,
>  }
>  
>  uint64_t igt_perf_type_id(const char *device);
> +uint64_t xe_perf_event_config(int xe, const char *pmu_event);
>  int igt_perf_events_dir(int i915);
>  int igt_perf_open(uint64_t type, uint64_t config);
>  int igt_perf_open_group(uint64_t type, uint64_t config, int group);
> +int igt_perf_format(const char *device, const char *name, char *buff, int buflen);
>  
>  const char *i915_perf_device(int i915, char *buf, int buflen);
>  uint64_t i915_perf_type_id(int i915);
> diff --git a/tools/gputop/common_gputop.c b/tools/gputop/common_gputop.c
> new file mode 100644
> index 000000000..1188d8e6a
> --- /dev/null
> +++ b/tools/gputop/common_gputop.c
> @@ -0,0 +1,51 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2025 Intel Corporation
> + */
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include "common_gputop.h"
> +
> +static const char * const bars[] = { " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
> +
> +void n_spaces(const unsigned int n)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < n; i++)
> +		putchar(' ');
> +}
> +
> +void print_percentage_bar(double percent, int max_len)
> +{
> +	int bar_len, i, len = max_len - 1;
> +	const int w = 8;
> +
> +	len -= printf("|%5.1f%% ", percent);
> +
> +	/* no space left for bars, do what we can */
> +	if (len < 0)
> +		len = 0;
> +
> +	bar_len = ceil(w * percent * len / 100.0);
> +	if (bar_len > w * len)
> +		bar_len = w * len;
> +
> +	for (i = bar_len; i >= w; i -= w)
> +		printf("%s", bars[w]);
> +	if (i)
> +		printf("%s", bars[i]);
> +
> +	len -= (bar_len + (w - 1)) / w;
> +	n_spaces(len);
> +
> +	putchar('|');
> +}
> +
> +int print_engines_footer(int lines, int con_w, int con_h)
> +{
> +	if (lines++ < con_h)
> +		printf("\n");
> +
> +	return lines;
> +}
> diff --git a/tools/gputop/common_gputop.h b/tools/gputop/common_gputop.h
> new file mode 100644
> index 000000000..29ba48d86
> --- /dev/null
> +++ b/tools/gputop/common_gputop.h
> @@ -0,0 +1,16 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2025 Intel Corporation
> + */
> +#ifndef COMMON_GPUTOP_H
> +#define COMMON_GPUTOP_H
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <math.h>

Move above std*h headers.

> +
> +void print_percentage_bar(double percent, int max_len);
> +int print_engines_footer(int lines, int con_w, int con_h);
> +void n_spaces(const unsigned int n);
> +
> +#endif // COMMON_GPUTOP_H
> diff --git a/tools/gputop.c b/tools/gputop/gputop.c
> similarity index 65%
> rename from tools/gputop.c
> rename to tools/gputop/gputop.c
> index 43b01f566..e53d1f087 100644
> --- a/tools/gputop.c
> +++ b/tools/gputop/gputop.c
> @@ -1,8 +1,7 @@
>  // SPDX-License-Identifier: MIT
>  /*
> - * Copyright © 2023 Intel Corporation
> + * Copyright © 2025 Intel Corporation

Do not erase years, add new one for example:

 * Copyright © 2023-2025 Intel Corporation

Regards,
Kamil

[...cut...]


More information about the igt-dev mailing list