[igt-dev] [PATCH i-g-t v7 3/3] Introduce device selection lsgpu tool

Zbigniew Kempczyński
2019-09-11T04:01:02Z

Tool uses device selection API to scan and display GPU devices.
It can be used to check filter correctness as well as order
of filter applying (.igtrc, IGT_DEVICE and --device argument).

Signed-off-by: Zbigniew Kempczyński <zbigniew.kempczynski@intel.com>
Cc: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Petri Latvala <petri.latvala@intel.com>
---
tools/Makefile.sources | 1 +
tools/lsgpu.c | 299 +++++++++++++++++++++++++++++++++++++++++
tools/meson.build | 1 +
3 files changed, 301 insertions(+)
create mode 100644 tools/lsgpu.c

diff --git a/tools/Makefile.sources b/tools/Makefile.sources
index 50706f41..0e67b654 100644
--- a/tools/Makefile.sources
+++ b/tools/Makefile.sources
@@ -33,6 +33,7 @@ tools_prog_lists = \
intel_watermark \
intel_gem_info \
intel_gvtg_test \
+ lsgpu \
$(NULL)

dist_bin_SCRIPTS = intel_gpu_abrt
diff --git a/tools/lsgpu.c b/tools/lsgpu.c
new file mode 100644
index 00000000..964bcf88
--- /dev/null
+++ b/tools/lsgpu.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "igt_device_scan.h"
+#include "igt.h"
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <glib.h>
+
+/**
+ * SECTION:lsgpu
+ * @short_description: lsgpu
+ * @title: lsgpu
+ * @include: lsgpu.c
+ *
+ * # lsgpu
+ *
+ * The devices can be scanned and displayed using 'lsgpu' tool. Tool also
+ * displays properties and sysattrs (-p switch, means print detail) which
+ * can be used during filter implementation.
+ *
+ * Tool can also be used to try out filters.
+ * To select device use '-d' or '--device' argument like:
+ *
+ * |[
+ * ./lsgpu -d 'pci:vendor=Intel'
+ * === Device filter list ===
+ * [ 0]: pci:vendor=Intel
+
+ * === Testing device open ===
+ * subsystem : pci
+ * chipset : 1
+ * drm card : /dev/dri/card0
+ * drm render : /dev/dri/renderD128
+ * Device /dev/dri/card0 successfully opened
+ * Device /dev/dri/renderD128 successfully opened
+ * ]|
+ *
+ * Additionally lsgpu tries to open the card and render nodes to verify
+ * permissions. It also uses IGT variable search order:
+ * - use --device first (it overrides IGT_DEVICE and .igtrc Common::Device
+ * settings)
+ * - use IGT_DEVICE enviroment variable if no --device are passed
+ * - use .igtrc Common::Device if no --device nor IGT_DEVICE are passed
+ */
+
+enum {
+ OPT_PRINT_DETAIL = 'p',
+ OPT_LIST_VENDORS = 'v',
+ OPT_LIST_FILTERS = 'l',
+ OPT_DEVICE = 'd',
+ OPT_HELP = 'h'
+};
+
+static bool g_show_vendors;
+static bool g_list_filters;
+static bool g_device;
+static bool g_help;
+static char *igt_rc_device;
+
+static const char *usage_str =
+ "usage: lsgpu [options]\n\n"
+ "Options:\n"
+ " -p, --print-details Print devices with details\n"
+ " -v, --list-vendors List recognized vendors\n"
+ " -l, --list-filter-types List registered device filters types\n"
+ " -d, --device filter Device filter, can be given multiple times\n"
+ " -h, --help Show this help message and exit\n";
+
+static void test_device_open(struct igt_device_card *card)
+{
+ int fd;
+
+ if (!card)
+ return;
+
+ fd = drm_open_card(card);
+ if (fd >= 0) {
+ printf("Device %s successfully opened\n", card->card);
+ close(fd);
+ } else {
+ if (strlen(card->card))
+ printf("Cannot open card %s device\n", card->card);
+ else
+ printf("Cannot open card device, empty name\n");
+ }
+
+ fd = drm_open_render(card);
+ if (fd >= 0) {
+ printf("Device %s successfully opened\n", card->render);
+ close(fd);
+ } else {
+ if (strlen(card->render))
+ printf("Cannot open render %s device\n", card->render);
+ else
+ printf("Cannot open render device, empty name\n");
+ }
+}
+
+static void print_card(struct igt_device_card *card)
+{
+ if (!card)
+ return;
+
+ printf("subsystem : %s\n", card->subsystem);
+ printf("chipset : %x\n", card->chipset);
+ printf("drm card : %s\n", card->card);
+ printf("drm render : %s\n", card->render);
+}
+
+/* Partially copied from igt_core to simulate device selection order:
+ * 1. --device (IGT_DEVICE and .igtrc Common::Device are ignored)
+ * 2. IGT_DEVICE env (.igtrc Common::Device is ignored)
+ * 3. .igtrc (overrides
+ */
+static void common_init_config(void)
+{
+ char *key_file_env = NULL;
+ char *key_file_loc = NULL;
+ GError *error = NULL;
+ GKeyFile *igt_key_file;
+ int ret;
+
+ /* Filter count > 0, just skip .igtrc */
+ if (igt_device_filter_count())
+ return;
+
+ /* Determine igt config path */
+ key_file_env = getenv("IGT_CONFIG_PATH");
+ if (key_file_env) {
+ key_file_loc = key_file_env;
+ } else {
+ key_file_loc = malloc(100);
+ snprintf(key_file_loc, 100, "%s/.igtrc", g_get_home_dir());
+ }
+
+ /* Load igt config file */
+ igt_key_file = g_key_file_new();
+ ret = g_key_file_load_from_file(igt_key_file, key_file_loc,
+ G_KEY_FILE_NONE, &error);
+ if (!ret) {
+ g_error_free(error);
+ g_key_file_free(igt_key_file);
+ igt_key_file = NULL;
+
+ return;
+ }
+
+ g_clear_error(&error);
+
+ if (!igt_rc_device)
+ igt_rc_device = g_key_file_get_string(igt_key_file, "Common",
+ "Device", &error);
+
+ if (igt_rc_device) {
+ igt_device_filter_add(igt_rc_device);
+ g_device = true;
+ }
+
+ g_clear_error(&error);
+}
+
+int main(int argc, char *argv[])
+{
+ static struct option long_options[] = {
+ {"print-detail", no_argument, NULL, OPT_PRINT_DETAIL},
+ {"list-vendors", no_argument, NULL, OPT_LIST_VENDORS},
+ {"list-filter-types", no_argument, NULL, OPT_LIST_FILTERS},
+ {"device", required_argument, NULL, OPT_DEVICE},
+ {"help", no_argument, NULL, OPT_HELP},
+ {0, 0, 0, 0}
+ };
+ int c, index = 0;
+ const char *env;
+ enum igt_devices_print_type printtype = IGT_PRINT_SIMPLE;
+
+ env = getenv("IGT_DEVICE");
+ if (env) {
+ igt_device_filter_add(env);
+ g_device = true;
+ }
+
+ while ((c = getopt_long(argc, argv, "pvld:h",
+ long_options, &index)) != -1) {
+ switch(c) {
+
+ case OPT_PRINT_DETAIL:
+ printtype = IGT_PRINT_DETAIL;
+ break;
+ case OPT_LIST_VENDORS:
+ g_show_vendors = true;
+ break;
+ case OPT_LIST_FILTERS:
+ g_list_filters = true;
+ break;
+ case OPT_DEVICE:
+ g_device = true;
+ if (getenv("IGT_DEVICE") && igt_device_filter_count()) {
+ unsetenv("IGT_DEVICE");
+ igt_rc_device = NULL;
+ igt_device_filter_free_all();
+ }
+ igt_device_filter_add(optarg);
+ break;
+ case OPT_HELP:
+ g_help = true;
+ break;
+ }
+ }
+ common_init_config();
+
+ if (g_help) {
+ printf("%s\n", usage_str);
+ exit(0);
+ }
+
+ if (g_show_vendors) {
+ igt_devices_print_vendors();
+ return 0;
+ }
+
+ if (g_list_filters) {
+ igt_device_print_filter_types();
+ return 0;
+ }
+
+ igt_devices_scan(false);
+
+ if (getenv("IGT_DEVICE")) {
+ printf("Notice: Using IGT_DEVICE device settings [%s]\n",
+ getenv("IGT_DEVICE"));
+ } else if (igt_rc_device) {
+ printf("Notice: Using .igtrc device settings [%s]\n",
+ igt_rc_device);
+ } else {
+ if (igt_device_filter_count())
+ printf("Notice: Using --device filters\n");
+ }
+
+ if (g_device) {
+ int n = igt_device_filter_count();
+ printf("=== Device filter list ===\n");
+ for (int i = 0; i < n; i++) {
+ printf("[%2d]: %s\n", i,
+ igt_device_filter_get(i));
+ }
+ printf("\n");
+
+ printf("=== Testing device open ===\n");
+ for (int i = 0; i < n; i++) {
+ struct igt_device_card card;
+ const char *filter = igt_device_filter_get(i);
+
+ if (!igt_device_card_match(filter, &card)) {
+ printf("[%2d]: No device found for filter\n\n",
+ i);
+ continue;
+ }
+ printf("[%2d]: Device detail:\n", i);
+ print_card(&card);
+ test_device_open(&card);
+ if (printtype == IGT_PRINT_DETAIL) {
+ printf("\n");
+ igt_devices_print(printtype);
+ }
+ printf("-------------------------------------------\n");
+ }
+
+ return 0;
+ }
+
+ igt_devices_print(printtype);
+
+ return 0;
+}
diff --git a/tools/meson.build b/tools/meson.build
index 6e72b263..9b3a2a69 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -36,6 +36,7 @@ tools_progs = [
'intel_gem_info',
'intel_gvtg_test',
'dpcd_reg',
+ 'lsgpu',
]
tool_deps = igt_deps

--
2.23.0