summaryrefslogtreecommitdiff
path: root/tools/i915-perf
diff options
context:
space:
mode:
authorLionel Landwerlin <lionel.g.landwerlin@intel.com>2020-02-12 17:18:47 +0200
committerLionel Landwerlin <lionel.g.landwerlin@intel.com>2020-02-19 18:46:07 +0200
commitc05dc6cd816feb1cc518ce777ab3fd6c81893113 (patch)
tree72bb814edd998d2a3378320486601ac039613890 /tools/i915-perf
parent43116ee368585d4fe37245e7439066a3239ec73e (diff)
tools: add i915-perf-reader
Reading & printing out data recorded with i915-perf-recorder. v2: Autotools support Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Acked-by: Chris Wilson <chris@chris-wilson.co.uk> Acked-by: Petri Latvala <petri.latvala@intel.com>
Diffstat (limited to 'tools/i915-perf')
-rw-r--r--tools/i915-perf/Makefile.am7
-rw-r--r--tools/i915-perf/i915_perf_reader.c284
-rw-r--r--tools/i915-perf/meson.build6
3 files changed, 296 insertions, 1 deletions
diff --git a/tools/i915-perf/Makefile.am b/tools/i915-perf/Makefile.am
index fa2d643a..5520a59e 100644
--- a/tools/i915-perf/Makefile.am
+++ b/tools/i915-perf/Makefile.am
@@ -1,7 +1,8 @@
bin_PROGRAMS = \
i915-perf-configs \
i915-perf-control \
- i915-perf-recorder
+ i915-perf-recorder \
+ i915-perf-reader
AM_CFLAGS = $(CWARNFLAGS) -Wno-unused-result $(DEBUG_CFLAGS)\
-I$(top_srcdir)/include/drm-uapi \
@@ -22,3 +23,7 @@ i915_perf_control_CFLAGS = $(AM_CFLAGS)
i915_perf_recorder_SOURCES = i915_perf_recorder.c
i915_perf_recorder_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/lib/i915
i915_perf_recorder_LDADD = $(LDADD) $(top_builddir)/lib/libi915_perf.la
+
+i915_perf_reader_SOURCES = i915_perf_reader.c
+i915_perf_reader_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/lib/i915
+i915_perf_reader_LDADD = ../../lib/libintel_tools.la $(top_builddir)/lib/libi915_perf.la
diff --git a/tools/i915-perf/i915_perf_reader.c b/tools/i915-perf/i915_perf_reader.c
new file mode 100644
index 00000000..3e4a6530
--- /dev/null
+++ b/tools/i915-perf/i915_perf_reader.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2020 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 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 <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <i915_drm.h>
+
+#include "igt_core.h"
+#include "intel_chipset.h"
+#include "i915/perf.h"
+#include "i915/perf_data_reader.h"
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MIN(a,b) ((a) > (b) ? (b) : (a))
+
+static void
+usage(void)
+{
+ printf("Usage: i915-perf-reader [options] file\n"
+ "Reads the content of an i915-perf recording.\n"
+ "\n"
+ " --help, -h Print this screen\n"
+ " --counters, -c c1,c2,... List of counters to display values for.\n"
+ " Use 'all' to display all counters.\n"
+ " Use 'list' to list available counters.\n");
+}
+
+static struct intel_perf_logical_counter *
+find_counter(struct intel_perf_metric_set *metric_set,
+ const char *name)
+{
+ for (uint32_t i = 0; i < metric_set->n_counters; i++) {
+ if (!strcmp(name, metric_set->counters[i].symbol_name)) {
+ return &metric_set->counters[i];
+ }
+ }
+
+ return NULL;
+}
+
+static void
+append_counter(struct intel_perf_logical_counter ***counters,
+ int32_t *n_counters,
+ uint32_t *n_allocated_counters,
+ struct intel_perf_logical_counter *counter)
+{
+ if (*n_counters < *n_allocated_counters) {
+ (*counters)[(*n_counters)++] = counter;
+ return;
+ }
+
+ *n_allocated_counters = MAX(2, *n_allocated_counters * 2);
+ *counters = realloc(*counters,
+ sizeof(struct intel_perf_logical_counter *) *
+ (*n_allocated_counters));
+ (*counters)[(*n_counters)++] = counter;
+}
+
+static struct intel_perf_logical_counter **
+get_logical_counters(struct intel_perf_metric_set *metric_set,
+ const char *counter_list,
+ int32_t *out_n_counters)
+{
+ struct intel_perf_logical_counter **counters = NULL, *counter;
+ uint32_t n_allocated_counters = 0;
+ const char *current, *next;
+ char counter_name[100];
+
+ if (!counter_list) {
+ *out_n_counters = 0;
+ return NULL;
+ }
+
+ if (!strcmp(counter_list, "list")) {
+ uint32_t longest_name = 0;
+
+ *out_n_counters = -1;
+ for (uint32_t i = 0; i < metric_set->n_counters; i++) {
+ longest_name = MAX(longest_name,
+ strlen(metric_set->counters[i].symbol_name));
+ }
+
+ fprintf(stdout, "Available counters:\n");
+ for (uint32_t i = 0; i < metric_set->n_counters; i++) {
+ fprintf(stdout, "%s:%*s%s\n",
+ metric_set->counters[i].symbol_name,
+ (int)(longest_name -
+ strlen(metric_set->counters[i].symbol_name) + 1), " ",
+ metric_set->counters[i].name);
+ }
+ return NULL;
+ }
+
+ if (!strcmp(counter_list, "all")) {
+ counters = malloc(sizeof(*counters) * metric_set->n_counters);
+ *out_n_counters = metric_set->n_counters;
+ for (uint32_t i = 0; i < metric_set->n_counters; i++)
+ counters[i] = &metric_set->counters[i];
+ return counters;
+ }
+
+ *out_n_counters = 0;
+ current = counter_list;
+ while ((next = strstr(current, ","))) {
+ snprintf(counter_name,
+ MIN((uint32_t)(next - current) + 1, sizeof(counter_name)),
+ "%s", current);
+
+ counter = find_counter(metric_set, counter_name);
+ if (!counter) {
+ fprintf(stderr, "Unknown counter '%s'.\n", counter_name);
+ free(counters);
+ *out_n_counters = -1;
+ return NULL;
+ }
+
+ append_counter(&counters, out_n_counters, &n_allocated_counters, counter);
+
+ current = next + 1;
+ }
+
+ if (strlen(current) > 0) {
+ counter = find_counter(metric_set, current);
+ if (!counter) {
+ fprintf(stderr, "Unknown counter '%s'.\n", current);
+ free(counters);
+ *out_n_counters = -1;
+ return NULL;
+ }
+
+ append_counter(&counters, out_n_counters, &n_allocated_counters, counter);
+ }
+
+ return counters;
+}
+
+int
+main(int argc, char *argv[])
+{
+ const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"counters", required_argument, 0, 'c'},
+ {0, 0, 0, 0}
+ };
+ struct intel_perf_data_reader reader;
+ struct intel_perf_logical_counter **counters;
+ const struct intel_device_info *devinfo;
+ const char *counter_names = NULL;
+ int32_t n_counters;
+ int fd, opt;
+
+ while ((opt = getopt_long(argc, argv, "hc:", long_options, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ usage();
+ return EXIT_SUCCESS;
+ case 'c':
+ counter_names = optarg;
+ break;
+ default:
+ fprintf(stderr, "Internal error: "
+ "unexpected getopt value: %d\n", opt);
+ usage();
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (optind >= argc) {
+ fprintf(stderr, "No recording file specified.\n");
+ return EXIT_FAILURE;
+ }
+
+ fd = open(argv[optind], 0, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open '%s': %s.\n",
+ argv[optind], strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ if (!intel_perf_data_reader_init(&reader, fd)) {
+ fprintf(stderr, "Unable to parse '%s': %s.\n",
+ argv[optind], reader.error_msg);
+ return EXIT_FAILURE;
+ }
+
+ counters = get_logical_counters(reader.metric_set, counter_names, &n_counters);
+ if (n_counters < 0)
+ goto exit;
+
+ devinfo = intel_get_device_info(reader.devinfo.devid);
+
+ fprintf(stdout, "Recorded on device=0x%x(%s) gen=%i\n",
+ reader.devinfo.devid, devinfo->codename, reader.devinfo.gen);
+ fprintf(stdout, "Metric used : %s (%s) uuid=%s\n",
+ reader.metric_set->symbol_name, reader.metric_set->name,
+ reader.metric_set->hw_config_guid);
+ fprintf(stdout, "Reports: %u\n", reader.n_records);
+ fprintf(stdout, "Context switches: %u\n", reader.n_timelines);
+ fprintf(stdout, "Timestamp correlation points: %u\n", reader.n_correlations);
+
+ if (strcmp(reader.metric_set_uuid, reader.metric_set->hw_config_guid)) {
+ fprintf(stdout,
+ "WARNING: Recording used a different HW configuration.\n"
+ "WARNING: This could lead to inconsistent counter values.\n");
+ }
+
+ for (uint32_t i = 0; i < reader.n_timelines; i++) {
+ const struct intel_perf_timeline_item *item = &reader.timelines[i];
+ const struct drm_i915_perf_record_header *i915_report0 =
+ reader.records[item->record_start];
+ const struct drm_i915_perf_record_header *i915_report1 =
+ reader.records[item->record_end];
+ struct intel_perf_accumulator accu;
+
+ fprintf(stdout, "Time: CPU=0x%016" PRIx64 "-0x%016" PRIx64
+ " GPU=0x%016" PRIx64 "-0x%016" PRIx64"\n",
+ item->cpu_ts_start, item->cpu_ts_end,
+ item->ts_start, item->ts_end);
+ fprintf(stdout, "hw_id=0x%x %s\n",
+ item->hw_id, item->hw_id == 0xffffffff ? "(idle)" : "");
+
+ intel_perf_accumulate_reports(&accu, reader.metric_set->perf_oa_format,
+ i915_report0, i915_report1);
+
+ for (uint32_t c = 0; c < n_counters; c++) {
+ struct intel_perf_logical_counter *counter = counters[c];
+
+ switch (counter->storage) {
+ case INTEL_PERF_LOGICAL_COUNTER_STORAGE_UINT64:
+ case INTEL_PERF_LOGICAL_COUNTER_STORAGE_UINT32:
+ case INTEL_PERF_LOGICAL_COUNTER_STORAGE_BOOL32:
+ fprintf(stdout, " %s: %" PRIu64 "\n",
+ counter->symbol_name, counter->read_uint64(reader.perf,
+ reader.metric_set,
+ accu.deltas));
+ break;
+ case INTEL_PERF_LOGICAL_COUNTER_STORAGE_DOUBLE:
+ case INTEL_PERF_LOGICAL_COUNTER_STORAGE_FLOAT:
+ fprintf(stdout, " %s: %f\n",
+ counter->symbol_name, counter->read_float(reader.perf,
+ reader.metric_set,
+ accu.deltas));
+ break;
+ }
+ }
+ }
+
+ exit:
+ intel_perf_data_reader_fini(&reader);
+ close(fd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/i915-perf/meson.build b/tools/i915-perf/meson.build
index 9884dfd9..3fbf20a0 100644
--- a/tools/i915-perf/meson.build
+++ b/tools/i915-perf/meson.build
@@ -14,3 +14,9 @@ executable('i915-perf-control',
[ 'i915_perf_control.c' ],
include_directories: inc,
install: true)
+
+executable('i915-perf-reader',
+ [ 'i915_perf_reader.c' ],
+ include_directories: inc,
+ dependencies: [lib_igt, lib_igt_i915_perf],
+ install: true)