All of lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf
@ 2020-02-17 14:21 Lionel Landwerlin
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 1/6] lib/intel_chipset: identify Elkhart Lake Lionel Landwerlin
                   ` (6 more replies)
  0 siblings, 7 replies; 16+ messages in thread
From: Lionel Landwerlin @ 2020-02-17 14:21 UTC (permalink / raw)
  To: igt-dev

Hi all,

i915-perf was added about 3 or 4 years ago (first released in 4.13).
At the time a new GPUTop [1] open source project was created to show
case the usefulness of the data exposed through i915-perf. Initially
GPUTop is entirely driven by traces coming from the GPU. Some effort
came along later to use perf traces (mostly tracepoints) to complete
the picture and connect the dots between GPU HW contexts and the
processes that triggered those contexts running.

About a year later Valve showcased another tool GPUvis [2]. GPUvis is
currently only driven by traces recorded on the CPU (ftrace on Linux)
but it's UI is undeniably better, showing a lot more information
coming off ftrace.

A few months ago Joonas thought it would be best to have GPUvis be the
tool we spend time improving rather than our own effort, and I came to
the same conclusion.

So what does this have to do IGT?

Well first, GPUvis is really only a few scripts around ftrace and some
parsing code for ftrace as well as a user interface. But it does not
deal directly with the kernel nor its drivers.

So a recording tool for the i915-perf data needs to live somewhere.
Right now this partly exists in GPUTop, except the data is never saved
anywhere, it just resides in memory (either on the machine being
monitored or the remote client inspecting the data).

Secondly, GPUTop is also the place where we store the HW
configurations for the Gen observation architecture as well as the
equations to make up human readable data out of HW register values. If
we're not going to invest much more effort into GPUTop, maybe it's a
good idea to more that part into a more lively project.


This series (probably too big for mail [3]) adds the following new
things to IGT :

   * A new library libi915_perf.so that helps you :

      * parse i915-perf data from low level reports into logical
        counters (with name & description)

      * a library to load a file in which was recorded i915-perf data
        along with other bits of information (device id, topology,
        timestamp correlation, etc...)

   * A set of tools to deal with :

      * HW configurations stored in i915

      * recording i915-perf data into a file that can be replay with
        the library mentioned above

      * basic replaying of i915-perf data (mostly showing how to use
        the library above)


Now with all this I have a GPUvis changes making use of this library &
recording tool [4].

Hopefully this explains what we're trying to do here.

Cheers,

[1] : https://github.com/rib/gputop
[2] : https://github.com/mikesart/gpuvis
[3] : https://github.com/djdeath/intel-gpu-tools/tree/review/i915-perf-tools

Lionel Landwerlin (6):
  lib/intel_chipset: identify Elkhart Lake
  Add i915_perf library
  lib/i915: Add support for loading perf configurations
  tools: add i915 perf recorder tool
  lib: add i915 perf data reader
  tools: add i915-perf-reader

 lib/i915-perf.pc.in                           |    11 +
 lib/i915/perf-configs/README.md               |   115 +
 lib/i915/perf-configs/codegen.py              |    33 +
 lib/i915/perf-configs/guids.xml               |   319 +
 lib/i915/perf-configs/mdapi-xml-convert.py    |  1006 +
 lib/i915/perf-configs/oa-bdw.xml              | 15653 ++++++++++++++++
 lib/i915/perf-configs/oa-bxt.xml              |  9595 ++++++++++
 lib/i915/perf-configs/oa-cflgt2.xml           | 10866 +++++++++++
 lib/i915/perf-configs/oa-cflgt3.xml           | 10933 +++++++++++
 lib/i915/perf-configs/oa-chv.xml              |  9757 ++++++++++
 lib/i915/perf-configs/oa-cnl.xml              | 10411 ++++++++++
 lib/i915/perf-configs/oa-glk.xml              |  9346 +++++++++
 lib/i915/perf-configs/oa-hsw.xml              |  4615 +++++
 lib/i915/perf-configs/oa-icl.xml              | 11869 ++++++++++++
 lib/i915/perf-configs/oa-kblgt2.xml           | 10866 +++++++++++
 lib/i915/perf-configs/oa-kblgt3.xml           | 10933 +++++++++++
 lib/i915/perf-configs/oa-lkf.xml              | 11803 ++++++++++++
 lib/i915/perf-configs/oa-sklgt2.xml           | 11895 ++++++++++++
 lib/i915/perf-configs/oa-sklgt3.xml           | 10933 +++++++++++
 lib/i915/perf-configs/oa-sklgt4.xml           | 10956 +++++++++++
 lib/i915/perf-configs/oa-tgl.xml              |  8491 +++++++++
 lib/i915/perf-configs/oa_guid_registry.py     |    73 +
 lib/i915/perf-configs/perf-codegen.py         |   850 +
 lib/i915/perf-configs/update-guids.py         |   231 +
 lib/i915/perf.c                               |   583 +
 lib/i915/perf.h                               |   240 +
 lib/i915/perf_data.h                          |   118 +
 lib/i915/perf_data_reader.c                   |   383 +
 lib/i915/perf_data_reader.h                   |   107 +
 lib/intel_chipset.h                           |     1 +
 lib/intel_device_info.c                       |     8 +-
 lib/meson.build                               |    68 +
 lib/tests/i915_perf_data_alignment.c          |    40 +
 lib/tests/meson.build                         |     1 +
 tools/i915-perf/i915_perf_configs.c           |   277 +
 tools/i915-perf/i915_perf_control.c           |   133 +
 tools/i915-perf/i915_perf_reader.c            |   279 +
 tools/i915-perf/i915_perf_recorder.c          |  1052 ++
 tools/i915-perf/i915_perf_recorder_commands.h |    39 +
 tools/i915-perf/meson.build                   |    22 +
 tools/meson.build                             |     1 +
 41 files changed, 174911 insertions(+), 1 deletion(-)
 create mode 100644 lib/i915-perf.pc.in
 create mode 100644 lib/i915/perf-configs/README.md
 create mode 100644 lib/i915/perf-configs/codegen.py
 create mode 100644 lib/i915/perf-configs/guids.xml
 create mode 100755 lib/i915/perf-configs/mdapi-xml-convert.py
 create mode 100644 lib/i915/perf-configs/oa-bdw.xml
 create mode 100644 lib/i915/perf-configs/oa-bxt.xml
 create mode 100644 lib/i915/perf-configs/oa-cflgt2.xml
 create mode 100644 lib/i915/perf-configs/oa-cflgt3.xml
 create mode 100644 lib/i915/perf-configs/oa-chv.xml
 create mode 100644 lib/i915/perf-configs/oa-cnl.xml
 create mode 100644 lib/i915/perf-configs/oa-glk.xml
 create mode 100644 lib/i915/perf-configs/oa-hsw.xml
 create mode 100644 lib/i915/perf-configs/oa-icl.xml
 create mode 100644 lib/i915/perf-configs/oa-kblgt2.xml
 create mode 100644 lib/i915/perf-configs/oa-kblgt3.xml
 create mode 100644 lib/i915/perf-configs/oa-lkf.xml
 create mode 100644 lib/i915/perf-configs/oa-sklgt2.xml
 create mode 100644 lib/i915/perf-configs/oa-sklgt3.xml
 create mode 100644 lib/i915/perf-configs/oa-sklgt4.xml
 create mode 100644 lib/i915/perf-configs/oa-tgl.xml
 create mode 100644 lib/i915/perf-configs/oa_guid_registry.py
 create mode 100755 lib/i915/perf-configs/perf-codegen.py
 create mode 100755 lib/i915/perf-configs/update-guids.py
 create mode 100644 lib/i915/perf.c
 create mode 100644 lib/i915/perf.h
 create mode 100644 lib/i915/perf_data.h
 create mode 100644 lib/i915/perf_data_reader.c
 create mode 100644 lib/i915/perf_data_reader.h
 create mode 100644 lib/tests/i915_perf_data_alignment.c
 create mode 100644 tools/i915-perf/i915_perf_configs.c
 create mode 100644 tools/i915-perf/i915_perf_control.c
 create mode 100644 tools/i915-perf/i915_perf_reader.c
 create mode 100644 tools/i915-perf/i915_perf_recorder.c
 create mode 100644 tools/i915-perf/i915_perf_recorder_commands.h
 create mode 100644 tools/i915-perf/meson.build

--
2.25.0
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [igt-dev] [PATCH i-g-t 1/6] lib/intel_chipset: identify Elkhart Lake
  2020-02-17 14:21 [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
@ 2020-02-17 14:21 ` Lionel Landwerlin
  2020-02-18 18:47   ` Chris Wilson
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 3/6] lib/i915: Add support for loading perf configurations Lionel Landwerlin
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 16+ messages in thread
From: Lionel Landwerlin @ 2020-02-17 14:21 UTC (permalink / raw)
  To: igt-dev

We'll need to identify this platform for performance tools.

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
 lib/intel_chipset.h     | 1 +
 lib/intel_device_info.c | 8 +++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/lib/intel_chipset.h b/lib/intel_chipset.h
index 2bd57f4f..929fac53 100644
--- a/lib/intel_chipset.h
+++ b/lib/intel_chipset.h
@@ -71,6 +71,7 @@ struct intel_device_info {
 	bool is_cometlake : 1;
 	bool is_cannonlake : 1;
 	bool is_icelake : 1;
+	bool is_elkhartlake : 1;
 	bool is_tigerlake : 1;
 	const char *codename;
 };
diff --git a/lib/intel_device_info.c b/lib/intel_device_info.c
index 4f96577d..07eeb7c5 100644
--- a/lib/intel_device_info.c
+++ b/lib/intel_device_info.c
@@ -309,6 +309,12 @@ static const struct intel_device_info intel_icelake_info = {
 	.codename = "icelake"
 };
 
+static const struct intel_device_info intel_elkhartlake_info = {
+	.gen = BIT(10),
+	.is_elkhartlake = true,
+	.codename = ""
+};
+
 static const struct intel_device_info intel_tigerlake_info = {
 	.gen = BIT(11),
 	.is_tigerlake = true,
@@ -394,7 +400,7 @@ static const struct pci_id_match intel_device_match[] = {
 
 	INTEL_ICL_11_IDS(&intel_icelake_info),
 
-	INTEL_EHL_IDS(&intel_icelake_info),
+	INTEL_EHL_IDS(&intel_elkhartlake_info),
 
 	INTEL_TGL_12_IDS(&intel_tigerlake_info),
 
-- 
2.25.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [igt-dev] [PATCH i-g-t 3/6] lib/i915: Add support for loading perf configurations
  2020-02-17 14:21 [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 1/6] lib/intel_chipset: identify Elkhart Lake Lionel Landwerlin
@ 2020-02-17 14:21 ` Lionel Landwerlin
  2020-02-18 18:52   ` Chris Wilson
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool Lionel Landwerlin
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 16+ messages in thread
From: Lionel Landwerlin @ 2020-02-17 14:21 UTC (permalink / raw)
  To: igt-dev

---
 lib/i915/perf.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/i915/perf.h |  2 ++
 2 files changed, 77 insertions(+)

diff --git a/lib/i915/perf.c b/lib/i915/perf.c
index 8aaf8e61..f23a9b12 100644
--- a/lib/i915/perf.c
+++ b/lib/i915/perf.c
@@ -433,3 +433,78 @@ intel_perf_add_metric_set(struct intel_perf *perf,
 {
 	igt_list_add_tail(&metric_set->link, &perf->metric_sets);
 }
+
+static void
+load_metric_set_config(struct intel_perf_metric_set *metric_set, int drm_fd)
+{
+	struct drm_i915_perf_oa_config config;
+	uint64_t config_id = 0;
+
+	memset(&config, 0, sizeof(config));
+
+	memcpy(config.uuid, metric_set->hw_config_guid, sizeof(config.uuid));
+
+	config.n_mux_regs = metric_set->n_mux_regs;
+	config.mux_regs_ptr = (uintptr_t) metric_set->mux_regs;
+
+	config.n_boolean_regs = metric_set->n_b_counter_regs;
+	config.boolean_regs_ptr = (uintptr_t) metric_set->b_counter_regs;
+
+	config.n_flex_regs = metric_set->n_flex_regs;
+	config.flex_regs_ptr = (uintptr_t) metric_set->flex_regs;
+
+	while (ioctl(drm_fd, DRM_IOCTL_I915_PERF_ADD_CONFIG, &config) < 0 &&
+	       (errno == EAGAIN || errno == EINTR));
+
+	metric_set->perf_oa_metrics_set = config_id;
+}
+
+void
+intel_perf_load_perf_configs(struct intel_perf *perf, int drm_fd)
+{
+	int drm_card = get_card_for_fd(drm_fd);
+	struct dirent *entry;
+	char metrics_path[128];
+	DIR *metrics_dir;
+	struct intel_perf_metric_set *metric_set;
+
+	snprintf(metrics_path, sizeof(metrics_path),
+		 "/sys/class/drm/card%d/metrics", drm_card);
+	metrics_dir = opendir(metrics_path);
+	if (!metrics_dir)
+		return;
+
+	while ((entry = readdir(metrics_dir))) {
+		char *metric_id_path;
+		uint64_t metric_id;
+
+		if (entry->d_type != DT_DIR)
+			continue;
+
+		asprintf(&metric_id_path, "%s/%s/id",
+			 metrics_path, entry->d_name);
+
+		if (!read_file_uint64(metric_id_path, &metric_id)) {
+			free(metric_id_path);
+			continue;
+		}
+
+		free(metric_id_path);
+
+		igt_list_for_each_entry(metric_set, &perf->metric_sets, link) {
+			if (!strcmp(metric_set->hw_config_guid, entry->d_name)) {
+				metric_set->perf_oa_metrics_set = metric_id;
+				break;
+			}
+		}
+	}
+
+	closedir(metrics_dir);
+
+	igt_list_for_each_entry(metric_set, &perf->metric_sets, link) {
+		if (metric_set->perf_oa_metrics_set)
+			continue;
+
+		load_metric_set_config(metric_set, drm_fd);
+	}
+}
diff --git a/lib/i915/perf.h b/lib/i915/perf.h
index 7dfa0472..246d06cf 100644
--- a/lib/i915/perf.h
+++ b/lib/i915/perf.h
@@ -220,6 +220,8 @@ void intel_perf_add_logical_counter(struct intel_perf *perf,
 void intel_perf_add_metric_set(struct intel_perf *perf,
 			       struct intel_perf_metric_set *metric_set);
 
+void intel_perf_load_perf_configs(struct intel_perf *perf, int drm_fd);
+
 #ifdef __cplusplus
 };
 #endif
-- 
2.25.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool
  2020-02-17 14:21 [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 1/6] lib/intel_chipset: identify Elkhart Lake Lionel Landwerlin
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 3/6] lib/i915: Add support for loading perf configurations Lionel Landwerlin
@ 2020-02-17 14:21 ` Lionel Landwerlin
  2020-02-18 18:57   ` Chris Wilson
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 5/6] lib: add i915 perf data reader Lionel Landwerlin
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 16+ messages in thread
From: Lionel Landwerlin @ 2020-02-17 14:21 UTC (permalink / raw)
  To: igt-dev

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
 lib/i915-perf.pc.in                           |    1 +
 lib/i915/perf_data.h                          |  118 ++
 lib/meson.build                               |    1 +
 lib/tests/i915_perf_data_alignment.c          |   40 +
 lib/tests/meson.build                         |    1 +
 tools/i915-perf/i915_perf_control.c           |  133 +++
 tools/i915-perf/i915_perf_recorder.c          | 1052 +++++++++++++++++
 tools/i915-perf/i915_perf_recorder_commands.h |   39 +
 tools/i915-perf/meson.build                   |   11 +
 9 files changed, 1396 insertions(+)
 create mode 100644 lib/i915/perf_data.h
 create mode 100644 lib/tests/i915_perf_data_alignment.c
 create mode 100644 tools/i915-perf/i915_perf_control.c
 create mode 100644 tools/i915-perf/i915_perf_recorder.c
 create mode 100644 tools/i915-perf/i915_perf_recorder_commands.h

diff --git a/lib/i915-perf.pc.in b/lib/i915-perf.pc.in
index e72efdc3..8cfa3dbe 100644
--- a/lib/i915-perf.pc.in
+++ b/lib/i915-perf.pc.in
@@ -6,5 +6,6 @@ includedir=@includedir@
 Name: i915-perf
 Description: i915 perf library
 Version: @version@
+Requires: libdrm
 Libs: -L${libdir} -li915_perf
 Cflags: -I${includedir}/i915-perf
diff --git a/lib/i915/perf_data.h b/lib/i915/perf_data.h
new file mode 100644
index 00000000..fb3556f6
--- /dev/null
+++ b/lib/i915/perf_data.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 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 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.
+ */
+
+#ifndef PERF_DATA_H
+#define PERF_DATA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <i915_drm.h>
+
+/* The structures below are embedded in the i915-perf stream so as to
+ * provide metadata. The types used in the
+ * drm_i915_perf_record_header.type are defined in
+ * intel_perf_record_type.
+ */
+
+#include <stdint.h>
+
+enum intel_perf_record_type {
+	/* Start at 65536, which is pretty safe since after 3years the
+	 * kernel hasn't defined more than 3 entries.
+	 */
+
+	INTEL_PERF_RECORD_TYPE_VERSION = 1 << 16,
+
+	/* intel_perf_record_device_info */
+	INTEL_PERF_RECORD_TYPE_DEVICE_INFO,
+
+	/* intel_perf_record_device_topology */
+	INTEL_PERF_RECORD_TYPE_DEVICE_TOPOLOGY,
+
+	/* intel_perf_record_timestamp_correlation */
+	INTEL_PERF_RECORD_TYPE_TIMESTAMP_CORRELATION,
+};
+
+/* This structure cannot ever change. */
+struct intel_perf_record_version {
+	/* Version of the i915-perf file recording format (effectively
+	 * versioning this file).
+	 */
+	uint32_t version;
+
+#define INTEL_PERF_RECORD_VERSION (1)
+
+	uint32_t pad;
+} __attribute__((packed));
+
+struct intel_perf_record_device_info {
+	/* Frequency of the timestamps in the records. */
+	uint64_t timestamp_frequency;
+
+	/* PCI ID */
+	uint32_t device_id;
+
+	/* Stepping */
+	uint32_t device_revision;
+
+	/* GT min/max frequencies */
+	uint32_t gt_min_frequency;
+	uint32_t gt_max_frequency;
+
+	/* Engine */
+	uint32_t engine_class;
+	uint32_t engine_instance;
+
+	/* enum drm_i915_oa_format */
+	uint32_t oa_format;
+
+	/* Metric set name */
+	char metric_set_name[256];
+
+	/* Configuration identifier */
+	char metric_set_uuid[40];
+
+	uint32_t pad;
+ } __attribute__((packed));
+
+/* Topology as reported by i915 (variable length, aligned by the
+ * recorder). */
+struct intel_perf_record_device_topology {
+	struct drm_i915_query_topology_info topology;
+};
+
+/* Timestamp correlation between CPU/GPU. */
+struct intel_perf_record_timestamp_correlation {
+	/* In CLOCK_MONOTONIC */
+	uint64_t cpu_timestamp;
+
+	/* Engine timestamp associated with the OA unit */
+	uint64_t gpu_timestamp;
+} __attribute__((packed));
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* PERF_DATA_H */
diff --git a/lib/meson.build b/lib/meson.build
index 4de1b211..1fe621ec 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -218,6 +218,7 @@ install_headers(
   'igt_list.h',
   'intel_chipset.h',
   'i915/perf.h',
+  'i915/perf_data.h',
   subdir : 'i915-perf'
 )
 
diff --git a/lib/tests/i915_perf_data_alignment.c b/lib/tests/i915_perf_data_alignment.c
new file mode 100644
index 00000000..8c14e0d0
--- /dev/null
+++ b/lib/tests/i915_perf_data_alignment.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 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 (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_core.h"
+
+#include "igt_tests_common.h"
+
+#include "i915/perf_data.h"
+
+#define is_aligned(s) ((sizeof(s) % 8) == 0)
+
+igt_main
+{
+	igt_subtest("alignment") {
+		internal_assert(is_aligned(struct intel_perf_record_version));
+		internal_assert(is_aligned(struct intel_perf_record_device_info));
+		internal_assert(is_aligned(struct intel_perf_record_timestamp_correlation));
+	}
+}
diff --git a/lib/tests/meson.build b/lib/tests/meson.build
index e5066665..6cd8cb0e 100644
--- a/lib/tests/meson.build
+++ b/lib/tests/meson.build
@@ -16,6 +16,7 @@ lib_tests = [
 	'igt_simulation',
 	'igt_stats',
 	'igt_subtest_group',
+	'i915_perf_data_alignment',
 ]
 
 lib_fail_tests = [
diff --git a/tools/i915-perf/i915_perf_control.c b/tools/i915-perf/i915_perf_control.c
new file mode 100644
index 00000000..a8d0d30f
--- /dev/null
+++ b/tools/i915-perf/i915_perf_control.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 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 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 <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "i915_perf_recorder_commands.h"
+
+static void
+usage(const char *name)
+{
+	fprintf(stdout,
+		"Usage: %s [options]\n"
+		"\n"
+		"     --help,               -h         Print this screen\n"
+		"     --command-fifo,       -f <path>  Path to a command fifo\n"
+		"     --dump,               -d <path>  Write a content of circular buffer to path\n",
+		name);
+}
+
+int
+main(int argc, char *argv[])
+{
+	const struct option long_options[] = {
+		{"help",                       no_argument, 0, 'h'},
+		{"dump",                 required_argument, 0, 'd'},
+		{"command-fifo",         required_argument, 0, 'f'},
+		{"quit",                       no_argument, 0, 'q'},
+		{0, 0, 0, 0}
+	};
+	const char *command_fifo = I915_PERF_RECORD_FIFO_PATH, *dump_file = NULL;
+	FILE *command_fifo_file;
+	int opt;
+	bool quit = false;
+
+	while ((opt = getopt_long(argc, argv, "hd:f:q", long_options, NULL)) != -1) {
+		switch (opt) {
+		case 'h':
+			usage(argv[0]);
+			return EXIT_SUCCESS;
+		case 'd':
+			dump_file = optarg;
+			break;
+		case 'f':
+			command_fifo = optarg;
+			break;
+		case 'q':
+			quit = true;
+			break;
+		default:
+			fprintf(stderr, "Internal error: "
+				"unexpected getopt value: %d\n", opt);
+			usage(argv[0]);
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (!command_fifo)
+		return EXIT_FAILURE;
+
+	command_fifo_file = fopen(command_fifo, "r+");
+	if (!command_fifo_file) {
+		fprintf(stderr, "Unable to open command file\n");
+		return EXIT_FAILURE;
+	}
+
+	if (dump_file) {
+		if (dump_file[0] == '/') {
+			uint32_t total_len =
+				sizeof(struct recorder_command_base) + strlen(dump_file) + 1;
+			struct {
+				struct recorder_command_base base;
+				struct recorder_command_dump dump;
+			} *data = malloc(total_len);
+
+			data->base.command = RECORDER_COMMAND_DUMP;
+			data->base.size = total_len;
+			snprintf((char *) data->dump.path, strlen(dump_file) + 1, "%s", dump_file);
+
+			fwrite(data, total_len, 1, command_fifo_file);
+		} else {
+			char *cwd = get_current_dir_name();
+			uint32_t path_len = strlen(cwd) + 1 + strlen(dump_file) + 1;
+			uint32_t total_len = sizeof(struct recorder_command_base) + path_len;
+			struct {
+				struct recorder_command_base base;
+				struct recorder_command_dump dump;
+			} *data = malloc(total_len);
+
+			data->base.command = RECORDER_COMMAND_DUMP;
+			data->base.size = total_len;
+			snprintf((char *) data->dump.path, path_len, "%s/%s", cwd, dump_file);
+
+			fwrite(data, total_len, 1, command_fifo_file);
+		}
+	}
+
+	if (quit) {
+		struct recorder_command_base base = {
+			.command = RECORDER_COMMAND_QUIT,
+			.size = sizeof(base),
+		};
+
+		fwrite(&base, sizeof(base), 1, command_fifo_file);
+	}
+
+	fclose(command_fifo_file);
+
+	return EXIT_SUCCESS;
+}
diff --git a/tools/i915-perf/i915_perf_recorder.c b/tools/i915-perf/i915_perf_recorder.c
new file mode 100644
index 00000000..760cabf1
--- /dev/null
+++ b/tools/i915-perf/i915_perf_recorder.c
@@ -0,0 +1,1052 @@
+/*
+ * Copyright (C) 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 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <i915_drm.h>
+
+#include "igt_core.h"
+#include "intel_chipset.h"
+#include "i915/perf.h"
+#include "i915/perf_data.h"
+
+#include "i915_perf_recorder_commands.h"
+
+#define ALIGN(v, a) (((v) + (a)-1) & ~((a)-1))
+#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0]))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+struct circular_buffer {
+	char   *data;
+	size_t  allocated_size;
+	size_t  size;
+	size_t  beginpos;
+	size_t  endpos;
+};
+
+struct chunk {
+	char *data;
+	size_t len;
+};
+
+static size_t
+circular_available_size(const struct circular_buffer *buffer)
+{
+	assert(buffer->size <= buffer->allocated_size);
+	return buffer->allocated_size - buffer->size;
+}
+
+static void
+get_chunks(struct chunk *chunks, struct circular_buffer *buffer, bool write, size_t len)
+{
+	size_t offset = write ? buffer->endpos : buffer->beginpos;
+
+	if (write)
+		assert(circular_available_size(buffer) >= len);
+	else
+		assert(buffer->size >= len);
+
+	chunks[0].data = &buffer->data[offset];
+
+	if ((offset + len) > buffer->allocated_size) {
+		chunks[0].len = buffer->allocated_size - offset;
+		chunks[1].data = buffer->data;
+		chunks[1].len = len - (buffer->allocated_size - offset);
+	} else {
+		chunks[0].len = len;
+		chunks[1].data = NULL;
+		chunks[1].len = 0;
+	}
+}
+
+static ssize_t
+circular_buffer_read(void *c, char *buf, size_t size)
+{
+	struct circular_buffer *buffer = c;
+	struct chunk chunks[2];
+
+	if (buffer->size < size)
+		return -1;
+
+	get_chunks(chunks, buffer, false, size);
+
+	memcpy(buf, chunks[0].data, chunks[0].len);
+	memcpy(buf + chunks[0].len, chunks[1].data, chunks[1].len);
+	buffer->beginpos = (buffer->beginpos + size) % buffer->allocated_size;
+	buffer->size -= size;
+
+	return size;
+}
+
+static size_t
+peek_item_size(struct circular_buffer *buffer)
+{
+	struct drm_i915_perf_record_header header;
+	struct chunk chunks[2];
+
+	if (!buffer->size)
+		return 0;
+
+	assert(buffer->size >= sizeof(header));
+
+	get_chunks(chunks, buffer, false, sizeof(header));
+	memcpy(&header, chunks[0].data, chunks[0].len);
+	memcpy((char *) &header + chunks[0].len, chunks[1].data, chunks[1].len);
+
+	return header.size;
+}
+
+static void
+circular_shrink(struct circular_buffer *buffer, size_t size)
+{
+	size_t shrank = 0, item_size;
+
+	assert(size <= buffer->allocated_size);
+
+	while (shrank < size && buffer->size > (item_size = peek_item_size(buffer))) {
+		assert(item_size > 0 && item_size <= buffer->allocated_size);
+
+		buffer->beginpos = (buffer->beginpos + item_size) % buffer->allocated_size;
+		buffer->size -= item_size;
+
+		shrank += item_size;
+	}
+}
+
+static ssize_t
+circular_buffer_write(void *c, const char *buf, size_t _size)
+{
+	struct circular_buffer *buffer = c;
+	size_t size = _size;
+
+	while (size) {
+		size_t avail = circular_available_size(buffer), item_size;
+		struct chunk chunks[2];
+
+		/* Make space in the buffer if there is too much data. */
+		if (avail < size)
+			circular_shrink(buffer, size - avail);
+
+		item_size = MIN(circular_available_size(buffer), size);
+
+		get_chunks(chunks, buffer, true, item_size);
+
+		memcpy(chunks[0].data, buf, chunks[0].len);
+		memcpy(chunks[1].data, buf + chunks[0].len, chunks[1].len);
+
+		buf += item_size;
+		size -= item_size;
+
+		buffer->endpos = (buffer->endpos + item_size) % buffer->allocated_size;
+		buffer->size += item_size;
+	}
+
+	return _size;
+}
+
+static int
+circular_buffer_seek(void *c, off64_t *offset, int whence)
+{
+	return -1;
+}
+
+static int
+circular_buffer_close(void *c)
+{
+	return 0;
+}
+
+cookie_io_functions_t circular_buffer_functions = {
+	.read  = circular_buffer_read,
+	.write = circular_buffer_write,
+	.seek  = circular_buffer_seek,
+	.close = circular_buffer_close,
+};
+
+
+static bool
+read_file_uint64(const char *file, uint64_t *value)
+{
+	char buf[32];
+	int fd, n;
+
+	fd = open(file, 0);
+	if (fd < 0)
+		return false;
+	n = read(fd, buf, sizeof (buf) - 1);
+	close(fd);
+	if (n < 0)
+		return false;
+
+	buf[n] = '\0';
+	*value = strtoull(buf, 0, 0);
+
+	return true;
+}
+
+static uint32_t
+read_device_param(const char *stem, int id, const char *param)
+{
+	char *name;
+	int ret = asprintf(&name, "/sys/class/drm/%s%u/device/%s", stem, id, param);
+	uint64_t value;
+	bool success;
+
+	assert(ret != -1);
+
+	success = read_file_uint64(name, &value);
+	free(name);
+
+	return success ? value : 0;
+}
+
+static int
+find_intel_render_node(void)
+{
+	for (int i = 128; i < (128 + 16); i++) {
+		if (read_device_param("renderD", i, "vendor") == 0x8086)
+			return i;
+	}
+
+	return -1;
+}
+
+static int
+open_render_node(uint32_t *devid)
+{
+	char *name;
+	int ret;
+	int fd;
+
+	int render = find_intel_render_node();
+	if (render < 0)
+		return -1;
+
+	ret = asprintf(&name, "/dev/dri/renderD%u", render);
+	assert(ret != -1);
+
+	*devid = read_device_param("renderD", render, "device");
+
+	fd = open(name, O_RDWR);
+	free(name);
+
+	return fd;
+}
+
+static uint32_t
+oa_exponent_for_period(uint64_t device_timestamp_frequency, double period)
+{
+	uint64_t period_ns = 1000 * 1000 * 1000 * period;
+	uint64_t device_periods[32];
+
+	for (uint32_t i = 0; i < ARRAY_SIZE(device_periods); i++)
+		device_periods[i] = 1000000000ull * (1u << i) / device_timestamp_frequency;
+
+	for (uint32_t i = 1; i < ARRAY_SIZE(device_periods); i++) {
+		if (period_ns >= device_periods[i - 1] &&
+		    period_ns < device_periods[i]) {
+			if ((device_periods[i] - period_ns) >
+			    (period_ns - device_periods[i - 1]))
+				return i - 1;
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+static int
+perf_ioctl(int fd, unsigned long request, void *arg)
+{
+	int ret;
+
+	do {
+		ret = ioctl(fd, request, arg);
+	} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+
+	return ret;
+}
+
+static uint64_t
+get_device_timestamp_frequency(const struct intel_device_info *devinfo, int drm_fd)
+{
+	drm_i915_getparam_t gp;
+	int timestamp_frequency;
+
+	gp.param = I915_PARAM_CS_TIMESTAMP_FREQUENCY;
+	gp.value = &timestamp_frequency;
+	if (perf_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0)
+		return timestamp_frequency;
+
+	if (devinfo->gen > 9) {
+		fprintf(stderr, "Unable to query timestamp frequency from i915, please update kernel.\n");
+		return 0;
+	}
+
+	fprintf(stderr, "Warning: unable to query timestamp frequency from i915, guessing values...\n");
+
+	if (devinfo->gen <= 8)
+		return 12500000;
+	if (devinfo->is_broxton)
+		return 19200000;
+	return 12000000;
+}
+
+struct recording_context {
+	int drm_fd;
+	int perf_fd;
+
+	uint32_t devid;
+	uint64_t timestamp_frequency;
+
+	const struct intel_device_info *devinfo;
+
+	struct drm_i915_query_topology_info *topology;
+	uint32_t topology_size;
+
+	struct intel_perf *perf;
+	struct intel_perf_metric_set *metric_set;
+
+	uint32_t oa_exponent;
+
+	struct circular_buffer circular_buffer;
+	FILE *output_stream;
+
+	const char *command_fifo;
+	int command_fifo_fd;
+};
+
+static int
+perf_open(struct recording_context *ctx)
+{
+	uint64_t properties[DRM_I915_PERF_PROP_MAX * 2];
+	struct drm_i915_perf_open_param param;
+	int p = 0, stream_fd;
+
+	properties[p++] = DRM_I915_PERF_PROP_SAMPLE_OA;
+	properties[p++] = true;
+
+	properties[p++] = DRM_I915_PERF_PROP_OA_METRICS_SET;
+	properties[p++] = ctx->metric_set->perf_oa_metrics_set;
+
+	properties[p++] = DRM_I915_PERF_PROP_OA_FORMAT;
+	properties[p++] = ctx->metric_set->perf_oa_format;
+
+	properties[p++] = DRM_I915_PERF_PROP_OA_EXPONENT;
+	properties[p++] = ctx->oa_exponent;
+
+	memset(&param, 0, sizeof(param));
+	param.flags = 0;
+	param.flags |= I915_PERF_FLAG_FD_CLOEXEC | I915_PERF_FLAG_FD_NONBLOCK;
+	param.properties_ptr = (uintptr_t)properties;
+	param.num_properties = p / 2;
+
+	stream_fd = perf_ioctl(ctx->drm_fd, DRM_IOCTL_I915_PERF_OPEN, &param);
+	return stream_fd;
+}
+
+static bool quit = false;
+
+static void
+sigint_handler(int val)
+{
+	quit = true;
+}
+
+static bool
+write_version(FILE *output, struct recording_context *ctx)
+{
+	struct intel_perf_record_version version = {
+		.version = INTEL_PERF_RECORD_VERSION,
+	};
+	struct drm_i915_perf_record_header header = {
+		.type = INTEL_PERF_RECORD_TYPE_VERSION,
+		.size = sizeof(header) + sizeof(version),
+	};
+
+	if (fwrite(&header, sizeof(header), 1, output) != 1)
+		return false;
+
+	if (fwrite(&version, sizeof(version), 1, output) != 1)
+		return false;
+
+	return true;
+}
+
+static bool
+write_header(FILE *output, struct recording_context *ctx)
+{
+	struct intel_perf_record_device_info info = {
+		.timestamp_frequency = ctx->timestamp_frequency,
+		.device_id = ctx->perf->devinfo.devid,
+		.device_revision = ctx->perf->devinfo.revision,
+		.gt_min_frequency = ctx->perf->devinfo.gt_min_freq,
+		.gt_max_frequency = ctx->perf->devinfo.gt_max_freq,
+		.oa_format = ctx->metric_set->perf_oa_format,
+		.engine_class = I915_ENGINE_CLASS_RENDER,
+		.engine_instance = 0,
+	};
+	struct drm_i915_perf_record_header header = {
+		.type = INTEL_PERF_RECORD_TYPE_DEVICE_INFO,
+		.size = sizeof(header) + sizeof(info),
+	};
+
+	snprintf(info.metric_set_name, sizeof(info.metric_set_name),
+		 "%s", ctx->metric_set->symbol_name);
+	snprintf(info.metric_set_uuid, sizeof(info.metric_set_uuid),
+		 "%s", ctx->metric_set->hw_config_guid);
+
+	if (fwrite(&header, sizeof(header), 1, output) != 1)
+		return false;
+
+	if (fwrite(&info, sizeof(info), 1, output) != 1)
+		return false;
+
+	return true;
+}
+
+static struct drm_i915_query_topology_info *
+get_topology(int drm_fd, uint32_t *topology_size)
+{
+	struct drm_i915_query query = {};
+	struct drm_i915_query_topology_info *topo_info;
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_TOPOLOGY_INFO,
+	};
+	int ret;
+
+	query.num_items = 1;
+	query.items_ptr = (uintptr_t) &item;
+
+	/* Maybe not be available on older kernels. */
+	ret = perf_ioctl(drm_fd, DRM_IOCTL_I915_QUERY, &query);
+	if (ret < 0)
+		return NULL;
+
+	assert(item.length > 0);
+	*topology_size = item.length;
+	topo_info = malloc(item.length);
+	item.data_ptr = (uintptr_t) topo_info;
+
+	ret = perf_ioctl(drm_fd, DRM_IOCTL_I915_QUERY, &query);
+	assert(ret == 0);
+
+	return topo_info;
+}
+
+static bool
+write_topology(FILE *output, struct recording_context *ctx)
+{
+	struct drm_i915_perf_record_header header = {
+		.type = INTEL_PERF_RECORD_TYPE_DEVICE_TOPOLOGY,
+	};
+	char pad[8] = { 0, };
+
+	header.size = sizeof(header) + ctx->topology_size;
+	if (fwrite(&header, sizeof(header), 1, output) != 1)
+		return false;
+
+	if (fwrite(ctx->topology, ctx->topology_size, 1, output) != 1)
+		return false;
+
+	/* Align the size to align all other packets to 8 bytes. */
+	if (ctx->topology_size % 8) {
+		if (fwrite(pad, ctx->topology_size % 8, 1, output) != 1)
+			return false;
+	}
+
+	return true;
+}
+
+static bool
+write_i915_perf_data(FILE *output, int perf_fd)
+{
+	ssize_t ret;
+	char data[4096];
+
+	while ((ret = read(perf_fd, data, sizeof(data))) > 0 ||
+	       errno == EINTR) {
+		if (fwrite(data, ret, 1, output) != 1)
+			return false;
+	}
+
+	return true;
+}
+
+static uint64_t timespec_diff(struct timespec *begin,
+			      struct timespec *end)
+{
+	return 1000000000ull * (end->tv_sec - begin->tv_sec) + end->tv_nsec - begin->tv_nsec;
+}
+
+static clock_t correlation_clock_id = CLOCK_MONOTONIC;
+
+static bool
+get_correlation_timestamps(struct intel_perf_record_timestamp_correlation *corr, int drm_fd)
+{
+	struct drm_i915_reg_read reg_read;
+	struct {
+		struct timespec cpu_ts_begin;
+		struct timespec cpu_ts_end;
+		uint64_t gpu_ts;
+	} attempts[3];
+	uint32_t best = 0;
+
+#define RENDER_RING_TIMESTAMP 0x2358
+
+        reg_read.offset = RENDER_RING_TIMESTAMP | I915_REG_READ_8B_WA;
+
+	/* Gather 3 correlations. */
+	for (uint32_t i = 0; i < ARRAY_SIZE(attempts); i++) {
+		clock_gettime(correlation_clock_id, &attempts[i].cpu_ts_begin);
+		if (perf_ioctl(drm_fd, DRM_IOCTL_I915_REG_READ, &reg_read) < 0)
+			return false;
+		clock_gettime(correlation_clock_id, &attempts[i].cpu_ts_end);
+
+		attempts[i].gpu_ts = reg_read.val;
+	}
+
+	/* Now select the best. */
+	for (uint32_t i = 1; i < ARRAY_SIZE(attempts); i++) {
+		if (timespec_diff(&attempts[i].cpu_ts_begin,
+				  &attempts[i].cpu_ts_end) <
+		    timespec_diff(&attempts[best].cpu_ts_begin,
+				  &attempts[best].cpu_ts_end))
+			best = i;
+	}
+
+	corr->cpu_timestamp =
+		(attempts[best].cpu_ts_begin.tv_sec * 1000000000ull +
+		 attempts[best].cpu_ts_begin.tv_nsec) +
+		timespec_diff(&attempts[best].cpu_ts_begin,
+			      &attempts[best].cpu_ts_end) / 2;
+	corr->gpu_timestamp = attempts[best].gpu_ts;
+
+	return true;
+}
+
+static bool
+write_saved_correlation_timestamps(FILE *output,
+				   const struct intel_perf_record_timestamp_correlation *corr)
+{
+	struct drm_i915_perf_record_header header = {
+		.type = INTEL_PERF_RECORD_TYPE_TIMESTAMP_CORRELATION,
+		.size = sizeof(header) + sizeof(*corr),
+	};
+
+	if (fwrite(&header, sizeof(header), 1, output) != 1)
+		return false;
+
+	if (fwrite(corr, sizeof(*corr), 1, output) != 1)
+		return false;
+
+	return true;
+}
+
+static bool
+write_correlation_timestamps(FILE *output, int drm_fd)
+{
+	struct intel_perf_record_timestamp_correlation corr;
+
+	if (!get_correlation_timestamps(&corr, drm_fd))
+		return false;
+
+	return write_saved_correlation_timestamps(output, &corr);
+}
+
+static void
+read_command_file(struct recording_context *ctx)
+{
+	struct recorder_command_base header;
+	ssize_t ret = read(ctx->command_fifo_fd, &header, sizeof(header));
+
+	if (ret < 0)
+		return;
+
+	switch (header.command) {
+	case RECORDER_COMMAND_DUMP: {
+		uint32_t len = header.size - sizeof(header), offset = 0;
+		struct recorder_command_dump *dump = malloc(len);
+		FILE *file;
+
+		while (offset < len &&
+		       ((ret = read(ctx->command_fifo_fd,
+				    (void *) dump + offset, len - offset)) > 0
+			|| errno == EAGAIN)) {
+			if (ret > 0)
+				offset += ret;
+		}
+
+		fprintf(stdout, "Writing circular buffer to %s\n", dump->path);
+
+		file = fopen((const char *) dump->path, "w+");
+		if (file) {
+			struct chunk chunks[2];
+
+			fflush(ctx->output_stream);
+			get_chunks(chunks, &ctx->circular_buffer,
+				   false, ctx->circular_buffer.size);
+
+			if (!write_version(file, ctx) ||
+			    !write_header(file, ctx) ||
+			    !write_topology(file, ctx) ||
+			    fwrite(chunks[0].data, chunks[0].len, 1, file) != 1 ||
+			    (chunks[1].len > 0 &&
+			     fwrite(chunks[1].data, chunks[1].len, 1, file) != 1) ||
+			    !write_correlation_timestamps(file, ctx->drm_fd)) {
+				fprintf(stderr, "Unable to write circular buffer data in file '%s'\n",
+					dump->path);
+			}
+			fclose(file);
+		} else
+			fprintf(stderr, "Unable to write dump file '%s'\n", dump->path);
+
+		free(dump);
+		break;
+	}
+	case RECORDER_COMMAND_QUIT:
+		quit = true;
+		break;
+	default:
+		fprintf(stderr, "Unknown command 0x%x\n", header.command);
+		break;
+	}
+}
+
+static void
+print_metric_sets(const struct intel_perf *perf)
+{
+	struct intel_perf_metric_set *metric_set;
+	uint32_t longest_name = 0;
+
+	igt_list_for_each_entry(metric_set, &perf->metric_sets, link) {
+		longest_name = MAX(longest_name, strlen(metric_set->symbol_name));
+	}
+
+	igt_list_for_each_entry(metric_set, &perf->metric_sets, link) {
+		fprintf(stdout, "%s:%*s%s\n",
+			metric_set->symbol_name,
+			(int) (longest_name - strlen(metric_set->symbol_name) + 1), " ",
+			metric_set->name);
+	}
+}
+
+static void
+print_metric_set_counters(const struct intel_perf_metric_set *metric_set)
+{
+	uint32_t longest_name = 0;
+
+	for (uint32_t i = 0; i < metric_set->n_counters; i++) {
+		longest_name = MAX(longest_name, strlen(metric_set->counters[i].name));
+	}
+
+	fprintf(stdout, "%s (%s):\n", metric_set->symbol_name, metric_set->name);
+	for (uint32_t i = 0; i < metric_set->n_counters; i++) {
+		struct intel_perf_logical_counter *counter = &metric_set->counters[i];
+
+		fprintf(stdout, "  %s:%*s%s\n",
+			counter->name,
+			(int)(longest_name - strlen(counter->name) + 1), " ",
+			counter->desc);
+	}
+}
+
+static void
+print_metric_sets_counters(struct intel_perf *perf)
+{
+	struct intel_perf_metric_set *metric_set;
+
+	igt_list_for_each_entry(metric_set, &perf->metric_sets, link)
+		print_metric_set_counters(metric_set);
+}
+
+static void
+usage(const char *name)
+{
+	fprintf(stdout,
+		"Usage: %s [options]\n"
+		"Recording tool for i915-perf.\n"
+		"\n"
+		"     --help,               -h          Print this screen\n"
+		"     --correlation-period, -c <value>  Time period of timestamp correlation in seconds\n"
+		"                                       (default = 1.0)\n"
+		"     --perf-period,        -p <value>  Time period of i915-perf reports in seconds\n"
+		"                                       (default = 0.001)\n"
+		"     --metric,             -m <value>  i915 metric to sample with (use value=list to list all metrics)\n"
+		"     --counters,           -C          List counters for a given metric and exit\n"
+		"     --size,               -s <value>  Size of circular buffer to use in kilobytes\n"
+		"                                       If specified, a maximum amount of <value> data will\n"
+		"                                       be recorded.\n"
+		"     --command-fifo,       -f <path>   Path to a command fifo, implies circular buffer\n"
+		"                                       (To use with i915-perf-control)\n"
+		"     --output,             -o <path>   Output file (default = i915_perf.record)\n"
+		"     --cpu-clock,          -k <path>   Cpu clock to use for correlations\n"
+		"                                       Values: boot, mono, mono_raw (default = mono)\n",
+		name);
+}
+
+static void
+teardown_recording_context(struct recording_context *ctx)
+{
+	if (ctx->topology)
+		free(ctx->topology);
+
+	if (ctx->perf)
+		intel_perf_free(ctx->perf);
+
+	if (ctx->command_fifo)
+		unlink(ctx->command_fifo);
+	if (ctx->command_fifo_fd != -1)
+		close(ctx->command_fifo_fd);
+
+	if (ctx->output_stream)
+		fclose(ctx->output_stream);
+
+	free(ctx->circular_buffer.data);
+
+	if (ctx->perf_fd != -1)
+		close(ctx->perf_fd);
+	if (ctx->drm_fd != -1)
+		close(ctx->drm_fd);
+}
+
+int
+main(int argc, char *argv[])
+{
+	const struct option long_options[] = {
+		{"help",                       no_argument, 0, 'h'},
+		{"correlation-period",   required_argument, 0, 'c'},
+		{"perf-period",          required_argument, 0, 'p'},
+		{"metric",               required_argument, 0, 'm'},
+		{"counters",                   no_argument, 0, 'C'},
+		{"output",               required_argument, 0, 'o'},
+		{"size",                 required_argument, 0, 's'},
+		{"command-fifo",         required_argument, 0, 'f'},
+		{"cpu-clock",            required_argument, 0, 'k'},
+		{0, 0, 0, 0}
+	};
+	const struct {
+		clock_t id;
+		const char *name;
+	} clock_names[] = {
+		{ CLOCK_BOOTTIME,      "boot" },
+		{ CLOCK_MONOTONIC,     "mono" },
+		{ CLOCK_MONOTONIC_RAW, "mono_raw" },
+	};
+	double corr_period = 1.0, perf_period = 0.001;
+	const char *metric_name = NULL, *output_file = "i915_perf.record";
+	struct intel_perf_metric_set *metric_set;
+	struct intel_perf_record_timestamp_correlation initial_correlation;
+	struct timespec now;
+	uint64_t corr_period_ns, poll_time_ns;
+	uint32_t circular_size = 0;
+	int opt;
+	bool list_counters = false;
+	FILE *output = NULL;
+	struct recording_context ctx = {
+		.drm_fd = -1,
+		.perf_fd = -1,
+
+		.command_fifo = I915_PERF_RECORD_FIFO_PATH,
+		.command_fifo_fd = -1,
+	};
+
+	while ((opt = getopt_long(argc, argv, "hc:p:m:Co:s:f:k:", long_options, NULL)) != -1) {
+		switch (opt) {
+		case 'h':
+			usage(argv[0]);
+			return EXIT_SUCCESS;
+		case 'c':
+			corr_period = atof(optarg);
+			break;
+		case 'p':
+			perf_period = atof(optarg);
+			break;
+		case 'm':
+			metric_name = optarg;
+			break;
+		case 'C':
+			list_counters = true;
+			break;
+		case 'o':
+			output_file = optarg;
+			break;
+		case 's':
+			circular_size = MAX(8, atoi(optarg)) * 1024;
+			break;
+		case 'f':
+			ctx.command_fifo = optarg;
+			circular_size = 8 * 1024 * 1024;
+			break;
+		case 'k': {
+			bool found = false;
+			for (uint32_t i = 0; i < ARRAY_SIZE(clock_names); i++) {
+				if (!strcmp(clock_names[i].name, optarg)) {
+					correlation_clock_id = clock_names[i].id;
+					found = true;
+					break;
+				}
+			}
+			if (!found) {
+				fprintf(stderr, "Unknown clock name '%s'\n", optarg);
+				return EXIT_FAILURE;
+			}
+			break;
+		}
+		default:
+			fprintf(stderr, "Internal error: "
+				"unexpected getopt value: %d\n", opt);
+			usage(argv[0]);
+			return EXIT_FAILURE;
+		}
+	}
+
+	ctx.drm_fd = open_render_node(&ctx.devid);
+	if (ctx.drm_fd < 0) {
+		fprintf(stderr, "Unable to open device.\n");
+		return EXIT_FAILURE;
+	}
+
+	ctx.devinfo = intel_get_device_info(ctx.devid);
+	if (!ctx.devinfo) {
+		fprintf(stderr, "No device info found.\n");
+		goto fail;
+	}
+
+	fprintf(stdout, "Device name=%s gen=%i gt=%i id=0x%x\n",
+		ctx.devinfo->codename, ctx.devinfo->gen, ctx.devinfo->gt, ctx.devid);
+
+	ctx.topology = get_topology(ctx.drm_fd, &ctx.topology_size);
+	if (!ctx.topology) {
+		fprintf(stderr, "Unable to retrieve GPU topology (requires kernel 4.17+).\n");
+		goto fail;
+	}
+
+	ctx.perf = intel_perf_for_fd(ctx.drm_fd);
+	if (!ctx.perf) {
+		fprintf(stderr, "No perf data found.\n");
+		goto fail;
+	}
+
+	intel_perf_load_perf_configs(ctx.perf, ctx.drm_fd);
+
+	if (metric_name) {
+		if (!strcmp(metric_name, "list")) {
+			print_metric_sets(ctx.perf);
+			return EXIT_SUCCESS;
+		}
+
+		igt_list_for_each_entry(metric_set, &ctx.perf->metric_sets, link) {
+			if (!strcasecmp(metric_set->symbol_name, metric_name)) {
+				ctx.metric_set = metric_set;
+				break;
+			}
+		}
+	}
+
+	if (list_counters) {
+		if (!ctx.metric_set)
+			print_metric_sets_counters(ctx.perf);
+		else
+			print_metric_set_counters(ctx.metric_set);
+		teardown_recording_context(&ctx);
+		return EXIT_SUCCESS;
+	}
+
+	if (!ctx.metric_set) {
+		if (!metric_name)
+			fprintf(stderr, "No metric set specified.\n");
+		else
+			fprintf(stderr, "Unknown metric set '%s'.\n", metric_name);
+		print_metric_sets(ctx.perf);
+		goto fail;
+	}
+
+	intel_perf_load_perf_configs(ctx.perf, ctx.drm_fd);
+
+	ctx.timestamp_frequency = get_device_timestamp_frequency(ctx.devinfo, ctx.drm_fd);
+
+	signal(SIGINT, sigint_handler);
+
+	if (ctx.command_fifo) {
+		if (mkfifo(ctx.command_fifo,
+			   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != 0) {
+			fprintf(stderr, "Unable to create command fifo '%s': %s\n",
+				ctx.command_fifo, strerror(errno));
+			goto fail;
+		}
+
+		ctx.command_fifo_fd = open(ctx.command_fifo, O_RDWR);
+		if (ctx.command_fifo_fd < 0) {
+			fprintf(stderr, "Unable to open command fifo '%s': %s\n",
+				ctx.command_fifo, strerror(errno));
+			goto fail;
+		}
+	}
+
+	if (circular_size) {
+		ctx.circular_buffer.allocated_size = circular_size;
+		ctx.circular_buffer.data = malloc(circular_size);
+		if (!ctx.circular_buffer.data) {
+			fprintf(stderr, "Unable to allocate circular buffer\n");
+			goto fail;
+		}
+
+		ctx.output_stream = fopencookie(&ctx.circular_buffer, "w+",
+						circular_buffer_functions);
+		if (!ctx.output_stream) {
+			fprintf(stderr, "Unable to create circular buffer\n");
+			goto fail;
+		}
+
+		if (!get_correlation_timestamps(&initial_correlation, ctx.drm_fd)) {
+			fprintf(stderr, "Unable to correlation timestamps\n");
+			goto fail;
+		}
+
+		write_correlation_timestamps(ctx.output_stream, ctx.drm_fd);
+		fprintf(stdout,
+			"Recoding in internal circular buffer.\n"
+			"Use i915-perf-control to snapshot into file.\n");
+	} else {
+		output = fopen(output_file, "w+");
+		if (!output) {
+			fprintf(stderr, "Unable to open output file '%s'\n",
+				output_file);
+			goto fail;
+		}
+
+		if (!write_version(output, &ctx) ||
+		    !write_header(output, &ctx) ||
+		    !write_topology(output, &ctx) ||
+		    !write_correlation_timestamps(output, ctx.drm_fd)) {
+			fprintf(stderr, "Unable to write header in file '%s'\n",
+				output_file);
+			goto fail;
+		}
+
+		ctx.output_stream = output;
+		fprintf(stdout, "Writing recoding to %s\n", output_file);
+	}
+
+	if (ctx.metric_set->perf_oa_metrics_set == 0) {
+		fprintf(stderr,
+			"Unable to load performance configuration, consider running:\n"
+			"   sysctl dev.i915.perf_stream_paranoid=0\n");
+		goto fail;
+	}
+
+	ctx.oa_exponent = oa_exponent_for_period(ctx.timestamp_frequency, perf_period);
+	fprintf(stdout, "Opening perf stream with metric_id=%lu oa_exponent=%u\n",
+		ctx.metric_set->perf_oa_metrics_set, ctx.oa_exponent);
+
+	ctx.perf_fd = perf_open(&ctx);
+	if (ctx.perf_fd < 0) {
+		fprintf(stderr, "Unable to open i915 perf stream: %s\n",
+			strerror(errno));
+		goto fail;
+	}
+
+	corr_period_ns = corr_period * 1000000000ul;
+	poll_time_ns = corr_period_ns;
+
+	while (!quit) {
+		struct pollfd pollfd[2] = {
+			{         ctx.perf_fd, POLLIN, 0 },
+			{ ctx.command_fifo_fd, POLLIN, 0 },
+		};
+		uint64_t elapsed_ns;
+		int ret;
+
+		igt_gettime(&now);
+		ret = poll(pollfd, ctx.command_fifo_fd != -1 ? 2 : 1, poll_time_ns / 1000000);
+		if (ret < 0 && errno != EINTR) {
+			fprintf(stderr, "Failed to poll i915-perf stream: %s\n",
+				strerror(errno));
+			break;
+		}
+
+		if (ret > 0) {
+			if (pollfd[0].revents & POLLIN) {
+				if (!write_i915_perf_data(ctx.output_stream, ctx.perf_fd)) {
+					fprintf(stderr, "Failed to write i915-perf data: %s\n",
+						strerror(errno));
+					break;
+				}
+			}
+
+			if (pollfd[1].revents & POLLIN) {
+				read_command_file(&ctx);
+			}
+		}
+
+		elapsed_ns = igt_nsec_elapsed(&now);
+		if (elapsed_ns > poll_time_ns) {
+			poll_time_ns = corr_period_ns;
+			if (!write_correlation_timestamps(ctx.output_stream, ctx.drm_fd)) {
+				fprintf(stderr,
+					"Failed to write i915 timestamp correlation data: %s\n",
+					strerror(errno));
+				break;
+			}
+		} else {
+			poll_time_ns -= elapsed_ns;
+		}
+	}
+
+	fprintf(stdout, "Exiting...\n");
+
+	if (!write_correlation_timestamps(ctx.output_stream, ctx.drm_fd)) {
+		fprintf(stderr,
+			"Failed to write final i915 timestamp correlation data: %s\n",
+			strerror(errno));
+	}
+
+	teardown_recording_context(&ctx);
+
+	return EXIT_SUCCESS;
+
+ fail:
+	teardown_recording_context(&ctx);
+
+	return EXIT_FAILURE;
+}
diff --git a/tools/i915-perf/i915_perf_recorder_commands.h b/tools/i915-perf/i915_perf_recorder_commands.h
new file mode 100644
index 00000000..4855d80f
--- /dev/null
+++ b/tools/i915-perf/i915_perf_recorder_commands.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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 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 <stdint.h>
+
+#define I915_PERF_RECORD_FIFO_PATH "/tmp/.i915-perf-record"
+
+enum recorder_command {
+	RECORDER_COMMAND_DUMP = 1,
+	RECORDER_COMMAND_QUIT,
+};
+
+struct recorder_command_base {
+	uint32_t command;
+	uint32_t size;
+};
+
+struct recorder_command_dump {
+	uint8_t path[0];
+};
diff --git a/tools/i915-perf/meson.build b/tools/i915-perf/meson.build
index 0ebdd185..9884dfd9 100644
--- a/tools/i915-perf/meson.build
+++ b/tools/i915-perf/meson.build
@@ -3,3 +3,14 @@ executable('i915-perf-configs',
            include_directories: inc,
            dependencies: [lib_igt_chipset, lib_igt_i915_perf],
            install: true)
+
+executable('i915-perf-recorder',
+           [ 'i915_perf_recorder.c' ],
+           include_directories: inc,
+           dependencies: [lib_igt, lib_igt_i915_perf],
+           install: true)
+
+executable('i915-perf-control',
+           [ 'i915_perf_control.c' ],
+           include_directories: inc,
+           install: true)
-- 
2.25.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [igt-dev] [PATCH i-g-t 5/6] lib: add i915 perf data reader
  2020-02-17 14:21 [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
                   ` (2 preceding siblings ...)
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool Lionel Landwerlin
@ 2020-02-17 14:21 ` Lionel Landwerlin
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 6/6] tools: add i915-perf-reader Lionel Landwerlin
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: Lionel Landwerlin @ 2020-02-17 14:21 UTC (permalink / raw)
  To: igt-dev

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
 lib/i915/perf_data_reader.c | 383 ++++++++++++++++++++++++++++++++++++
 lib/i915/perf_data_reader.h | 107 ++++++++++
 lib/meson.build             |   2 +
 3 files changed, 492 insertions(+)
 create mode 100644 lib/i915/perf_data_reader.c
 create mode 100644 lib/i915/perf_data_reader.h

diff --git a/lib/i915/perf_data_reader.c b/lib/i915/perf_data_reader.c
new file mode 100644
index 00000000..3b05a2e5
--- /dev/null
+++ b/lib/i915/perf_data_reader.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 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 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <i915_drm.h>
+
+#include "intel_chipset.h"
+#include "perf.h"
+#include "perf_data_reader.h"
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+static inline bool
+oa_report_ctx_is_valid(const struct intel_perf_devinfo *devinfo,
+		       const uint8_t *_report)
+{
+	const uint32_t *report = (const uint32_t *) _report;
+
+	if (devinfo->gen < 8) {
+		return false; /* TODO */
+	} else if (devinfo->gen == 8) {
+		return report[0] & (1ul << 25);
+	} else if (devinfo->gen > 8) {
+		return report[0] & (1ul << 16);
+	}
+
+	return false;
+}
+
+static uint32_t
+oa_report_ctx_id(const struct intel_perf_devinfo *devinfo, const uint8_t *report)
+{
+	if (!oa_report_ctx_is_valid(devinfo, report))
+		return 0xffffffff;
+	return ((const uint32_t *) report)[2];
+}
+
+static inline uint64_t
+oa_report_timestamp(const uint8_t *report)
+{
+	return ((const uint32_t *)report)[1];
+}
+
+static void
+append_record(struct intel_perf_data_reader *reader,
+	      const struct drm_i915_perf_record_header *header)
+{
+	if (reader->n_records >= reader->n_allocated_records) {
+		reader->n_allocated_records = MAX(100, 2 * reader->n_allocated_records);
+		reader->records =
+			(const struct drm_i915_perf_record_header **)
+			realloc((void *) reader->records,
+				reader->n_allocated_records *
+				sizeof(struct drm_i915_perf_record_header *));
+		assert(reader->records);
+	}
+
+	reader->records[reader->n_records++] = header;
+}
+
+static void
+append_timestamp_correlation(struct intel_perf_data_reader *reader,
+			     const struct intel_perf_record_timestamp_correlation *corr)
+{
+	if (reader->n_correlations >= reader->n_allocated_correlations) {
+		reader->n_allocated_correlations = MAX(100, 2 * reader->n_allocated_correlations);
+		reader->correlations =
+			(const struct intel_perf_record_timestamp_correlation **)
+			realloc((void *) reader->correlations,
+				reader->n_allocated_correlations *
+				sizeof(*reader->correlations));
+		assert(reader->correlations);
+	}
+
+	reader->correlations[reader->n_correlations++] = corr;
+}
+
+static struct intel_perf_metric_set *
+find_metric_set(struct intel_perf *perf, const char *symbol_name)
+{
+	struct intel_perf_metric_set *metric_set;
+
+	igt_list_for_each_entry(metric_set, &perf->metric_sets, link) {
+		if (!strcmp(symbol_name, metric_set->symbol_name))
+			return metric_set;
+	}
+
+	return NULL;
+}
+
+static void
+init_devinfo(struct intel_perf_devinfo *perf_devinfo,
+	     const struct intel_device_info *devinfo,
+	     uint32_t devid,
+	     uint64_t timestamp_frequency)
+{
+	perf_devinfo->devid = devid;
+	perf_devinfo->gen = devinfo->gen;
+	perf_devinfo->timestamp_frequency = timestamp_frequency;
+}
+
+static bool
+parse_data(struct intel_perf_data_reader *reader)
+{
+	const struct intel_perf_record_device_info *record_info;
+	const struct intel_perf_record_device_topology *record_topology;
+	const struct intel_device_info *devinfo;
+	const uint8_t *end = reader->mmap_data + reader->mmap_size;
+	const uint8_t *iter = reader->mmap_data;
+
+	while (iter < end) {
+		const struct drm_i915_perf_record_header *header =
+			(const struct drm_i915_perf_record_header *) iter;
+
+		switch (header->type) {
+		case DRM_I915_PERF_RECORD_SAMPLE:
+			append_record(reader, header);
+			break;
+
+		case DRM_I915_PERF_RECORD_OA_REPORT_LOST:
+		case DRM_I915_PERF_RECORD_OA_BUFFER_LOST:
+			assert(header->size == sizeof(*header));
+			break;
+
+		case INTEL_PERF_RECORD_TYPE_VERSION: {
+			struct intel_perf_record_version *version =
+				(struct intel_perf_record_version*) (header + 1);
+			if (version->version != INTEL_PERF_RECORD_VERSION) {
+				snprintf(reader->error_msg, sizeof(reader->error_msg),
+					 "Unsupported recording version (%u, expected %u)",
+					 version->version, INTEL_PERF_RECORD_VERSION);
+				return false;
+			}
+			break;
+		}
+
+		case INTEL_PERF_RECORD_TYPE_DEVICE_INFO: {
+			reader->record_info = header + 1;
+			assert(header->size == (sizeof(struct intel_perf_record_device_info) +
+						sizeof(*header)));
+			break;
+		}
+
+		case INTEL_PERF_RECORD_TYPE_DEVICE_TOPOLOGY: {
+			reader->record_topology = header + 1;
+			break;
+		}
+
+		case INTEL_PERF_RECORD_TYPE_TIMESTAMP_CORRELATION: {
+			append_timestamp_correlation(reader,
+						     (const struct intel_perf_record_timestamp_correlation *) (header + 1));
+			break;
+		}
+		}
+
+		iter += header->size;
+	}
+
+	if (!reader->record_info ||
+	    !reader->record_topology) {
+		snprintf(reader->error_msg, sizeof(reader->error_msg),
+			 "Invalid file, missing device or topology info");
+		return false;
+	}
+
+	record_info = reader->record_info;
+	record_topology = reader->record_topology;
+
+	devinfo = intel_get_device_info(record_info->device_id);
+	if (!devinfo) {
+		snprintf(reader->error_msg, sizeof(reader->error_msg),
+			 "Recording occured on unsupported device (0x%x)",
+			 record_info->device_id);
+		return false;
+	}
+
+	init_devinfo(&reader->devinfo, devinfo,
+		     record_info->device_id,
+		     record_info->timestamp_frequency);
+	reader->perf = intel_perf_for_devinfo(record_info->device_id,
+					      record_info->device_revision,
+					      record_info->timestamp_frequency,
+					      record_info->gt_min_frequency,
+					      record_info->gt_max_frequency,
+					      &record_topology->topology);
+
+	reader->metric_set_name = record_info->metric_set_name;
+	reader->metric_set_uuid = record_info->metric_set_uuid;
+	reader->metric_set = find_metric_set(reader->perf, record_info->metric_set_name);
+
+	return true;
+}
+
+static uint64_t
+correlate_gpu_timestamp(struct intel_perf_data_reader *reader,
+			uint64_t gpu_ts)
+{
+	/* OA reports only have the lower 32bits of the timestamp
+	 * register, while our correlation data has the whole 36bits.
+	 * Try to figure what portion of the correlation data the
+	 * 32bit timestamp belongs to.
+	 */
+	uint64_t mask = 0xffffffff;
+	int corr_idx = -1;
+
+	for (uint32_t i = 0; i < reader->n_correlation_chunks; i++) {
+		if (gpu_ts >= (reader->correlation_chunks[i].gpu_ts_begin & mask) &&
+		    gpu_ts <= (reader->correlation_chunks[i].gpu_ts_end & mask)) {
+			corr_idx = reader->correlation_chunks[i].idx;
+			break;
+		}
+	}
+
+	/* Not found? Assume prior to the first timestamp correlation.
+	 */
+	if (corr_idx < 0) {
+		return reader->correlations[0]->cpu_timestamp -
+			((reader->correlations[0]->gpu_timestamp & mask) - gpu_ts) *
+			(reader->correlations[1]->cpu_timestamp - reader->correlations[0]->cpu_timestamp) /
+			(reader->correlations[1]->gpu_timestamp - reader->correlations[0]->gpu_timestamp);
+	}
+
+	for (uint32_t i = corr_idx; i < (reader->n_correlations - 1); i++) {
+		if (gpu_ts >= (reader->correlations[i]->gpu_timestamp & mask) &&
+		    gpu_ts < (reader->correlations[i + 1]->gpu_timestamp & mask)) {
+			return reader->correlations[i]->cpu_timestamp +
+				(gpu_ts - (reader->correlations[i]->gpu_timestamp & mask)) *
+				(reader->correlations[i + 1]->cpu_timestamp - reader->correlations[i]->cpu_timestamp) /
+				(reader->correlations[i + 1]->gpu_timestamp - reader->correlations[i]->gpu_timestamp);
+		}
+	}
+
+	/* This is a bit harsh, but the recording tool should ensure we have
+	 * sampling points on either side of the bag of OA reports.
+	 */
+	assert(0);
+}
+
+static void
+append_timeline_event(struct intel_perf_data_reader *reader,
+		      uint64_t ts_start, uint64_t ts_end,
+		      uint32_t record_start, uint32_t record_end,
+		      uint32_t hw_id)
+{
+	if (reader->n_timelines >= reader->n_allocated_timelines) {
+		reader->n_allocated_timelines = MAX(100, 2 * reader->n_allocated_timelines);
+		reader->timelines =
+			(struct intel_perf_timeline_item *)
+			realloc((void *) reader->timelines,
+				reader->n_allocated_timelines *
+				sizeof(*reader->timelines));
+		assert(reader->timelines);
+	}
+
+	reader->timelines[reader->n_timelines].ts_start = ts_start;
+	reader->timelines[reader->n_timelines].ts_end = ts_end;
+	reader->timelines[reader->n_timelines].cpu_ts_start =
+		correlate_gpu_timestamp(reader, ts_start);
+	reader->timelines[reader->n_timelines].cpu_ts_end =
+		correlate_gpu_timestamp(reader, ts_end);
+	reader->timelines[reader->n_timelines].record_start = record_start;
+	reader->timelines[reader->n_timelines].record_end = record_end;
+	reader->timelines[reader->n_timelines].hw_id = hw_id;
+	reader->n_timelines++;
+}
+
+static void
+generate_cpu_events(struct intel_perf_data_reader *reader)
+{
+	uint32_t last_header_idx = 0;
+	const struct drm_i915_perf_record_header *last_header = reader->records[0];
+
+	for (uint32_t i = 1; i < reader->n_records; i++) {
+		const struct drm_i915_perf_record_header *current_header =
+			reader->records[i];
+		const uint8_t *start_report = (const uint8_t *) (last_header + 1),
+			*end_report = (const uint8_t *) (current_header + 1);
+		uint32_t last_ctx_id = oa_report_ctx_id(&reader->devinfo, start_report),
+			current_ctx_id = oa_report_ctx_id(&reader->devinfo, end_report);
+		uint64_t gpu_ts_start = oa_report_timestamp(start_report),
+			gpu_ts_end = oa_report_timestamp(end_report);
+
+		if (last_ctx_id == current_ctx_id)
+			continue;
+
+		append_timeline_event(reader, gpu_ts_start, gpu_ts_end, last_header_idx, i, last_ctx_id);
+
+		last_header = current_header;
+		last_header_idx = i;
+	}
+}
+
+static void
+compute_correlation_chunks(struct intel_perf_data_reader *reader)
+{
+	uint64_t mask = ~(0xffffffff);
+	uint32_t last_idx = 0;
+	uint64_t last_ts = reader->correlations[last_idx]->gpu_timestamp;
+
+	for (uint32_t i = 0; i < reader->n_correlations; i++) {
+		if (!reader->n_correlation_chunks ||
+		    (last_ts & mask) != (reader->correlations[i]->gpu_timestamp & mask)) {
+			assert(reader->n_correlation_chunks < ARRAY_SIZE(reader->correlation_chunks));
+			reader->correlation_chunks[reader->n_correlation_chunks].gpu_ts_begin = last_ts;
+			reader->correlation_chunks[reader->n_correlation_chunks].gpu_ts_end = last_ts | ~mask;
+			reader->correlation_chunks[reader->n_correlation_chunks].idx = last_idx;
+			last_ts = reader->correlation_chunks[reader->n_correlation_chunks].gpu_ts_end + 1;
+			last_idx = i;
+			reader->n_correlation_chunks++;
+		}
+	}
+}
+
+bool
+intel_perf_data_reader_init(struct intel_perf_data_reader *reader,
+			    int perf_file_fd)
+{
+        struct stat st;
+        if (fstat(perf_file_fd, &st) != 0) {
+		snprintf(reader->error_msg, sizeof(reader->error_msg),
+			 "Unable to access file (%s)", strerror(errno));
+		return false;
+	}
+
+	memset(reader, 0, sizeof(*reader));
+
+	reader->mmap_size = st.st_size;
+	reader->mmap_data = (const uint8_t *) mmap(NULL, st.st_size,
+						   PROT_READ, MAP_PRIVATE,
+						   perf_file_fd, 0);
+	if (reader->mmap_data == MAP_FAILED) {
+		snprintf(reader->error_msg, sizeof(reader->error_msg),
+			 "Unable to access file (%s)", strerror(errno));
+		return false;
+	}
+
+	if (!parse_data(reader))
+		return false;
+
+	compute_correlation_chunks(reader);
+	generate_cpu_events(reader);
+
+	return true;
+}
+
+void
+intel_perf_data_reader_fini(struct intel_perf_data_reader *reader)
+{
+	intel_perf_free(reader->perf);
+	free(reader->records);
+	free(reader->timelines);
+	free(reader->correlations);
+	munmap((void *)reader->mmap_data, reader->mmap_size);
+}
diff --git a/lib/i915/perf_data_reader.h b/lib/i915/perf_data_reader.h
new file mode 100644
index 00000000..88268b46
--- /dev/null
+++ b/lib/i915/perf_data_reader.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 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 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.
+ */
+
+#ifndef PERF_DATA_READER_H
+#define PERF_DATA_READER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Helper to read a i915-perf recording. */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "perf.h"
+#include "perf_data.h"
+
+struct intel_device_info;
+
+struct intel_perf_timeline_item {
+	uint64_t ts_start;
+	uint64_t ts_end;
+	uint64_t cpu_ts_start;
+	uint64_t cpu_ts_end;
+
+	/* Offsets into intel_perf_data_reader.records */
+	uint32_t record_start;
+	uint32_t record_end;
+
+	uint32_t hw_id;
+
+	/* User associated data with a given item on the i915 perf
+	 * timeline.
+	 */
+	void *user_data;
+};
+
+struct intel_perf_data_reader {
+	/* Array of pointers into the mmapped i915 perf file. */
+	const struct drm_i915_perf_record_header **records;
+	uint32_t n_records;
+	uint32_t n_allocated_records;
+
+	/**/
+	struct intel_perf_timeline_item *timelines;
+	uint32_t n_timelines;
+	uint32_t n_allocated_timelines;
+
+	/**/
+	const struct intel_perf_record_timestamp_correlation **correlations;
+	uint32_t n_correlations;
+	uint32_t n_allocated_correlations;
+
+	struct {
+		uint64_t gpu_ts_begin;
+		uint64_t gpu_ts_end;
+		uint32_t idx;
+	} correlation_chunks[4];
+	uint32_t n_correlation_chunks;
+
+	const char *metric_set_uuid;
+	const char *metric_set_name;
+
+	struct intel_perf_devinfo devinfo;
+
+	struct intel_perf *perf;
+	struct intel_perf_metric_set *metric_set;
+
+	char error_msg[256];
+
+	/**/
+	const void *record_info;
+	const void *record_topology;
+
+	const uint8_t *mmap_data;
+	size_t mmap_size;
+};
+
+bool intel_perf_data_reader_init(struct intel_perf_data_reader *reader,
+				 int perf_file_fd);
+void intel_perf_data_reader_fini(struct intel_perf_data_reader *reader);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* PERF_DATA_READER_H */
diff --git a/lib/meson.build b/lib/meson.build
index 1fe621ec..05c3b767 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -173,6 +173,7 @@ lib_igt_perf = declare_dependency(link_with : lib_igt_perf_build,
 
 i915_perf_files = [
   'i915/perf.c',
+  'i915/perf_data_reader.c',
 ]
 
 i915_perf_hardware = [
@@ -219,6 +220,7 @@ install_headers(
   'intel_chipset.h',
   'i915/perf.h',
   'i915/perf_data.h',
+  'i915/perf_data_reader.h',
   subdir : 'i915-perf'
 )
 
-- 
2.25.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [igt-dev] [PATCH i-g-t 6/6] tools: add i915-perf-reader
  2020-02-17 14:21 [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
                   ` (3 preceding siblings ...)
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 5/6] lib: add i915 perf data reader Lionel Landwerlin
@ 2020-02-17 14:21 ` Lionel Landwerlin
  2020-02-17 14:27 ` [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
  2020-02-18 18:46 ` Chris Wilson
  6 siblings, 0 replies; 16+ messages in thread
From: Lionel Landwerlin @ 2020-02-17 14:21 UTC (permalink / raw)
  To: igt-dev

Reading & printing out data recorded with i915-perf-recorder.

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
 lib/i915/perf.c                    |  73 ++++++++
 lib/i915/perf.h                    |  11 ++
 tools/i915-perf/i915_perf_reader.c | 279 +++++++++++++++++++++++++++++
 tools/i915-perf/meson.build        |   6 +
 4 files changed, 369 insertions(+)
 create mode 100644 tools/i915-perf/i915_perf_reader.c

diff --git a/lib/i915/perf.c b/lib/i915/perf.c
index f23a9b12..0872ecc7 100644
--- a/lib/i915/perf.c
+++ b/lib/i915/perf.c
@@ -508,3 +508,76 @@ intel_perf_load_perf_configs(struct intel_perf *perf, int drm_fd)
 		load_metric_set_config(metric_set, drm_fd);
 	}
 }
+
+static void
+accumulate_uint32(const uint32_t *report0,
+                  const uint32_t *report1,
+                  uint64_t *deltas)
+{
+	*deltas += (uint32_t)(*report1 - *report0);
+}
+
+static void
+accumulate_uint40(int a_index,
+                  const uint32_t *report0,
+                  const uint32_t *report1,
+                  uint64_t *deltas)
+{
+	const uint8_t *high_bytes0 = (uint8_t *)(report0 + 40);
+	const uint8_t *high_bytes1 = (uint8_t *)(report1 + 40);
+	uint64_t high0 = (uint64_t)(high_bytes0[a_index]) << 32;
+	uint64_t high1 = (uint64_t)(high_bytes1[a_index]) << 32;
+	uint64_t value0 = report0[a_index + 4] | high0;
+	uint64_t value1 = report1[a_index + 4] | high1;
+	uint64_t delta;
+
+	if (value0 > value1)
+		delta = (1ULL << 40) + value1 - value0;
+	else
+		delta = value1 - value0;
+
+	*deltas += delta;
+}
+
+void intel_perf_accumulate_reports(struct intel_perf_accumulator *acc,
+				   int oa_format,
+				   const struct drm_i915_perf_record_header *record0,
+				   const struct drm_i915_perf_record_header *record1)
+{
+	const uint32_t *start = (const uint32_t *)(record0 + 1);
+	const uint32_t *end = (const uint32_t *)(record1 + 1);
+	uint64_t *deltas = acc->deltas;
+	int idx = 0;
+	int i;
+
+	memset(acc, 0, sizeof(*acc));
+
+	switch (oa_format) {
+	case I915_OA_FORMAT_A32u40_A4u32_B8_C8:
+		accumulate_uint32(start + 1, end + 1, deltas + idx++); /* timestamp */
+		accumulate_uint32(start + 3, end + 3, deltas + idx++); /* clock */
+
+		/* 32x 40bit A counters... */
+		for (i = 0; i < 32; i++)
+			accumulate_uint40(i, start, end, deltas + idx++);
+
+		/* 4x 32bit A counters... */
+		for (i = 0; i < 4; i++)
+			accumulate_uint32(start + 36 + i, end + 36 + i, deltas + idx++);
+
+		/* 8x 32bit B counters + 8x 32bit C counters... */
+		for (i = 0; i < 16; i++)
+			accumulate_uint32(start + 48 + i, end + 48 + i, deltas + idx++);
+		break;
+
+	case I915_OA_FORMAT_A45_B8_C8:
+		accumulate_uint32(start + 1, end + 1, deltas); /* timestamp */
+
+		for (i = 0; i < 61; i++)
+			accumulate_uint32(start + 3 + i, end + 3 + i, deltas + 1 + i);
+		break;
+	default:
+		assert(0);
+	}
+
+}
diff --git a/lib/i915/perf.h b/lib/i915/perf.h
index 246d06cf..00ac2f6f 100644
--- a/lib/i915/perf.h
+++ b/lib/i915/perf.h
@@ -114,6 +114,11 @@ typedef enum {
 	INTEL_PERF_LOGICAL_COUNTER_UNIT_MAX
 } intel_perf_logical_counter_unit_t;
 
+/* Hold deltas of raw performance counters. */
+struct intel_perf_accumulator {
+#define INTEL_PERF_MAX_RAW_OA_COUNTERS 62
+	uint64_t deltas[INTEL_PERF_MAX_RAW_OA_COUNTERS];
+};
 
 struct intel_perf;
 struct intel_perf_metric_set;
@@ -202,6 +207,7 @@ struct intel_perf {
 	struct intel_perf_devinfo devinfo;
 };
 
+struct drm_i915_perf_record_header;
 struct drm_i915_query_topology_info;
 
 struct intel_perf *intel_perf_for_fd(int drm_fd);
@@ -222,6 +228,11 @@ void intel_perf_add_metric_set(struct intel_perf *perf,
 
 void intel_perf_load_perf_configs(struct intel_perf *perf, int drm_fd);
 
+void intel_perf_accumulate_reports(struct intel_perf_accumulator *acc,
+				   int oa_format,
+				   const struct drm_i915_perf_record_header *record0,
+				   const struct drm_i915_perf_record_header *record1);
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/tools/i915-perf/i915_perf_reader.c b/tools/i915-perf/i915_perf_reader.c
new file mode 100644
index 00000000..fd944b45
--- /dev/null
+++ b/tools/i915-perf/i915_perf_reader.c
@@ -0,0 +1,279 @@
+/*
+ * 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 "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 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;
+
+	fprintf(stdout, "Recorded on device=0x%x gen=%i\n",
+		reader.devinfo.devid, 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..bc2d8f39 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_i915_perf,
+           install: true)
-- 
2.25.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf
  2020-02-17 14:21 [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
                   ` (4 preceding siblings ...)
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 6/6] tools: add i915-perf-reader Lionel Landwerlin
@ 2020-02-17 14:27 ` Lionel Landwerlin
  2020-02-18 18:46 ` Chris Wilson
  6 siblings, 0 replies; 16+ messages in thread
From: Lionel Landwerlin @ 2020-02-17 14:27 UTC (permalink / raw)
  To: igt-dev

On 17/02/2020 16:21, Lionel Landwerlin wrote:
> Hi all,
>
> i915-perf was added about 3 or 4 years ago (first released in 4.13).
> At the time a new GPUTop [1] open source project was created to show
> case the usefulness of the data exposed through i915-perf. Initially
> GPUTop is entirely driven by traces coming from the GPU. Some effort
> came along later to use perf traces (mostly tracepoints) to complete
> the picture and connect the dots between GPU HW contexts and the
> processes that triggered those contexts running.
>
> About a year later Valve showcased another tool GPUvis [2]. GPUvis is
> currently only driven by traces recorded on the CPU (ftrace on Linux)
> but it's UI is undeniably better, showing a lot more information
> coming off ftrace.
>
> A few months ago Joonas thought it would be best to have GPUvis be the
> tool we spend time improving rather than our own effort, and I came to
> the same conclusion.
>
> So what does this have to do IGT?
>
> Well first, GPUvis is really only a few scripts around ftrace and some
> parsing code for ftrace as well as a user interface. But it does not
> deal directly with the kernel nor its drivers.
>
> So a recording tool for the i915-perf data needs to live somewhere.
> Right now this partly exists in GPUTop, except the data is never saved
> anywhere, it just resides in memory (either on the machine being
> monitored or the remote client inspecting the data).
>
> Secondly, GPUTop is also the place where we store the HW
> configurations for the Gen observation architecture as well as the
> equations to make up human readable data out of HW register values. If
> we're not going to invest much more effort into GPUTop, maybe it's a
> good idea to more that part into a more lively project.
>
>
> This series (probably too big for mail [3]) adds the following new
> things to IGT :
>
>     * A new library libi915_perf.so that helps you :
>
>        * parse i915-perf data from low level reports into logical
>          counters (with name & description)
>
>        * a library to load a file in which was recorded i915-perf data
>          along with other bits of information (device id, topology,
>          timestamp correlation, etc...)
>
>     * A set of tools to deal with :
>
>        * HW configurations stored in i915
>
>        * recording i915-perf data into a file that can be replay with
>          the library mentioned above
>
>        * basic replaying of i915-perf data (mostly showing how to use
>          the library above)
>
>
> Now with all this I have a GPUvis changes making use of this library &
> recording tool [4].
>
> Hopefully this explains what we're trying to do here.
>
> Cheers,
>
> [1] : https://github.com/rib/gputop
> [2] : https://github.com/mikesart/gpuvis
> [3] : https://github.com/djdeath/intel-gpu-tools/tree/review/i915-perf-tools
[4] : https://github.com/mikesart/gpuvis/pull/40
>
> Lionel Landwerlin (6):
>    lib/intel_chipset: identify Elkhart Lake
>    Add i915_perf library
>    lib/i915: Add support for loading perf configurations
>    tools: add i915 perf recorder tool
>    lib: add i915 perf data reader
>    tools: add i915-perf-reader
>
>   lib/i915-perf.pc.in                           |    11 +
>   lib/i915/perf-configs/README.md               |   115 +
>   lib/i915/perf-configs/codegen.py              |    33 +
>   lib/i915/perf-configs/guids.xml               |   319 +
>   lib/i915/perf-configs/mdapi-xml-convert.py    |  1006 +
>   lib/i915/perf-configs/oa-bdw.xml              | 15653 ++++++++++++++++
>   lib/i915/perf-configs/oa-bxt.xml              |  9595 ++++++++++
>   lib/i915/perf-configs/oa-cflgt2.xml           | 10866 +++++++++++
>   lib/i915/perf-configs/oa-cflgt3.xml           | 10933 +++++++++++
>   lib/i915/perf-configs/oa-chv.xml              |  9757 ++++++++++
>   lib/i915/perf-configs/oa-cnl.xml              | 10411 ++++++++++
>   lib/i915/perf-configs/oa-glk.xml              |  9346 +++++++++
>   lib/i915/perf-configs/oa-hsw.xml              |  4615 +++++
>   lib/i915/perf-configs/oa-icl.xml              | 11869 ++++++++++++
>   lib/i915/perf-configs/oa-kblgt2.xml           | 10866 +++++++++++
>   lib/i915/perf-configs/oa-kblgt3.xml           | 10933 +++++++++++
>   lib/i915/perf-configs/oa-lkf.xml              | 11803 ++++++++++++
>   lib/i915/perf-configs/oa-sklgt2.xml           | 11895 ++++++++++++
>   lib/i915/perf-configs/oa-sklgt3.xml           | 10933 +++++++++++
>   lib/i915/perf-configs/oa-sklgt4.xml           | 10956 +++++++++++
>   lib/i915/perf-configs/oa-tgl.xml              |  8491 +++++++++
>   lib/i915/perf-configs/oa_guid_registry.py     |    73 +
>   lib/i915/perf-configs/perf-codegen.py         |   850 +
>   lib/i915/perf-configs/update-guids.py         |   231 +
>   lib/i915/perf.c                               |   583 +
>   lib/i915/perf.h                               |   240 +
>   lib/i915/perf_data.h                          |   118 +
>   lib/i915/perf_data_reader.c                   |   383 +
>   lib/i915/perf_data_reader.h                   |   107 +
>   lib/intel_chipset.h                           |     1 +
>   lib/intel_device_info.c                       |     8 +-
>   lib/meson.build                               |    68 +
>   lib/tests/i915_perf_data_alignment.c          |    40 +
>   lib/tests/meson.build                         |     1 +
>   tools/i915-perf/i915_perf_configs.c           |   277 +
>   tools/i915-perf/i915_perf_control.c           |   133 +
>   tools/i915-perf/i915_perf_reader.c            |   279 +
>   tools/i915-perf/i915_perf_recorder.c          |  1052 ++
>   tools/i915-perf/i915_perf_recorder_commands.h |    39 +
>   tools/i915-perf/meson.build                   |    22 +
>   tools/meson.build                             |     1 +
>   41 files changed, 174911 insertions(+), 1 deletion(-)
>   create mode 100644 lib/i915-perf.pc.in
>   create mode 100644 lib/i915/perf-configs/README.md
>   create mode 100644 lib/i915/perf-configs/codegen.py
>   create mode 100644 lib/i915/perf-configs/guids.xml
>   create mode 100755 lib/i915/perf-configs/mdapi-xml-convert.py
>   create mode 100644 lib/i915/perf-configs/oa-bdw.xml
>   create mode 100644 lib/i915/perf-configs/oa-bxt.xml
>   create mode 100644 lib/i915/perf-configs/oa-cflgt2.xml
>   create mode 100644 lib/i915/perf-configs/oa-cflgt3.xml
>   create mode 100644 lib/i915/perf-configs/oa-chv.xml
>   create mode 100644 lib/i915/perf-configs/oa-cnl.xml
>   create mode 100644 lib/i915/perf-configs/oa-glk.xml
>   create mode 100644 lib/i915/perf-configs/oa-hsw.xml
>   create mode 100644 lib/i915/perf-configs/oa-icl.xml
>   create mode 100644 lib/i915/perf-configs/oa-kblgt2.xml
>   create mode 100644 lib/i915/perf-configs/oa-kblgt3.xml
>   create mode 100644 lib/i915/perf-configs/oa-lkf.xml
>   create mode 100644 lib/i915/perf-configs/oa-sklgt2.xml
>   create mode 100644 lib/i915/perf-configs/oa-sklgt3.xml
>   create mode 100644 lib/i915/perf-configs/oa-sklgt4.xml
>   create mode 100644 lib/i915/perf-configs/oa-tgl.xml
>   create mode 100644 lib/i915/perf-configs/oa_guid_registry.py
>   create mode 100755 lib/i915/perf-configs/perf-codegen.py
>   create mode 100755 lib/i915/perf-configs/update-guids.py
>   create mode 100644 lib/i915/perf.c
>   create mode 100644 lib/i915/perf.h
>   create mode 100644 lib/i915/perf_data.h
>   create mode 100644 lib/i915/perf_data_reader.c
>   create mode 100644 lib/i915/perf_data_reader.h
>   create mode 100644 lib/tests/i915_perf_data_alignment.c
>   create mode 100644 tools/i915-perf/i915_perf_configs.c
>   create mode 100644 tools/i915-perf/i915_perf_control.c
>   create mode 100644 tools/i915-perf/i915_perf_reader.c
>   create mode 100644 tools/i915-perf/i915_perf_recorder.c
>   create mode 100644 tools/i915-perf/i915_perf_recorder_commands.h
>   create mode 100644 tools/i915-perf/meson.build
>
> --
> 2.25.0


_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf
  2020-02-17 14:21 [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
                   ` (5 preceding siblings ...)
  2020-02-17 14:27 ` [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
@ 2020-02-18 18:46 ` Chris Wilson
  6 siblings, 0 replies; 16+ messages in thread
From: Chris Wilson @ 2020-02-18 18:46 UTC (permalink / raw)
  To: Lionel Landwerlin, igt-dev

Quoting Lionel Landwerlin (2020-02-17 14:21:49)
> Lionel Landwerlin (6):
>   lib/intel_chipset: identify Elkhart Lake
>   Add i915_perf library
>   lib/i915: Add support for loading perf configurations
>   tools: add i915 perf recorder tool
>   lib: add i915 perf data reader
>   tools: add i915-perf-reader

Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 1/6] lib/intel_chipset: identify Elkhart Lake
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 1/6] lib/intel_chipset: identify Elkhart Lake Lionel Landwerlin
@ 2020-02-18 18:47   ` Chris Wilson
  0 siblings, 0 replies; 16+ messages in thread
From: Chris Wilson @ 2020-02-18 18:47 UTC (permalink / raw)
  To: Lionel Landwerlin, igt-dev

Quoting Lionel Landwerlin (2020-02-17 14:21:50)
> We'll need to identify this platform for performance tools.
> 
> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> ---
>  lib/intel_chipset.h     | 1 +
>  lib/intel_device_info.c | 8 +++++++-
>  2 files changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/intel_chipset.h b/lib/intel_chipset.h
> index 2bd57f4f..929fac53 100644
> --- a/lib/intel_chipset.h
> +++ b/lib/intel_chipset.h
> @@ -71,6 +71,7 @@ struct intel_device_info {
>         bool is_cometlake : 1;
>         bool is_cannonlake : 1;
>         bool is_icelake : 1;
> +       bool is_elkhartlake : 1;
>         bool is_tigerlake : 1;
>         const char *codename;
>  };
> diff --git a/lib/intel_device_info.c b/lib/intel_device_info.c
> index 4f96577d..07eeb7c5 100644
> --- a/lib/intel_device_info.c
> +++ b/lib/intel_device_info.c
> @@ -309,6 +309,12 @@ static const struct intel_device_info intel_icelake_info = {
>         .codename = "icelake"
>  };
>  
> +static const struct intel_device_info intel_elkhartlake_info = {
> +       .gen = BIT(10),
> +       .is_elkhartlake = true,
> +       .codename = ""

.codename = "elkhartlake"

Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 3/6] lib/i915: Add support for loading perf configurations
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 3/6] lib/i915: Add support for loading perf configurations Lionel Landwerlin
@ 2020-02-18 18:52   ` Chris Wilson
  0 siblings, 0 replies; 16+ messages in thread
From: Chris Wilson @ 2020-02-18 18:52 UTC (permalink / raw)
  To: Lionel Landwerlin, igt-dev

Quoting Lionel Landwerlin (2020-02-17 14:21:52)
> +void
> +intel_perf_load_perf_configs(struct intel_perf *perf, int drm_fd)
> +{
> +       int drm_card = get_card_for_fd(drm_fd);
> +       struct dirent *entry;
> +       char metrics_path[128];
> +       DIR *metrics_dir;
> +       struct intel_perf_metric_set *metric_set;
> +
> +       snprintf(metrics_path, sizeof(metrics_path),
> +                "/sys/class/drm/card%d/metrics", drm_card);

        if (fstat(i915, &st) || !S_ISCHR(st.st_mode))
                return NULL;

        snprintf(path, pathlen, "/sys/dev/char/%d:%d/metrics",
                 major(st.st_rdev), minor(st.st_rdev));


> +       metrics_dir = opendir(metrics_path);
> +       if (!metrics_dir)
> +               return;
> +
> +       while ((entry = readdir(metrics_dir))) {
> +               char *metric_id_path;
> +               uint64_t metric_id;
> +
> +               if (entry->d_type != DT_DIR)
> +                       continue;
> +
> +               asprintf(&metric_id_path, "%s/%s/id",
> +                        metrics_path, entry->d_name);

I'd suggest using openat.

> +
> +               if (!read_file_uint64(metric_id_path, &metric_id)) {
> +                       free(metric_id_path);
> +                       continue;
> +               }
> +
> +               free(metric_id_path);
> +
> +               igt_list_for_each_entry(metric_set, &perf->metric_sets, link) {
> +                       if (!strcmp(metric_set->hw_config_guid, entry->d_name)) {
> +                               metric_set->perf_oa_metrics_set = metric_id;
> +                               break;
> +                       }
> +               }
> +       }
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool
  2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool Lionel Landwerlin
@ 2020-02-18 18:57   ` Chris Wilson
  2020-02-18 19:25     ` Lionel Landwerlin
  0 siblings, 1 reply; 16+ messages in thread
From: Chris Wilson @ 2020-02-18 18:57 UTC (permalink / raw)
  To: Lionel Landwerlin, igt-dev

Quoting Lionel Landwerlin (2020-02-17 14:21:53)
> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> ---
>  lib/i915-perf.pc.in                           |    1 +
>  lib/i915/perf_data.h                          |  118 ++
>  lib/meson.build                               |    1 +
>  lib/tests/i915_perf_data_alignment.c          |   40 +
>  lib/tests/meson.build                         |    1 +
>  tools/i915-perf/i915_perf_control.c           |  133 +++
>  tools/i915-perf/i915_perf_recorder.c          | 1052 +++++++++++++++++
>  tools/i915-perf/i915_perf_recorder_commands.h |   39 +
>  tools/i915-perf/meson.build                   |   11 +
>  9 files changed, 1396 insertions(+)
>  create mode 100644 lib/i915/perf_data.h
>  create mode 100644 lib/tests/i915_perf_data_alignment.c
>  create mode 100644 tools/i915-perf/i915_perf_control.c
>  create mode 100644 tools/i915-perf/i915_perf_recorder.c
>  create mode 100644 tools/i915-perf/i915_perf_recorder_commands.h
> 
> diff --git a/lib/i915-perf.pc.in b/lib/i915-perf.pc.in
> index e72efdc3..8cfa3dbe 100644
> --- a/lib/i915-perf.pc.in
> +++ b/lib/i915-perf.pc.in
> @@ -6,5 +6,6 @@ includedir=@includedir@
>  Name: i915-perf
>  Description: i915 perf library
>  Version: @version@
> +Requires: libdrm

You only use the uAPI headers, and they are in include/drm-uapi/
Right?
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool
  2020-02-18 18:57   ` Chris Wilson
@ 2020-02-18 19:25     ` Lionel Landwerlin
  2020-02-18 19:36       ` Chris Wilson
  0 siblings, 1 reply; 16+ messages in thread
From: Lionel Landwerlin @ 2020-02-18 19:25 UTC (permalink / raw)
  To: Chris Wilson, igt-dev

On 18/02/2020 20:57, Chris Wilson wrote:
> Quoting Lionel Landwerlin (2020-02-17 14:21:53)
>> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
>> ---
>>   lib/i915-perf.pc.in                           |    1 +
>>   lib/i915/perf_data.h                          |  118 ++
>>   lib/meson.build                               |    1 +
>>   lib/tests/i915_perf_data_alignment.c          |   40 +
>>   lib/tests/meson.build                         |    1 +
>>   tools/i915-perf/i915_perf_control.c           |  133 +++
>>   tools/i915-perf/i915_perf_recorder.c          | 1052 +++++++++++++++++
>>   tools/i915-perf/i915_perf_recorder_commands.h |   39 +
>>   tools/i915-perf/meson.build                   |   11 +
>>   9 files changed, 1396 insertions(+)
>>   create mode 100644 lib/i915/perf_data.h
>>   create mode 100644 lib/tests/i915_perf_data_alignment.c
>>   create mode 100644 tools/i915-perf/i915_perf_control.c
>>   create mode 100644 tools/i915-perf/i915_perf_recorder.c
>>   create mode 100644 tools/i915-perf/i915_perf_recorder_commands.h
>>
>> diff --git a/lib/i915-perf.pc.in b/lib/i915-perf.pc.in
>> index e72efdc3..8cfa3dbe 100644
>> --- a/lib/i915-perf.pc.in
>> +++ b/lib/i915-perf.pc.in
>> @@ -6,5 +6,6 @@ includedir=@includedir@
>>   Name: i915-perf
>>   Description: i915 perf library
>>   Version: @version@
>> +Requires: libdrm
> You only use the uAPI headers, and they are in include/drm-uapi/
> Right?
> -Chris

For IGT yeah, but for another application using this library, it needs 
the dependency.


-Lionel

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool
  2020-02-18 19:25     ` Lionel Landwerlin
@ 2020-02-18 19:36       ` Chris Wilson
  2020-02-18 19:49         ` Lionel Landwerlin
  0 siblings, 1 reply; 16+ messages in thread
From: Chris Wilson @ 2020-02-18 19:36 UTC (permalink / raw)
  To: Lionel Landwerlin, igt-dev

Quoting Lionel Landwerlin (2020-02-18 19:25:08)
> On 18/02/2020 20:57, Chris Wilson wrote:
> > Quoting Lionel Landwerlin (2020-02-17 14:21:53)
> >> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> >> ---
> >>   lib/i915-perf.pc.in                           |    1 +
> >>   lib/i915/perf_data.h                          |  118 ++
> >>   lib/meson.build                               |    1 +
> >>   lib/tests/i915_perf_data_alignment.c          |   40 +
> >>   lib/tests/meson.build                         |    1 +
> >>   tools/i915-perf/i915_perf_control.c           |  133 +++
> >>   tools/i915-perf/i915_perf_recorder.c          | 1052 +++++++++++++++++
> >>   tools/i915-perf/i915_perf_recorder_commands.h |   39 +
> >>   tools/i915-perf/meson.build                   |   11 +
> >>   9 files changed, 1396 insertions(+)
> >>   create mode 100644 lib/i915/perf_data.h
> >>   create mode 100644 lib/tests/i915_perf_data_alignment.c
> >>   create mode 100644 tools/i915-perf/i915_perf_control.c
> >>   create mode 100644 tools/i915-perf/i915_perf_recorder.c
> >>   create mode 100644 tools/i915-perf/i915_perf_recorder_commands.h
> >>
> >> diff --git a/lib/i915-perf.pc.in b/lib/i915-perf.pc.in
> >> index e72efdc3..8cfa3dbe 100644
> >> --- a/lib/i915-perf.pc.in
> >> +++ b/lib/i915-perf.pc.in
> >> @@ -6,5 +6,6 @@ includedir=@includedir@
> >>   Name: i915-perf
> >>   Description: i915 perf library
> >>   Version: @version@
> >> +Requires: libdrm
> > You only use the uAPI headers, and they are in include/drm-uapi/
> > Right?
> > -Chris
> 
> For IGT yeah, but for another application using this library, it needs 
> the dependency.

Isn't that a Requires.private:
No linkage required, but headers are?
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool
  2020-02-18 19:36       ` Chris Wilson
@ 2020-02-18 19:49         ` Lionel Landwerlin
  2020-02-18 20:14           ` Lionel Landwerlin
  0 siblings, 1 reply; 16+ messages in thread
From: Lionel Landwerlin @ 2020-02-18 19:49 UTC (permalink / raw)
  To: Chris Wilson, igt-dev

On 18/02/2020 21:36, Chris Wilson wrote:
> Quoting Lionel Landwerlin (2020-02-18 19:25:08)
>> On 18/02/2020 20:57, Chris Wilson wrote:
>>> Quoting Lionel Landwerlin (2020-02-17 14:21:53)
>>>> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
>>>> ---
>>>>    lib/i915-perf.pc.in                           |    1 +
>>>>    lib/i915/perf_data.h                          |  118 ++
>>>>    lib/meson.build                               |    1 +
>>>>    lib/tests/i915_perf_data_alignment.c          |   40 +
>>>>    lib/tests/meson.build                         |    1 +
>>>>    tools/i915-perf/i915_perf_control.c           |  133 +++
>>>>    tools/i915-perf/i915_perf_recorder.c          | 1052 +++++++++++++++++
>>>>    tools/i915-perf/i915_perf_recorder_commands.h |   39 +
>>>>    tools/i915-perf/meson.build                   |   11 +
>>>>    9 files changed, 1396 insertions(+)
>>>>    create mode 100644 lib/i915/perf_data.h
>>>>    create mode 100644 lib/tests/i915_perf_data_alignment.c
>>>>    create mode 100644 tools/i915-perf/i915_perf_control.c
>>>>    create mode 100644 tools/i915-perf/i915_perf_recorder.c
>>>>    create mode 100644 tools/i915-perf/i915_perf_recorder_commands.h
>>>>
>>>> diff --git a/lib/i915-perf.pc.in b/lib/i915-perf.pc.in
>>>> index e72efdc3..8cfa3dbe 100644
>>>> --- a/lib/i915-perf.pc.in
>>>> +++ b/lib/i915-perf.pc.in
>>>> @@ -6,5 +6,6 @@ includedir=@includedir@
>>>>    Name: i915-perf
>>>>    Description: i915 perf library
>>>>    Version: @version@
>>>> +Requires: libdrm
>>> You only use the uAPI headers, and they are in include/drm-uapi/
>>> Right?
>>> -Chris
>> For IGT yeah, but for another application using this library, it needs
>> the dependency.
> Isn't that a Requires.private:
> No linkage required, but headers are?
> -Chris

The headers are a structure pointer from i915_drm.h

But I can probably forward declare this and potentially drop the need 
for any dep :)


-Lionel

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool
  2020-02-18 19:49         ` Lionel Landwerlin
@ 2020-02-18 20:14           ` Lionel Landwerlin
  2020-02-18 20:26             ` Chris Wilson
  0 siblings, 1 reply; 16+ messages in thread
From: Lionel Landwerlin @ 2020-02-18 20:14 UTC (permalink / raw)
  To: Chris Wilson, igt-dev

On 18/02/2020 21:49, Lionel Landwerlin wrote:
> On 18/02/2020 21:36, Chris Wilson wrote:
>> Quoting Lionel Landwerlin (2020-02-18 19:25:08)
>>> On 18/02/2020 20:57, Chris Wilson wrote:
>>>> Quoting Lionel Landwerlin (2020-02-17 14:21:53)
>>>>> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
>>>>> ---
>>>>>    lib/i915-perf.pc.in                           |    1 +
>>>>>    lib/i915/perf_data.h                          |  118 ++
>>>>>    lib/meson.build                               |    1 +
>>>>>    lib/tests/i915_perf_data_alignment.c          |   40 +
>>>>>    lib/tests/meson.build                         |    1 +
>>>>>    tools/i915-perf/i915_perf_control.c           |  133 +++
>>>>>    tools/i915-perf/i915_perf_recorder.c          | 1052 
>>>>> +++++++++++++++++
>>>>>    tools/i915-perf/i915_perf_recorder_commands.h |   39 +
>>>>>    tools/i915-perf/meson.build                   |   11 +
>>>>>    9 files changed, 1396 insertions(+)
>>>>>    create mode 100644 lib/i915/perf_data.h
>>>>>    create mode 100644 lib/tests/i915_perf_data_alignment.c
>>>>>    create mode 100644 tools/i915-perf/i915_perf_control.c
>>>>>    create mode 100644 tools/i915-perf/i915_perf_recorder.c
>>>>>    create mode 100644 tools/i915-perf/i915_perf_recorder_commands.h
>>>>>
>>>>> diff --git a/lib/i915-perf.pc.in b/lib/i915-perf.pc.in
>>>>> index e72efdc3..8cfa3dbe 100644
>>>>> --- a/lib/i915-perf.pc.in
>>>>> +++ b/lib/i915-perf.pc.in
>>>>> @@ -6,5 +6,6 @@ includedir=@includedir@
>>>>>    Name: i915-perf
>>>>>    Description: i915 perf library
>>>>>    Version: @version@
>>>>> +Requires: libdrm
>>>> You only use the uAPI headers, and they are in include/drm-uapi/
>>>> Right?
>>>> -Chris
>>> For IGT yeah, but for another application using this library, it needs
>>> the dependency.
>> Isn't that a Requires.private:
>> No linkage required, but headers are?
>> -Chris
>
> The headers are a structure pointer from i915_drm.h
>
> But I can probably forward declare this and potentially drop the need 
> for any dep :)
>
>
> -Lionel 


Arg I was wrong, one of the packet in the perf_data.h embeds the 
topology structure from i915_drm.h.


I guess it could be rewritten just in there. What do you think?

Thanks,


-Lionel

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool
  2020-02-18 20:14           ` Lionel Landwerlin
@ 2020-02-18 20:26             ` Chris Wilson
  0 siblings, 0 replies; 16+ messages in thread
From: Chris Wilson @ 2020-02-18 20:26 UTC (permalink / raw)
  To: Lionel Landwerlin, igt-dev

Quoting Lionel Landwerlin (2020-02-18 20:14:12)
> On 18/02/2020 21:49, Lionel Landwerlin wrote:
> > On 18/02/2020 21:36, Chris Wilson wrote:
> >> Quoting Lionel Landwerlin (2020-02-18 19:25:08)
> >>> On 18/02/2020 20:57, Chris Wilson wrote:
> >>>> Quoting Lionel Landwerlin (2020-02-17 14:21:53)
> >>>>> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> >>>>> ---
> >>>>>    lib/i915-perf.pc.in                           |    1 +
> >>>>>    lib/i915/perf_data.h                          |  118 ++
> >>>>>    lib/meson.build                               |    1 +
> >>>>>    lib/tests/i915_perf_data_alignment.c          |   40 +
> >>>>>    lib/tests/meson.build                         |    1 +
> >>>>>    tools/i915-perf/i915_perf_control.c           |  133 +++
> >>>>>    tools/i915-perf/i915_perf_recorder.c          | 1052 
> >>>>> +++++++++++++++++
> >>>>>    tools/i915-perf/i915_perf_recorder_commands.h |   39 +
> >>>>>    tools/i915-perf/meson.build                   |   11 +
> >>>>>    9 files changed, 1396 insertions(+)
> >>>>>    create mode 100644 lib/i915/perf_data.h
> >>>>>    create mode 100644 lib/tests/i915_perf_data_alignment.c
> >>>>>    create mode 100644 tools/i915-perf/i915_perf_control.c
> >>>>>    create mode 100644 tools/i915-perf/i915_perf_recorder.c
> >>>>>    create mode 100644 tools/i915-perf/i915_perf_recorder_commands.h
> >>>>>
> >>>>> diff --git a/lib/i915-perf.pc.in b/lib/i915-perf.pc.in
> >>>>> index e72efdc3..8cfa3dbe 100644
> >>>>> --- a/lib/i915-perf.pc.in
> >>>>> +++ b/lib/i915-perf.pc.in
> >>>>> @@ -6,5 +6,6 @@ includedir=@includedir@
> >>>>>    Name: i915-perf
> >>>>>    Description: i915 perf library
> >>>>>    Version: @version@
> >>>>> +Requires: libdrm
> >>>> You only use the uAPI headers, and they are in include/drm-uapi/
> >>>> Right?
> >>>> -Chris
> >>> For IGT yeah, but for another application using this library, it needs
> >>> the dependency.
> >> Isn't that a Requires.private:
> >> No linkage required, but headers are?
> >> -Chris
> >
> > The headers are a structure pointer from i915_drm.h
> >
> > But I can probably forward declare this and potentially drop the need 
> > for any dep :)
> >
> >
> > -Lionel 
> 
> 
> Arg I was wrong, one of the packet in the perf_data.h embeds the 
> topology structure from i915_drm.h.
> 
> 
> I guess it could be rewritten just in there. What do you think?

Pull in the header via pkg-config, we should stick to a single canonical
header for the outside world. I think it is possible for our .pc to
avoid the linkage; we just risk Eero complaining about the million links
if we get it wrong.
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2020-02-18 20:26 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-17 14:21 [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 1/6] lib/intel_chipset: identify Elkhart Lake Lionel Landwerlin
2020-02-18 18:47   ` Chris Wilson
2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 3/6] lib/i915: Add support for loading perf configurations Lionel Landwerlin
2020-02-18 18:52   ` Chris Wilson
2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 4/6] tools: add i915 perf recorder tool Lionel Landwerlin
2020-02-18 18:57   ` Chris Wilson
2020-02-18 19:25     ` Lionel Landwerlin
2020-02-18 19:36       ` Chris Wilson
2020-02-18 19:49         ` Lionel Landwerlin
2020-02-18 20:14           ` Lionel Landwerlin
2020-02-18 20:26             ` Chris Wilson
2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 5/6] lib: add i915 perf data reader Lionel Landwerlin
2020-02-17 14:21 ` [igt-dev] [PATCH i-g-t 6/6] tools: add i915-perf-reader Lionel Landwerlin
2020-02-17 14:27 ` [igt-dev] [PATCH i-g-t 0/6] New performance recording/replay tools for i915-perf Lionel Landwerlin
2020-02-18 18:46 ` Chris Wilson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.