All of lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
@ 2021-04-29  0:29 Umesh Nerlige Ramappa
  2021-04-29  1:25 ` [igt-dev] ✓ Fi.CI.BAT: success for i915/perf: Add test to query CS timestamp (rev6) Patchwork
  2021-04-29  2:42 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  0 siblings, 2 replies; 13+ messages in thread
From: Umesh Nerlige Ramappa @ 2021-04-29  0:29 UTC (permalink / raw)
  To: igt-dev

Add tests to query CS timestamps for different engines.

v2:
- remove flag parameter
- assert for minimum usable values rather than maximum

v3:
- use clock id for cpu timestamps (Lionel)
- check if query is supported (Ashutosh)
- test bad queries

v4: (Chris, Tvrtko)
- cs_timestamp is a misnomer, use cs_cycles instead
- use cs cycle frequency returned in the query
- omit size parameter

v5:
- use __for_each_physical_engine (Lionel)
- check for ENODEV (Umesh)

v6: Use 2 cpu timestamps to calculate reg read time (Lionel)
v7: Refactor test code and add a spinner (Chris)
v8: Update cpu_timestamp array split into timestamp and delta

Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
 include/drm-uapi/i915_drm.h |  52 ++++++++++
 tests/i915/i915_query.c     | 190 ++++++++++++++++++++++++++++++++++++
 2 files changed, 242 insertions(+)

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index bf9ea471..1d1fe852 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
 #define DRM_I915_QUERY_TOPOLOGY_INFO    1
 #define DRM_I915_QUERY_ENGINE_INFO	2
 #define DRM_I915_QUERY_PERF_CONFIG      3
+	/**
+	 * Query Command Streamer timestamp register.
+	 */
+#define DRM_I915_QUERY_CS_CYCLES	4
 /* Must be kept compact -- no holes and well documented */
 
 	/*
@@ -2309,6 +2313,54 @@ struct drm_i915_engine_info {
 	__u64 rsvd1[4];
 };
 
+/**
+ * struct drm_i915_query_cs_cycles
+ *
+ * The query returns the command streamer cycles, the frequency that can be
+ * used to calculate the command streamer timestamp, a cpu timestamp indicating
+ * when the cs cycles was captured and a cpu_delta capturing time taken to read
+ * the cs_cycles register.
+ */
+struct drm_i915_query_cs_cycles {
+	/** Engine for which command streamer cycles is queried. */
+	struct i915_engine_class_instance engine;
+
+	/** Must be zero. */
+	__u32 flags;
+
+	/**
+	 * Command streamer cycles as read from the command streamer
+	 * register at 0x358 offset.
+	 */
+	__u64 cs_cycles;
+
+	/** Frequency of the cs cycles in Hz. */
+	__u64 cs_frequency;
+
+	/**
+	 * CPU timestamp in ns. The timestamp is captured before reading the
+	 * cs_cycles register using the reference clockid set by the user.
+	 */
+	__u64 cpu_timestamp;
+
+	/**
+	 * Time delta in ns captured around reading the lower dword of the
+	 * cs_cycles register.
+	 */
+	__u64 cpu_delta;
+
+	/**
+	 * Reference clock id for CPU timestamp. For definition, see
+	 * clock_gettime(2) and perf_event_open(2). Supported clock ids are
+	 * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
+	 * CLOCK_TAI.
+	 */
+	__s32 clockid;
+
+	/** Must be zero. */
+	__u32 rsvd;
+};
+
 /**
  * struct drm_i915_query_engine_info
  *
diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
index 29b938e9..3c6c5c54 100644
--- a/tests/i915/i915_query.c
+++ b/tests/i915/i915_query.c
@@ -267,6 +267,184 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
 				eu / 8] >> (eu % 8)) & 1;
 }
 
+static int __query_cs_cycles(int i915, void *data)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+		.data_ptr = to_user_pointer(data),
+		.length = data ? sizeof(struct drm_i915_query_cs_cycles) : 0,
+	};
+
+	i915_query_items(i915, &item, 1);
+
+	return item.length;
+}
+
+static bool query_cs_cycles_supported(int fd)
+{
+	return __query_cs_cycles(fd, NULL) > 0;
+}
+
+static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
+{
+	struct drm_i915_query_cs_cycles ts = {
+		.engine = { class, instance }
+	};
+
+	return __query_cs_cycles(i915, &ts) != -ENODEV;
+}
+
+static void
+__cs_cycles(int i915, struct i915_engine_class_instance *engine)
+{
+	struct drm_i915_query_cs_cycles ts1 = {};
+	struct drm_i915_query_cs_cycles ts2 = {};
+	uint64_t delta_cpu, delta_cs, delta_delta;
+	int i, usable = 0;
+	igt_spin_t *spin;
+	uint32_t ctx;
+	struct {
+		int32_t id;
+		const char *name;
+	} clock[] = {
+		{ CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
+		{ CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
+		{ CLOCK_REALTIME, "CLOCK_REALTIME" },
+		{ CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
+		{ CLOCK_TAI, "CLOCK_TAI" },
+	};
+
+	igt_debug("engine[%u:%u]\n",
+		  engine->engine_class,
+		  engine->engine_instance);
+
+	ctx = gem_context_create_for_engine(i915,
+					    engine->engine_class,
+					    engine->engine_instance);
+	spin = igt_spin_new(i915, ctx);
+
+	/* Try a new clock every 10 iterations. */
+#define NUM_SNAPSHOTS 10
+	for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
+		int index = i / NUM_SNAPSHOTS;
+
+		ts1.engine = *engine;
+		ts1.clockid = clock[index].id;
+
+		ts2.engine = *engine;
+		ts2.clockid = clock[index].id;
+
+		igt_assert_eq(__query_cs_cycles(i915, &ts1), sizeof(ts1));
+		igt_assert_eq(__query_cs_cycles(i915, &ts2), sizeof(ts2));
+
+		igt_debug("[1] cpu_ts before %llu, reg read time %llu\n",
+			  ts1.cpu_timestamp,
+			  ts1.cpu_delta);
+		igt_debug("[1] cs_ts %llu, freq %llu Hz\n",
+			  ts1.cs_cycles, ts1.cs_frequency);
+
+		igt_debug("[2] cpu_ts before %llu, reg read time %llu\n",
+			  ts2.cpu_timestamp,
+			  ts2.cpu_delta);
+		igt_debug("[2] cs_ts %llu, freq %llu Hz\n",
+			  ts2.cs_cycles, ts2.cs_frequency);
+
+		delta_cpu = ts2.cpu_timestamp - ts1.cpu_timestamp;
+		delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
+			   NSEC_PER_SEC / ts1.cs_frequency;
+
+		igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
+			  delta_cpu, delta_cs);
+
+		delta_delta = delta_cpu > delta_cs ?
+			       delta_cpu - delta_cs :
+			       delta_cs - delta_cpu;
+		igt_debug("delta_delta %lu\n", delta_delta);
+
+		if (delta_delta < 5000)
+			usable++;
+
+		/*
+		 * User needs few good snapshots of the timestamps to
+		 * synchronize cpu time with cs time. Check if we have enough
+		 * usable values before moving to the next clockid.
+		 */
+		if (!((i + 1) % NUM_SNAPSHOTS)) {
+			igt_debug("clock %s\n", clock[index].name);
+			igt_debug("usable %d\n", usable);
+			igt_assert(usable > 2);
+			usable = 0;
+		}
+	}
+
+	gem_context_destroy(i915, ctx);
+	igt_spin_free(i915, spin);
+}
+
+static void test_cs_cycles(int i915)
+{
+	const struct intel_execution_engine2 *e;
+	struct i915_engine_class_instance engine;
+
+	__for_each_physical_engine(i915, e) {
+		if (engine_has_cs_cycles(i915, e->class, e->instance)) {
+			engine.engine_class = e->class;
+			engine.engine_instance = e->instance;
+			__cs_cycles(i915, &engine);
+		}
+	}
+}
+
+static void test_cs_cycles_invalid(int i915)
+{
+	struct i915_engine_class_instance engine;
+	const struct intel_execution_engine2 *e;
+	struct drm_i915_query_cs_cycles ts = {};
+
+	/* get one engine */
+	__for_each_physical_engine(i915, e)
+		break;
+
+	/* sanity check engine selection is valid */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), sizeof(ts));
+
+	/* bad engines */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* non zero flags */
+	ts.flags = 1;
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* non zero rsvd field */
+	ts.flags = 0;
+	ts.rsvd = 1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* bad clockid */
+	ts.rsvd = 0;
+	ts.clockid = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* sanity check */
+	engine.engine_class = e->class;
+	engine.engine_instance = e->instance;
+	__cs_cycles(i915, &engine);
+}
+
 /*
  * Verify that we get coherent values between the legacy getparam slice/subslice
  * masks and the new topology query.
@@ -783,6 +961,18 @@ igt_main
 			engines(fd);
 	}
 
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(query_cs_cycles_supported(fd));
+		}
+
+		igt_subtest("cs-cycles-invalid")
+			test_cs_cycles_invalid(fd);
+
+		igt_subtest("cs-cycles")
+			test_cs_cycles(fd);
+	}
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.20.1

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

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

* [igt-dev] ✓ Fi.CI.BAT: success for i915/perf: Add test to query CS timestamp (rev6)
  2021-04-29  0:29 [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp Umesh Nerlige Ramappa
@ 2021-04-29  1:25 ` Patchwork
  2021-04-29  2:42 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  1 sibling, 0 replies; 13+ messages in thread
From: Patchwork @ 2021-04-29  1:25 UTC (permalink / raw)
  To: Umesh Nerlige Ramappa; +Cc: igt-dev


[-- Attachment #1.1: Type: text/plain, Size: 2933 bytes --]

== Series Details ==

Series: i915/perf: Add test to query CS timestamp (rev6)
URL   : https://patchwork.freedesktop.org/series/87553/
State : success

== Summary ==

CI Bug Log - changes from IGT_6077 -> IGTPW_5769
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/index.html

Known issues
------------

  Here are the changes found in IGTPW_5769 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@amdgpu/amd_cs_nop@fork-gfx0:
    - fi-tgl-y:           NOTRUN -> [SKIP][1] ([fdo#109315] / [i915#2575]) +14 similar issues
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/fi-tgl-y/igt@amdgpu/amd_cs_nop@fork-gfx0.html

  * igt@kms_chamelium@hdmi-hpd-fast:
    - fi-icl-u2:          [PASS][2] -> [DMESG-WARN][3] ([i915#2203] / [i915#2868])
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/fi-icl-u2/igt@kms_chamelium@hdmi-hpd-fast.html
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/fi-icl-u2/igt@kms_chamelium@hdmi-hpd-fast.html

  
#### Possible fixes ####

  * igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-b:
    - fi-cfl-8109u:       [DMESG-WARN][4] ([i915#165]) -> [PASS][5] +15 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/fi-cfl-8109u/igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-b.html
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/fi-cfl-8109u/igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-b.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [i915#165]: https://gitlab.freedesktop.org/drm/intel/issues/165
  [i915#2203]: https://gitlab.freedesktop.org/drm/intel/issues/2203
  [i915#2575]: https://gitlab.freedesktop.org/drm/intel/issues/2575
  [i915#2868]: https://gitlab.freedesktop.org/drm/intel/issues/2868
  [i915#3277]: https://gitlab.freedesktop.org/drm/intel/issues/3277
  [i915#3283]: https://gitlab.freedesktop.org/drm/intel/issues/3283


Participating hosts (44 -> 38)
------------------------------

  Missing    (6): fi-kbl-soraka fi-ilk-m540 fi-hsw-4200u fi-bsw-cyan fi-dg1-1 fi-bdw-samus 


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_6077 -> IGTPW_5769

  CI-20190529: 20190529
  CI_DRM_10023: a8bf9e284933fa5c1cb821b48ba95821e5d1cc3f @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_5769: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/index.html
  IGT_6077: 126a3f6fc0e97786e2819085efc84e741093aed5 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools



== Testlist changes ==

+igt@i915_query@cs-cycles
+igt@i915_query@cs-cycles-invalid

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/index.html

[-- Attachment #1.2: Type: text/html, Size: 3464 bytes --]

[-- Attachment #2: Type: text/plain, Size: 154 bytes --]

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

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

* [igt-dev] ✓ Fi.CI.IGT: success for i915/perf: Add test to query CS timestamp (rev6)
  2021-04-29  0:29 [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp Umesh Nerlige Ramappa
  2021-04-29  1:25 ` [igt-dev] ✓ Fi.CI.BAT: success for i915/perf: Add test to query CS timestamp (rev6) Patchwork
@ 2021-04-29  2:42 ` Patchwork
  1 sibling, 0 replies; 13+ messages in thread
From: Patchwork @ 2021-04-29  2:42 UTC (permalink / raw)
  To: Umesh Nerlige Ramappa; +Cc: igt-dev


[-- Attachment #1.1: Type: text/plain, Size: 30266 bytes --]

== Series Details ==

Series: i915/perf: Add test to query CS timestamp (rev6)
URL   : https://patchwork.freedesktop.org/series/87553/
State : success

== Summary ==

CI Bug Log - changes from IGT_6077_full -> IGTPW_5769_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/index.html

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_5769_full:

### IGT changes ###

#### Possible regressions ####

  * {igt@i915_query@cs-cycles-invalid} (NEW):
    - shard-iclb:         NOTRUN -> [SKIP][1] +1 similar issue
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb2/igt@i915_query@cs-cycles-invalid.html
    - shard-tglb:         NOTRUN -> [SKIP][2] +1 similar issue
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb2/igt@i915_query@cs-cycles-invalid.html

  
#### Suppressed ####

  The following results come from untrusted machines, tests, or statuses.
  They do not affect the overall result.

  * {igt@kms_dp_tiled_display@basic-test-pattern-with-chamelium}:
    - shard-tglb:         NOTRUN -> [SKIP][3]
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb2/igt@kms_dp_tiled_display@basic-test-pattern-with-chamelium.html
    - shard-iclb:         NOTRUN -> [SKIP][4]
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb2/igt@kms_dp_tiled_display@basic-test-pattern-with-chamelium.html

  
New tests
---------

  New tests have been introduced between IGT_6077_full and IGTPW_5769_full:

### New IGT tests (2) ###

  * igt@i915_query@cs-cycles:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  * igt@i915_query@cs-cycles-invalid:
    - Statuses : 6 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_5769_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_ctx_param@set-priority-not-supported:
    - shard-tglb:         NOTRUN -> [SKIP][5] ([fdo#109314])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb6/igt@gem_ctx_param@set-priority-not-supported.html
    - shard-iclb:         NOTRUN -> [SKIP][6] ([fdo#109314])
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb8/igt@gem_ctx_param@set-priority-not-supported.html

  * igt@gem_ctx_persistence@clone:
    - shard-snb:          NOTRUN -> [SKIP][7] ([fdo#109271] / [i915#1099]) +4 similar issues
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-snb2/igt@gem_ctx_persistence@clone.html

  * igt@gem_eio@in-flight-suspend:
    - shard-kbl:          [PASS][8] -> [INCOMPLETE][9] ([i915#155])
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-kbl3/igt@gem_eio@in-flight-suspend.html
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl3/igt@gem_eio@in-flight-suspend.html

  * igt@gem_exec_fair@basic-none@rcs0:
    - shard-glk:          NOTRUN -> [FAIL][10] ([i915#2842])
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk1/igt@gem_exec_fair@basic-none@rcs0.html

  * igt@gem_exec_fair@basic-none@vcs0:
    - shard-tglb:         NOTRUN -> [FAIL][11] ([i915#2842]) +4 similar issues
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb2/igt@gem_exec_fair@basic-none@vcs0.html

  * igt@gem_exec_fair@basic-none@vcs1:
    - shard-kbl:          NOTRUN -> [FAIL][12] ([i915#2842])
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl3/igt@gem_exec_fair@basic-none@vcs1.html

  * igt@gem_exec_fair@basic-pace-solo@rcs0:
    - shard-kbl:          [PASS][13] -> [FAIL][14] ([i915#2842])
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-kbl7/igt@gem_exec_fair@basic-pace-solo@rcs0.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl1/igt@gem_exec_fair@basic-pace-solo@rcs0.html

  * igt@gem_exec_fair@basic-pace@bcs0:
    - shard-tglb:         [PASS][15] -> [FAIL][16] ([i915#2842]) +1 similar issue
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-tglb1/igt@gem_exec_fair@basic-pace@bcs0.html
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb7/igt@gem_exec_fair@basic-pace@bcs0.html

  * igt@gem_exec_fair@basic-pace@vcs1:
    - shard-iclb:         NOTRUN -> [FAIL][17] ([i915#2842]) +4 similar issues
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb4/igt@gem_exec_fair@basic-pace@vcs1.html

  * igt@gem_exec_reloc@basic-wide-active@bcs0:
    - shard-apl:          NOTRUN -> [FAIL][18] ([i915#2389]) +3 similar issues
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl3/igt@gem_exec_reloc@basic-wide-active@bcs0.html

  * igt@gem_exec_reloc@basic-wide-active@rcs0:
    - shard-snb:          NOTRUN -> [FAIL][19] ([i915#2389]) +2 similar issues
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-snb2/igt@gem_exec_reloc@basic-wide-active@rcs0.html

  * igt@gem_exec_reloc@basic-wide-active@vcs1:
    - shard-iclb:         NOTRUN -> [FAIL][20] ([i915#2389])
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb1/igt@gem_exec_reloc@basic-wide-active@vcs1.html

  * igt@gem_exec_whisper@basic-queues-all:
    - shard-glk:          [PASS][21] -> [DMESG-WARN][22] ([i915#118] / [i915#95]) +1 similar issue
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-glk7/igt@gem_exec_whisper@basic-queues-all.html
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk8/igt@gem_exec_whisper@basic-queues-all.html

  * igt@gem_exec_whisper@basic-queues-forked-all:
    - shard-iclb:         [PASS][23] -> [INCOMPLETE][24] ([i915#1895])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-iclb2/igt@gem_exec_whisper@basic-queues-forked-all.html
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb1/igt@gem_exec_whisper@basic-queues-forked-all.html

  * igt@gem_mmap_gtt@cpuset-medium-copy-xy:
    - shard-iclb:         [PASS][25] -> [FAIL][26] ([i915#307])
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-iclb3/igt@gem_mmap_gtt@cpuset-medium-copy-xy.html
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb6/igt@gem_mmap_gtt@cpuset-medium-copy-xy.html

  * igt@gem_pread@exhaustion:
    - shard-tglb:         NOTRUN -> [WARN][27] ([i915#2658])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb5/igt@gem_pread@exhaustion.html
    - shard-glk:          NOTRUN -> [WARN][28] ([i915#2658])
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk9/igt@gem_pread@exhaustion.html
    - shard-apl:          NOTRUN -> [WARN][29] ([i915#2658])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl1/igt@gem_pread@exhaustion.html
    - shard-iclb:         NOTRUN -> [WARN][30] ([i915#2658])
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb1/igt@gem_pread@exhaustion.html
    - shard-snb:          NOTRUN -> [WARN][31] ([i915#2658])
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-snb6/igt@gem_pread@exhaustion.html
    - shard-kbl:          NOTRUN -> [WARN][32] ([i915#2658])
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl4/igt@gem_pread@exhaustion.html

  * igt@gem_render_copy@y-tiled-mc-ccs-to-vebox-y-tiled:
    - shard-iclb:         NOTRUN -> [SKIP][33] ([i915#768]) +1 similar issue
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb1/igt@gem_render_copy@y-tiled-mc-ccs-to-vebox-y-tiled.html

  * igt@gem_softpin@noreloc-s3:
    - shard-kbl:          [PASS][34] -> [INCOMPLETE][35] ([i915#2405])
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-kbl3/igt@gem_softpin@noreloc-s3.html
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl3/igt@gem_softpin@noreloc-s3.html

  * igt@gem_userptr_blits@dmabuf-sync:
    - shard-apl:          NOTRUN -> [SKIP][36] ([fdo#109271] / [i915#3323])
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl7/igt@gem_userptr_blits@dmabuf-sync.html

  * igt@gem_userptr_blits@dmabuf-unsync:
    - shard-tglb:         NOTRUN -> [SKIP][37] ([i915#3297])
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb2/igt@gem_userptr_blits@dmabuf-unsync.html
    - shard-iclb:         NOTRUN -> [SKIP][38] ([i915#3297])
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb6/igt@gem_userptr_blits@dmabuf-unsync.html

  * igt@gem_userptr_blits@input-checking:
    - shard-snb:          NOTRUN -> [DMESG-WARN][39] ([i915#3002])
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-snb2/igt@gem_userptr_blits@input-checking.html

  * igt@gem_userptr_blits@vma-merge:
    - shard-apl:          NOTRUN -> [FAIL][40] ([i915#3318])
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl2/igt@gem_userptr_blits@vma-merge.html

  * igt@gen3_render_tiledx_blits:
    - shard-iclb:         NOTRUN -> [SKIP][41] ([fdo#109289])
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb1/igt@gen3_render_tiledx_blits.html
    - shard-tglb:         NOTRUN -> [SKIP][42] ([fdo#109289])
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb8/igt@gen3_render_tiledx_blits.html

  * igt@gen9_exec_parse@allowed-all:
    - shard-tglb:         NOTRUN -> [SKIP][43] ([fdo#112306]) +1 similar issue
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb5/igt@gen9_exec_parse@allowed-all.html

  * igt@gen9_exec_parse@basic-rejected:
    - shard-iclb:         NOTRUN -> [SKIP][44] ([fdo#112306])
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb5/igt@gen9_exec_parse@basic-rejected.html

  * igt@i915_pm_dc@dc6-psr:
    - shard-tglb:         NOTRUN -> [FAIL][45] ([i915#454])
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb6/igt@i915_pm_dc@dc6-psr.html

  * igt@i915_pm_lpsp@kms-lpsp@kms-lpsp-dp:
    - shard-apl:          NOTRUN -> [SKIP][46] ([fdo#109271] / [i915#1937])
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl8/igt@i915_pm_lpsp@kms-lpsp@kms-lpsp-dp.html

  * igt@i915_pm_lpsp@kms-lpsp@kms-lpsp-hdmi-a:
    - shard-glk:          NOTRUN -> [SKIP][47] ([fdo#109271] / [i915#1937])
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk3/igt@i915_pm_lpsp@kms-lpsp@kms-lpsp-hdmi-a.html

  * igt@i915_pm_rpm@modeset-pc8-residency-stress:
    - shard-apl:          NOTRUN -> [SKIP][48] ([fdo#109271]) +222 similar issues
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl1/igt@i915_pm_rpm@modeset-pc8-residency-stress.html

  * igt@i915_selftest@live@hangcheck:
    - shard-snb:          [PASS][49] -> [INCOMPLETE][50] ([i915#2782])
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-snb6/igt@i915_selftest@live@hangcheck.html
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-snb6/igt@i915_selftest@live@hangcheck.html

  * igt@kms_big_fb@yf-tiled-addfb-size-overflow:
    - shard-tglb:         NOTRUN -> [SKIP][51] ([fdo#111615]) +5 similar issues
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb8/igt@kms_big_fb@yf-tiled-addfb-size-overflow.html

  * igt@kms_chamelium@dp-hpd-storm-disable:
    - shard-apl:          NOTRUN -> [SKIP][52] ([fdo#109271] / [fdo#111827]) +16 similar issues
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl1/igt@kms_chamelium@dp-hpd-storm-disable.html

  * igt@kms_chamelium@hdmi-audio-edid:
    - shard-kbl:          NOTRUN -> [SKIP][53] ([fdo#109271] / [fdo#111827]) +16 similar issues
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl2/igt@kms_chamelium@hdmi-audio-edid.html

  * igt@kms_color@pipe-a-degamma:
    - shard-tglb:         NOTRUN -> [FAIL][54] ([i915#1149])
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb3/igt@kms_color@pipe-a-degamma.html
    - shard-iclb:         NOTRUN -> [FAIL][55] ([i915#1149])
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb3/igt@kms_color@pipe-a-degamma.html

  * igt@kms_color_chamelium@pipe-b-ctm-red-to-blue:
    - shard-iclb:         NOTRUN -> [SKIP][56] ([fdo#109284] / [fdo#111827]) +2 similar issues
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb8/igt@kms_color_chamelium@pipe-b-ctm-red-to-blue.html
    - shard-glk:          NOTRUN -> [SKIP][57] ([fdo#109271] / [fdo#111827]) +3 similar issues
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk1/igt@kms_color_chamelium@pipe-b-ctm-red-to-blue.html

  * igt@kms_color_chamelium@pipe-c-ctm-red-to-blue:
    - shard-snb:          NOTRUN -> [SKIP][58] ([fdo#109271] / [fdo#111827]) +14 similar issues
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-snb5/igt@kms_color_chamelium@pipe-c-ctm-red-to-blue.html

  * igt@kms_color_chamelium@pipe-d-ctm-red-to-blue:
    - shard-tglb:         NOTRUN -> [SKIP][59] ([fdo#109284] / [fdo#111827]) +4 similar issues
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb8/igt@kms_color_chamelium@pipe-d-ctm-red-to-blue.html
    - shard-iclb:         NOTRUN -> [SKIP][60] ([fdo#109278] / [fdo#109284] / [fdo#111827])
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb1/igt@kms_color_chamelium@pipe-d-ctm-red-to-blue.html

  * igt@kms_content_protection@atomic:
    - shard-apl:          NOTRUN -> [TIMEOUT][61] ([i915#1319]) +1 similar issue
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl7/igt@kms_content_protection@atomic.html

  * igt@kms_content_protection@srm:
    - shard-kbl:          NOTRUN -> [TIMEOUT][62] ([i915#1319])
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl7/igt@kms_content_protection@srm.html

  * igt@kms_content_protection@uevent:
    - shard-apl:          NOTRUN -> [FAIL][63] ([i915#2105])
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl2/igt@kms_content_protection@uevent.html

  * igt@kms_cursor_crc@pipe-a-cursor-512x512-offscreen:
    - shard-iclb:         NOTRUN -> [SKIP][64] ([fdo#109278] / [fdo#109279])
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb1/igt@kms_cursor_crc@pipe-a-cursor-512x512-offscreen.html
    - shard-tglb:         NOTRUN -> [SKIP][65] ([fdo#109279] / [i915#3359])
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb5/igt@kms_cursor_crc@pipe-a-cursor-512x512-offscreen.html

  * igt@kms_cursor_crc@pipe-a-cursor-suspend:
    - shard-kbl:          NOTRUN -> [DMESG-WARN][66] ([i915#180]) +2 similar issues
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl6/igt@kms_cursor_crc@pipe-a-cursor-suspend.html

  * igt@kms_cursor_crc@pipe-b-cursor-32x32-onscreen:
    - shard-tglb:         NOTRUN -> [SKIP][67] ([i915#3319]) +1 similar issue
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb2/igt@kms_cursor_crc@pipe-b-cursor-32x32-onscreen.html

  * igt@kms_cursor_crc@pipe-c-cursor-suspend:
    - shard-apl:          NOTRUN -> [DMESG-WARN][68] ([i915#180])
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl6/igt@kms_cursor_crc@pipe-c-cursor-suspend.html

  * igt@kms_cursor_crc@pipe-d-cursor-256x256-onscreen:
    - shard-kbl:          NOTRUN -> [SKIP][69] ([fdo#109271]) +156 similar issues
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl2/igt@kms_cursor_crc@pipe-d-cursor-256x256-onscreen.html

  * igt@kms_cursor_crc@pipe-d-cursor-dpms:
    - shard-iclb:         NOTRUN -> [SKIP][70] ([fdo#109278]) +7 similar issues
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb2/igt@kms_cursor_crc@pipe-d-cursor-dpms.html

  * igt@kms_cursor_crc@pipe-d-cursor-max-size-rapid-movement:
    - shard-tglb:         NOTRUN -> [SKIP][71] ([i915#3359])
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb5/igt@kms_cursor_crc@pipe-d-cursor-max-size-rapid-movement.html

  * igt@kms_cursor_legacy@cursorb-vs-flipa-varying-size:
    - shard-iclb:         NOTRUN -> [SKIP][72] ([fdo#109274] / [fdo#109278])
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb4/igt@kms_cursor_legacy@cursorb-vs-flipa-varying-size.html

  * igt@kms_fbcon_fbt@fbc-suspend:
    - shard-kbl:          [PASS][73] -> [INCOMPLETE][74] ([i915#155] / [i915#180] / [i915#636])
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-kbl1/igt@kms_fbcon_fbt@fbc-suspend.html
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl7/igt@kms_fbcon_fbt@fbc-suspend.html

  * igt@kms_flip@2x-flip-vs-wf_vblank-interruptible:
    - shard-iclb:         NOTRUN -> [SKIP][75] ([fdo#109274]) +1 similar issue
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb1/igt@kms_flip@2x-flip-vs-wf_vblank-interruptible.html

  * igt@kms_flip@flip-vs-suspend-interruptible@a-dp1:
    - shard-kbl:          [PASS][76] -> [DMESG-WARN][77] ([i915#180]) +8 similar issues
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-kbl1/igt@kms_flip@flip-vs-suspend-interruptible@a-dp1.html
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl4/igt@kms_flip@flip-vs-suspend-interruptible@a-dp1.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytileccs:
    - shard-tglb:         NOTRUN -> [SKIP][78] ([i915#2587])
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb8/igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytileccs.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytilegen12rcccs:
    - shard-apl:          NOTRUN -> [SKIP][79] ([fdo#109271] / [i915#2672])
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl6/igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytilegen12rcccs.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile:
    - shard-apl:          NOTRUN -> [SKIP][80] ([fdo#109271] / [i915#2642])
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl7/igt@kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile.html

  * igt@kms_frontbuffer_tracking@fbcpsr-suspend:
    - shard-glk:          NOTRUN -> [SKIP][81] ([fdo#109271]) +50 similar issues
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk9/igt@kms_frontbuffer_tracking@fbcpsr-suspend.html

  * igt@kms_frontbuffer_tracking@psr-2p-primscrn-shrfb-plflip-blt:
    - shard-iclb:         NOTRUN -> [SKIP][82] ([fdo#109280]) +10 similar issues
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb3/igt@kms_frontbuffer_tracking@psr-2p-primscrn-shrfb-plflip-blt.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-draw-pwrite:
    - shard-tglb:         NOTRUN -> [SKIP][83] ([fdo#111825]) +15 similar issues
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb2/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-draw-pwrite.html

  * igt@kms_hdr@static-toggle:
    - shard-iclb:         NOTRUN -> [SKIP][84] ([i915#1187])
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb2/igt@kms_hdr@static-toggle.html
    - shard-tglb:         NOTRUN -> [SKIP][85] ([i915#1187])
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb7/igt@kms_hdr@static-toggle.html

  * igt@kms_pipe_crc_basic@disable-crc-after-crtc-pipe-d:
    - shard-apl:          NOTRUN -> [SKIP][86] ([fdo#109271] / [i915#533])
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl6/igt@kms_pipe_crc_basic@disable-crc-after-crtc-pipe-d.html

  * igt@kms_pipe_crc_basic@hang-read-crc-pipe-d:
    - shard-kbl:          NOTRUN -> [SKIP][87] ([fdo#109271] / [i915#533])
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl6/igt@kms_pipe_crc_basic@hang-read-crc-pipe-d.html

  * igt@kms_plane_alpha_blend@pipe-a-alpha-transparent-fb:
    - shard-kbl:          NOTRUN -> [FAIL][88] ([i915#265])
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl6/igt@kms_plane_alpha_blend@pipe-a-alpha-transparent-fb.html

  * igt@kms_plane_alpha_blend@pipe-b-alpha-opaque-fb:
    - shard-kbl:          NOTRUN -> [FAIL][89] ([fdo#108145] / [i915#265])
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl3/igt@kms_plane_alpha_blend@pipe-b-alpha-opaque-fb.html

  * igt@kms_plane_alpha_blend@pipe-c-alpha-basic:
    - shard-glk:          NOTRUN -> [FAIL][90] ([fdo#108145] / [i915#265])
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk9/igt@kms_plane_alpha_blend@pipe-c-alpha-basic.html
    - shard-apl:          NOTRUN -> [FAIL][91] ([fdo#108145] / [i915#265]) +2 similar issues
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl1/igt@kms_plane_alpha_blend@pipe-c-alpha-basic.html

  * igt@kms_psr2_sf@overlay-plane-update-sf-dmg-area-2:
    - shard-apl:          NOTRUN -> [SKIP][92] ([fdo#109271] / [i915#658]) +4 similar issues
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl7/igt@kms_psr2_sf@overlay-plane-update-sf-dmg-area-2.html

  * igt@kms_psr2_sf@primary-plane-update-sf-dmg-area-1:
    - shard-iclb:         NOTRUN -> [SKIP][93] ([i915#658])
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb4/igt@kms_psr2_sf@primary-plane-update-sf-dmg-area-1.html
    - shard-glk:          NOTRUN -> [SKIP][94] ([fdo#109271] / [i915#658]) +1 similar issue
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk3/igt@kms_psr2_sf@primary-plane-update-sf-dmg-area-1.html
    - shard-kbl:          NOTRUN -> [SKIP][95] ([fdo#109271] / [i915#658]) +3 similar issues
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl2/igt@kms_psr2_sf@primary-plane-update-sf-dmg-area-1.html

  * igt@kms_psr2_su@page_flip:
    - shard-tglb:         NOTRUN -> [SKIP][96] ([i915#1911])
   [96]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb7/igt@kms_psr2_su@page_flip.html
    - shard-iclb:         NOTRUN -> [SKIP][97] ([fdo#109642] / [fdo#111068] / [i915#658])
   [97]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb4/igt@kms_psr2_su@page_flip.html

  * igt@kms_psr@psr2_primary_page_flip:
    - shard-iclb:         NOTRUN -> [SKIP][98] ([fdo#109441])
   [98]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb5/igt@kms_psr@psr2_primary_page_flip.html

  * igt@kms_psr@psr2_sprite_render:
    - shard-tglb:         NOTRUN -> [FAIL][99] ([i915#132]) +1 similar issue
   [99]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb8/igt@kms_psr@psr2_sprite_render.html

  * igt@kms_psr@psr2_suspend:
    - shard-iclb:         [PASS][100] -> [SKIP][101] ([fdo#109441]) +1 similar issue
   [100]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-iclb2/igt@kms_psr@psr2_suspend.html
   [101]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb4/igt@kms_psr@psr2_suspend.html

  * igt@kms_setmode@basic:
    - shard-snb:          NOTRUN -> [FAIL][102] ([i915#31])
   [102]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-snb2/igt@kms_setmode@basic.html

  * igt@kms_tv_load_detect@load-detect:
    - shard-tglb:         NOTRUN -> [SKIP][103] ([fdo#109309])
   [103]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb2/igt@kms_tv_load_detect@load-detect.html
    - shard-iclb:         NOTRUN -> [SKIP][104] ([fdo#109309])
   [104]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb6/igt@kms_tv_load_detect@load-detect.html

  * igt@kms_vblank@pipe-d-query-forked-hang:
    - shard-snb:          NOTRUN -> [SKIP][105] ([fdo#109271]) +306 similar issues
   [105]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-snb5/igt@kms_vblank@pipe-d-query-forked-hang.html

  * igt@kms_vrr@flip-suspend:
    - shard-iclb:         NOTRUN -> [SKIP][106] ([fdo#109502])
   [106]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb2/igt@kms_vrr@flip-suspend.html
    - shard-tglb:         NOTRUN -> [SKIP][107] ([fdo#109502])
   [107]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb5/igt@kms_vrr@flip-suspend.html

  * igt@kms_writeback@writeback-fb-id:
    - shard-kbl:          NOTRUN -> [SKIP][108] ([fdo#109271] / [i915#2437]) +1 similar issue
   [108]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl3/igt@kms_writeback@writeback-fb-id.html

  * igt@kms_writeback@writeback-invalid-parameters:
    - shard-apl:          NOTRUN -> [SKIP][109] ([fdo#109271] / [i915#2437])
   [109]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl3/igt@kms_writeback@writeback-invalid-parameters.html

  * igt@nouveau_crc@pipe-a-source-rg:
    - shard-iclb:         NOTRUN -> [SKIP][110] ([i915#2530])
   [110]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb8/igt@nouveau_crc@pipe-a-source-rg.html
    - shard-tglb:         NOTRUN -> [SKIP][111] ([i915#2530]) +1 similar issue
   [111]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb6/igt@nouveau_crc@pipe-a-source-rg.html

  * igt@nouveau_crc@pipe-d-source-outp-complete:
    - shard-iclb:         NOTRUN -> [SKIP][112] ([fdo#109278] / [i915#2530])
   [112]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb1/igt@nouveau_crc@pipe-d-source-outp-complete.html

  * igt@perf@polling-parameterized:
    - shard-iclb:         [PASS][113] -> [FAIL][114] ([i915#1542])
   [113]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-iclb7/igt@perf@polling-parameterized.html
   [114]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb5/igt@perf@polling-parameterized.html

  * igt@prime_nv_api@nv_self_import:
    - shard-iclb:         NOTRUN -> [SKIP][115] ([fdo#109291]) +1 similar issue
   [115]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb3/igt@prime_nv_api@nv_self_import.html

  * igt@prime_nv_pcopy@test1_macro:
    - shard-tglb:         NOTRUN -> [SKIP][116] ([fdo#109291]) +1 similar issue
   [116]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb2/igt@prime_nv_pcopy@test1_macro.html

  * igt@sysfs_clients@create:
    - shard-glk:          NOTRUN -> [SKIP][117] ([fdo#109271] / [i915#2994])
   [117]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk6/igt@sysfs_clients@create.html
    - shard-tglb:         NOTRUN -> [SKIP][118] ([i915#2994])
   [118]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb6/igt@sysfs_clients@create.html
    - shard-apl:          NOTRUN -> [SKIP][119] ([fdo#109271] / [i915#2994]) +2 similar issues
   [119]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-apl2/igt@sysfs_clients@create.html
    - shard-iclb:         NOTRUN -> [SKIP][120] ([i915#2994])
   [120]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb3/igt@sysfs_clients@create.html

  * igt@sysfs_clients@sema-25:
    - shard-kbl:          NOTRUN -> [SKIP][121] ([fdo#109271] / [i915#2994]) +2 similar issues
   [121]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl1/igt@sysfs_clients@sema-25.html

  
#### Possible fixes ####

  * igt@gem_create@create-clear:
    - shard-glk:          [FAIL][122] ([i915#1888] / [i915#3160]) -> [PASS][123]
   [122]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-glk1/igt@gem_create@create-clear.html
   [123]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk4/igt@gem_create@create-clear.html

  * igt@gem_ctx_persistence@many-contexts:
    - shard-tglb:         [FAIL][124] ([i915#2410]) -> [PASS][125]
   [124]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-tglb8/igt@gem_ctx_persistence@many-contexts.html
   [125]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb7/igt@gem_ctx_persistence@many-contexts.html

  * igt@gem_exec_fair@basic-pace@rcs0:
    - shard-tglb:         [FAIL][126] ([i915#2842]) -> [PASS][127]
   [126]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-tglb1/igt@gem_exec_fair@basic-pace@rcs0.html
   [127]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb7/igt@gem_exec_fair@basic-pace@rcs0.html

  * igt@gem_exec_fair@basic-pace@vcs0:
    - shard-iclb:         [FAIL][128] ([i915#2842]) -> [PASS][129]
   [128]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-iclb3/igt@gem_exec_fair@basic-pace@vcs0.html
   [129]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-iclb4/igt@gem_exec_fair@basic-pace@vcs0.html
    - shard-kbl:          [FAIL][130] ([i915#2842]) -> [PASS][131]
   [130]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-kbl1/igt@gem_exec_fair@basic-pace@vcs0.html
   [131]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl7/igt@gem_exec_fair@basic-pace@vcs0.html

  * igt@gem_exec_fair@basic-throttle@rcs0:
    - shard-glk:          [FAIL][132] ([i915#2842]) -> [PASS][133]
   [132]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-glk9/igt@gem_exec_fair@basic-throttle@rcs0.html
   [133]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk8/igt@gem_exec_fair@basic-throttle@rcs0.html

  * igt@gem_mmap_gtt@big-copy:
    - shard-glk:          [FAIL][134] ([i915#307]) -> [PASS][135]
   [134]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-glk6/igt@gem_mmap_gtt@big-copy.html
   [135]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-glk3/igt@gem_mmap_gtt@big-copy.html

  * igt@kms_cursor_edge_walk@pipe-a-256x256-right-edge:
    - shard-tglb:         [FAIL][136] -> [PASS][137]
   [136]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-tglb7/igt@kms_cursor_edge_walk@pipe-a-256x256-right-edge.html
   [137]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-tglb8/igt@kms_cursor_edge_walk@pipe-a-256x256-right-edge.html

  * igt@kms_frontbuffer_tracking@fbc-suspend:
    - shard-kbl:          [DMESG-WARN][138] ([i915#180]) -> [PASS][139] +2 similar issues
   [138]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_6077/shard-kbl6/igt@kms_frontbuffer_tracking@fbc-suspend.html
   [139]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/shard-kbl2/igt@kms_frontbuffer_tracking@fbc-suspend.html

  * igt@kms_psr@psr2_cursor_render:
    - shard-iclb:         [SKIP][140] ([fdo#109441

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_5769/index.html

[-- Attachment #1.2: Type: text/html, Size: 34046 bytes --]

[-- Attachment #2: Type: text/plain, Size: 154 bytes --]

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

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

* [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
@ 2021-05-04  0:10 Umesh Nerlige Ramappa
  0 siblings, 0 replies; 13+ messages in thread
From: Umesh Nerlige Ramappa @ 2021-05-04  0:10 UTC (permalink / raw)
  To: igt-dev

Add tests to query CS timestamps for different engines.

v2:
- remove flag parameter
- assert for minimum usable values rather than maximum

v3:
- use clock id for cpu timestamps (Lionel)
- check if query is supported (Ashutosh)
- test bad queries

v4: (Chris, Tvrtko)
- cs_timestamp is a misnomer, use cs_cycles instead
- use cs cycle frequency returned in the query
- omit size parameter

v5:
- use __for_each_physical_engine (Lionel)
- check for ENODEV (Umesh)

v6: Use 2 cpu timestamps to calculate reg read time (Lionel)
v7: Refactor test code and add a spinner (Chris)
v8: Update cpu_timestamp array split into timestamp and delta
v9: Update test and api with width

Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
 include/drm-uapi/i915_drm.h |  56 +++++++++++
 tests/i915/i915_query.c     | 195 ++++++++++++++++++++++++++++++++++++
 2 files changed, 251 insertions(+)

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index bf9ea471..f68306e0 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
 #define DRM_I915_QUERY_TOPOLOGY_INFO    1
 #define DRM_I915_QUERY_ENGINE_INFO	2
 #define DRM_I915_QUERY_PERF_CONFIG      3
+	/**
+	 * Query Command Streamer timestamp register.
+	 */
+#define DRM_I915_QUERY_CS_CYCLES	4
 /* Must be kept compact -- no holes and well documented */
 
 	/*
@@ -2309,6 +2313,58 @@ struct drm_i915_engine_info {
 	__u64 rsvd1[4];
 };
 
+/**
+ * struct drm_i915_query_cs_cycles
+ *
+ * The query returns the command streamer cycles, the frequency that can be
+ * used to calculate the command streamer timestamp, a cpu timestamp indicating
+ * when the cs cycles was captured and a cpu_delta capturing time taken to read
+ * the cs_cycles register.
+ */
+struct drm_i915_query_cs_cycles {
+	/** @engine: Engine for which command streamer cycles is queried. */
+	struct i915_engine_class_instance engine;
+
+	/** @flags: MBZ */
+	__u32 flags;
+
+	/**
+	 * @cs_cycles: Command streamer cycles as read from the command streamer
+	 * register at 0x358 offset.
+	 */
+	__u64 cs_cycles;
+
+	/** @cs_frequency: Frequency of the cs cycles in Hz. */
+	__u64 cs_frequency;
+
+	/** @width: Width of the cs cycles in bits. */
+	__u64 width;
+
+	/**
+	 * @cpu_timestamp: CPU timestamp in ns. The timestamp is captured before
+	 * reading the cs_cycles register using the reference clockid set by the
+	 * user.
+	 */
+	__u64 cpu_timestamp;
+
+	/**
+	 * @cpu_delta: Time delta in ns captured around reading the lower dword
+	 * of the cs_cycles register.
+	 */
+	__u64 cpu_delta;
+
+	/**
+	 * @clockid: Reference clock id for CPU timestamp. For definition, see
+	 * clock_gettime(2) and perf_event_open(2). Supported clock ids are
+	 * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
+	 * CLOCK_TAI.
+	 */
+	__s32 clockid;
+
+	/** @rsvd: MBZ */
+	__u32 rsvd;
+};
+
 /**
  * struct drm_i915_query_engine_info
  *
diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
index 29b938e9..38f06ae8 100644
--- a/tests/i915/i915_query.c
+++ b/tests/i915/i915_query.c
@@ -267,6 +267,189 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
 				eu / 8] >> (eu % 8)) & 1;
 }
 
+static int __query_cs_cycles(int i915, void *data)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+		.data_ptr = to_user_pointer(data),
+		.length = data ? sizeof(struct drm_i915_query_cs_cycles) : 0,
+	};
+
+	i915_query_items(i915, &item, 1);
+
+	return item.length;
+}
+
+static bool query_cs_cycles_supported(int fd)
+{
+	return __query_cs_cycles(fd, NULL) > 0;
+}
+
+static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
+{
+	struct drm_i915_query_cs_cycles ts = {
+		.engine = { class, instance }
+	};
+
+	return __query_cs_cycles(i915, &ts) != -ENODEV;
+}
+
+static void
+__cs_cycles(int i915, struct i915_engine_class_instance *engine)
+{
+	struct drm_i915_query_cs_cycles ts1 = {};
+	struct drm_i915_query_cs_cycles ts2 = {};
+	uint64_t delta_cpu, delta_cs, delta_delta;
+	int i, usable = 0;
+	igt_spin_t *spin;
+	uint32_t ctx;
+	struct {
+		int32_t id;
+		const char *name;
+	} clock[] = {
+		{ CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
+		{ CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
+		{ CLOCK_REALTIME, "CLOCK_REALTIME" },
+		{ CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
+		{ CLOCK_TAI, "CLOCK_TAI" },
+	};
+
+	igt_debug("engine[%u:%u]\n",
+		  engine->engine_class,
+		  engine->engine_instance);
+
+	ctx = gem_context_create_for_engine(i915,
+					    engine->engine_class,
+					    engine->engine_instance);
+	spin = igt_spin_new(i915, ctx);
+
+	/* Try a new clock every 10 iterations. */
+#define NUM_SNAPSHOTS 10
+	for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
+		int index = i / NUM_SNAPSHOTS;
+
+		ts1.engine = *engine;
+		ts1.clockid = clock[index].id;
+
+		ts2.engine = *engine;
+		ts2.clockid = clock[index].id;
+
+		igt_assert_eq(__query_cs_cycles(i915, &ts1), sizeof(ts1));
+		igt_assert_eq(__query_cs_cycles(i915, &ts2), sizeof(ts2));
+
+		igt_debug("[1] cpu_ts before %llu, reg read time %llu\n",
+			  ts1.cpu_timestamp,
+			  ts1.cpu_delta);
+		igt_debug("[1] cs_ts %llu, freq %llu Hz, width %llu\n",
+			  ts1.cs_cycles, ts1.cs_frequency, ts1.width);
+
+		igt_debug("[2] cpu_ts before %llu, reg read time %llu\n",
+			  ts2.cpu_timestamp,
+			  ts2.cpu_delta);
+		igt_debug("[2] cs_ts %llu, freq %llu Hz, width %llu\n",
+			  ts2.cs_cycles, ts2.cs_frequency, ts2.width);
+
+		delta_cpu = ts2.cpu_timestamp - ts1.cpu_timestamp;
+
+		if (ts2.cs_cycles >= ts1.cs_cycles)
+			delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
+				   NSEC_PER_SEC / ts1.cs_frequency;
+		else
+			delta_cs = (((1 << ts2.width) - ts2.cs_cycles) + ts1.cs_cycles) *
+				   NSEC_PER_SEC / ts1.cs_frequency;
+
+		igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
+			  delta_cpu, delta_cs);
+
+		delta_delta = delta_cpu > delta_cs ?
+			       delta_cpu - delta_cs :
+			       delta_cs - delta_cpu;
+		igt_debug("delta_delta %lu\n", delta_delta);
+
+		if (delta_delta < 5000)
+			usable++;
+
+		/*
+		 * User needs few good snapshots of the timestamps to
+		 * synchronize cpu time with cs time. Check if we have enough
+		 * usable values before moving to the next clockid.
+		 */
+		if (!((i + 1) % NUM_SNAPSHOTS)) {
+			igt_debug("clock %s\n", clock[index].name);
+			igt_debug("usable %d\n", usable);
+			igt_assert(usable > 2);
+			usable = 0;
+		}
+	}
+
+	gem_context_destroy(i915, ctx);
+	igt_spin_free(i915, spin);
+}
+
+static void test_cs_cycles(int i915)
+{
+	const struct intel_execution_engine2 *e;
+	struct i915_engine_class_instance engine;
+
+	__for_each_physical_engine(i915, e) {
+		if (engine_has_cs_cycles(i915, e->class, e->instance)) {
+			engine.engine_class = e->class;
+			engine.engine_instance = e->instance;
+			__cs_cycles(i915, &engine);
+		}
+	}
+}
+
+static void test_cs_cycles_invalid(int i915)
+{
+	struct i915_engine_class_instance engine;
+	const struct intel_execution_engine2 *e;
+	struct drm_i915_query_cs_cycles ts = {};
+
+	/* get one engine */
+	__for_each_physical_engine(i915, e)
+		break;
+
+	/* sanity check engine selection is valid */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), sizeof(ts));
+
+	/* bad engines */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* non zero flags */
+	ts.flags = 1;
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* non zero rsvd field */
+	ts.flags = 0;
+	ts.rsvd = 1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* bad clockid */
+	ts.rsvd = 0;
+	ts.clockid = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* sanity check */
+	engine.engine_class = e->class;
+	engine.engine_instance = e->instance;
+	__cs_cycles(i915, &engine);
+}
+
 /*
  * Verify that we get coherent values between the legacy getparam slice/subslice
  * masks and the new topology query.
@@ -783,6 +966,18 @@ igt_main
 			engines(fd);
 	}
 
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(query_cs_cycles_supported(fd));
+		}
+
+		igt_subtest("cs-cycles-invalid")
+			test_cs_cycles_invalid(fd);
+
+		igt_subtest("cs-cycles")
+			test_cs_cycles(fd);
+	}
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.20.1

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

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

* [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
@ 2021-04-21 17:20 Umesh Nerlige Ramappa
  0 siblings, 0 replies; 13+ messages in thread
From: Umesh Nerlige Ramappa @ 2021-04-21 17:20 UTC (permalink / raw)
  To: igt-dev

Add tests to query CS timestamps for different engines.

v2:
- remove flag parameter
- assert for minimum usable values rather than maximum

v3:
- use clock id for cpu timestamps (Lionel)
- check if query is supported (Ashutosh)
- test bad queries

v4: (Chris, Tvrtko)
- cs_timestamp is a misnomer, use cs_cycles instead
- use cs cycle frequency returned in the query
- omit size parameter

v5:
- use __for_each_physical_engine (Lionel)
- check for ENODEV (Umesh)

v6: Use 2 cpu timestamps to calculate reg read time (Lionel)
v7: Refactor test code and add a spinner (Chris)

Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
 include/drm-uapi/i915_drm.h |  48 +++++++++
 tests/i915/i915_query.c     | 190 ++++++++++++++++++++++++++++++++++++
 2 files changed, 238 insertions(+)

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index bf9ea471..0e50302f 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
 #define DRM_I915_QUERY_TOPOLOGY_INFO    1
 #define DRM_I915_QUERY_ENGINE_INFO	2
 #define DRM_I915_QUERY_PERF_CONFIG      3
+	/**
+	 * Query Command Streamer timestamp register.
+	 */
+#define DRM_I915_QUERY_CS_CYCLES	4
 /* Must be kept compact -- no holes and well documented */
 
 	/*
@@ -2309,6 +2313,50 @@ struct drm_i915_engine_info {
 	__u64 rsvd1[4];
 };
 
+/**
+ * struct drm_i915_query_cs_cycles
+ *
+ * The query returns the command streamer cycles and the frequency that can be
+ * used to calculate the command streamer timestamp. In addition the query
+ * returns a set of cpu timestamps that indicate when the command streamer cycle
+ * count was captured.
+ */
+struct drm_i915_query_cs_cycles {
+	/** Engine for which command streamer cycles is queried. */
+	struct i915_engine_class_instance engine;
+
+	/** Must be zero. */
+	__u32 flags;
+
+	/**
+	 * Command streamer cycles as read from the command streamer
+	 * register at 0x358 offset.
+	 */
+	__u64 cs_cycles;
+
+	/** Frequency of the cs cycles in Hz. */
+	__u64 cs_frequency;
+
+	/**
+	 * CPU timestamps in ns. cpu_timestamp[0] is captured before reading the
+	 * cs_cycles register using the reference clockid set by the user.
+	 * cpu_timestamp[1] is the time taken in ns to read the lower dword of
+	 * the cs_cycles register.
+	 */
+	__u64 cpu_timestamp[2];
+
+	/**
+	 * Reference clock id for CPU timestamp. For definition, see
+	 * clock_gettime(2) and perf_event_open(2). Supported clock ids are
+	 * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
+	 * CLOCK_TAI.
+	 */
+	__s32 clockid;
+
+	/** Must be zero. */
+	__u32 rsvd;
+};
+
 /**
  * struct drm_i915_query_engine_info
  *
diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
index 29b938e9..173b4c56 100644
--- a/tests/i915/i915_query.c
+++ b/tests/i915/i915_query.c
@@ -267,6 +267,184 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
 				eu / 8] >> (eu % 8)) & 1;
 }
 
+static int __query_cs_cycles(int i915, void *data)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+		.data_ptr = to_user_pointer(data),
+		.length = data ? sizeof(struct drm_i915_query_cs_cycles) : 0,
+	};
+
+	i915_query_items(i915, &item, 1);
+
+	return item.length;
+}
+
+static bool query_cs_cycles_supported(int fd)
+{
+	return __query_cs_cycles(fd, NULL) > 0;
+}
+
+static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
+{
+	struct drm_i915_query_cs_cycles ts = {
+		.engine = { class, instance }
+	};
+
+	return __query_cs_cycles(i915, &ts) != -ENODEV;
+}
+
+static void
+__cs_cycles(int i915, struct i915_engine_class_instance *engine)
+{
+	struct drm_i915_query_cs_cycles ts1 = {};
+	struct drm_i915_query_cs_cycles ts2 = {};
+	uint64_t delta_cpu, delta_cs, delta_delta;
+	int i, usable = 0;
+	igt_spin_t *spin;
+	uint32_t ctx;
+	struct {
+		int32_t id;
+		const char *name;
+	} clock[] = {
+		{ CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
+		{ CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
+		{ CLOCK_REALTIME, "CLOCK_REALTIME" },
+		{ CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
+		{ CLOCK_TAI, "CLOCK_TAI" },
+	};
+
+	igt_debug("engine[%u:%u]\n",
+		  engine->engine_class,
+		  engine->engine_instance);
+
+	ctx = gem_context_create_for_engine(i915,
+					    engine->engine_class,
+					    engine->engine_instance);
+	spin = igt_spin_new(i915, ctx);
+
+	/* Try a new clock every 10 iterations. */
+#define NUM_SNAPSHOTS 10
+	for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
+		int index = i / NUM_SNAPSHOTS;
+
+		ts1.engine = *engine;
+		ts1.clockid = clock[index].id;
+
+		ts2.engine = *engine;
+		ts2.clockid = clock[index].id;
+
+		igt_assert_eq(__query_cs_cycles(i915, &ts1), sizeof(ts1));
+		igt_assert_eq(__query_cs_cycles(i915, &ts2), sizeof(ts2));
+
+		igt_debug("[1] cpu_ts before %llu, reg read time %llu\n",
+			  ts1.cpu_timestamp[0],
+			  ts1.cpu_timestamp[1]);
+		igt_debug("[1] cs_ts %llu, freq %llu Hz\n",
+			  ts1.cs_cycles, ts1.cs_frequency);
+
+		igt_debug("[2] cpu_ts before %llu, reg read time %llu\n",
+			  ts2.cpu_timestamp[0],
+			  ts2.cpu_timestamp[1]);
+		igt_debug("[2] cs_ts %llu, freq %llu Hz\n",
+			  ts2.cs_cycles, ts2.cs_frequency);
+
+		delta_cpu = ts2.cpu_timestamp[0] - ts1.cpu_timestamp[0];
+		delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
+			   NSEC_PER_SEC / ts1.cs_frequency;
+
+		igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
+			  delta_cpu, delta_cs);
+
+		delta_delta = delta_cpu > delta_cs ?
+			       delta_cpu - delta_cs :
+			       delta_cs - delta_cpu;
+		igt_debug("delta_delta %lu\n", delta_delta);
+
+		if (delta_delta < 5000)
+			usable++;
+
+		/*
+		 * User needs few good snapshots of the timestamps to
+		 * synchronize cpu time with cs time. Check if we have enough
+		 * usable values before moving to the next clockid.
+		 */
+		if (!((i + 1) % NUM_SNAPSHOTS)) {
+			igt_debug("clock %s\n", clock[index].name);
+			igt_debug("usable %d\n", usable);
+			igt_assert(usable > 2);
+			usable = 0;
+		}
+	}
+
+	gem_context_destroy(i915, ctx);
+	igt_spin_free(i915, spin);
+}
+
+static void test_cs_cycles(int i915)
+{
+	const struct intel_execution_engine2 *e;
+	struct i915_engine_class_instance engine;
+
+	__for_each_physical_engine(i915, e) {
+		if (engine_has_cs_cycles(i915, e->class, e->instance)) {
+			engine.engine_class = e->class;
+			engine.engine_instance = e->instance;
+			__cs_cycles(i915, &engine);
+		}
+	}
+}
+
+static void test_cs_cycles_invalid(int i915)
+{
+	struct i915_engine_class_instance engine;
+	const struct intel_execution_engine2 *e;
+	struct drm_i915_query_cs_cycles ts = {};
+
+	/* get one engine */
+	__for_each_physical_engine(i915, e)
+		break;
+
+	/* sanity check engine selection is valid */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), sizeof(ts));
+
+	/* bad engines */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* non zero flags */
+	ts.flags = 1;
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* non zero rsvd field */
+	ts.flags = 0;
+	ts.rsvd = 1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* bad clockid */
+	ts.rsvd = 0;
+	ts.clockid = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* sanity check */
+	engine.engine_class = e->class;
+	engine.engine_instance = e->instance;
+	__cs_cycles(i915, &engine);
+}
+
 /*
  * Verify that we get coherent values between the legacy getparam slice/subslice
  * masks and the new topology query.
@@ -783,6 +961,18 @@ igt_main
 			engines(fd);
 	}
 
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(query_cs_cycles_supported(fd));
+		}
+
+		igt_subtest("cs-cycles-invalid")
+			test_cs_cycles_invalid(fd);
+
+		igt_subtest("cs-cycles")
+			test_cs_cycles(fd);
+	}
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.20.1

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

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

* Re: [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
  2021-03-05 20:33 ` Chris Wilson
@ 2021-03-13  6:04   ` Umesh Nerlige Ramappa
  0 siblings, 0 replies; 13+ messages in thread
From: Umesh Nerlige Ramappa @ 2021-03-13  6:04 UTC (permalink / raw)
  To: Chris Wilson; +Cc: igt-dev

On Fri, Mar 05, 2021 at 08:33:25PM +0000, Chris Wilson wrote:
>Quoting Umesh Nerlige Ramappa (2021-03-05 19:37:08)
>> Add tests to query CS timestamps for different engines.
>>
>> v2:
>> - remove flag parameter
>> - assert for minimum usable values rather than maximum
>>
>> v3:
>> - use clock id for cpu timestamps (Lionel)
>> - check if query is supported (Ashutosh)
>> - test bad queries
>>
>> v4: (Chris, Tvrtko)
>> - cs_timestamp is a misnomer, use cs_cycles instead
>> - use cs cycle frequency returned in the query
>> - omit size parameter
>>
>> v5:
>> - use __for_each_physical_engine (Lionel)
>> - check for ENODEV (Umesh)
>>
>> v6: Use 2 cpu timestamps to calculate reg read time (Lionel)
>>
>> Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
>> ---
>>  include/drm-uapi/i915_drm.h |  48 +++++++++
>>  tests/i915/i915_query.c     | 189 ++++++++++++++++++++++++++++++++++++
>>  2 files changed, 237 insertions(+)
>>
>> diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
>> index bf9ea471..0e50302f 100644
>> --- a/include/drm-uapi/i915_drm.h
>> +++ b/include/drm-uapi/i915_drm.h
>> @@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
>>  #define DRM_I915_QUERY_TOPOLOGY_INFO    1
>>  #define DRM_I915_QUERY_ENGINE_INFO     2
>>  #define DRM_I915_QUERY_PERF_CONFIG      3
>> +       /**
>> +        * Query Command Streamer timestamp register.
>> +        */
>> +#define DRM_I915_QUERY_CS_CYCLES       4
>>  /* Must be kept compact -- no holes and well documented */
>>
>>         /*
>> @@ -2309,6 +2313,50 @@ struct drm_i915_engine_info {
>>         __u64 rsvd1[4];
>>  };
>>
>> +/**
>> + * struct drm_i915_query_cs_cycles
>> + *
>> + * The query returns the command streamer cycles and the frequency that can be
>> + * used to calculate the command streamer timestamp. In addition the query
>> + * returns a set of cpu timestamps that indicate when the command streamer cycle
>> + * count was captured.
>> + */
>> +struct drm_i915_query_cs_cycles {
>> +       /** Engine for which command streamer cycles is queried. */
>> +       struct i915_engine_class_instance engine;
>> +
>> +       /** Must be zero. */
>> +       __u32 flags;
>> +
>> +       /**
>> +        * Command streamer cycles as read from the command streamer
>> +        * register at 0x358 offset.
>> +        */
>> +       __u64 cs_cycles;
>> +
>> +       /** Frequency of the cs cycles in Hz. */
>> +       __u64 cs_frequency;
>> +
>> +       /**
>> +        * CPU timestamps in ns. cpu_timestamp[0] is captured before reading the
>> +        * cs_cycles register using the reference clockid set by the user.
>> +        * cpu_timestamp[1] is the time taken in ns to read the lower dword of
>> +        * the cs_cycles register.
>> +        */
>> +       __u64 cpu_timestamp[2];
>> +
>> +       /**
>> +        * Reference clock id for CPU timestamp. For definition, see
>> +        * clock_gettime(2) and perf_event_open(2). Supported clock ids are
>> +        * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
>> +        * CLOCK_TAI.
>> +        */
>> +       __s32 clockid;
>> +
>> +       /** Must be zero. */
>> +       __u32 rsvd;
>> +};
>> +
>>  /**
>>   * struct drm_i915_query_engine_info
>>   *
>> diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
>> index 29b938e9..2ab3905b 100644
>> --- a/tests/i915/i915_query.c
>> +++ b/tests/i915/i915_query.c
>> @@ -267,6 +267,182 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
>>                                 eu / 8] >> (eu % 8)) & 1;
>>  }
>>
>> +static bool query_cs_cycles_supported(int fd)
>> +{
>> +       struct drm_i915_query_item item = {
>> +               .query_id = DRM_I915_QUERY_CS_CYCLES,
>> +       };
>> +
>> +       return __i915_query_items(fd, &item, 1) == 0 && item.length > 0;
>> +}
>> +
>> +static void __query_cs_cycles(int i915, void *data, int err)
>> +{
>> +       struct drm_i915_query_item item = {
>> +               .query_id = DRM_I915_QUERY_CS_CYCLES,
>> +               .data_ptr = to_user_pointer(data),
>> +               .length = sizeof(struct drm_i915_query_cs_cycles),
>> +       };
>> +
>> +       i915_query_items(i915, &item, 1);
>> +
>> +       if (err)
>> +               igt_assert(item.length == -err);
>
>igt_assert_eq(item.length, -err);
>
>s/err/expect/
>
>I was looking for how err was being returned from i915_query_items....
>
>And might as well pass in -EINVAL.
>
>
>> +}
>> +
>> +static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
>> +{
>> +       struct drm_i915_query_cs_cycles ts = {};
>> +       struct drm_i915_query_item item = {
>> +               .query_id = DRM_I915_QUERY_CS_CYCLES,
>> +               .data_ptr = to_user_pointer(&ts),
>> +               .length = sizeof(struct drm_i915_query_cs_cycles),
>> +       };
>> +
>> +       ts.engine.engine_class = class;
>> +       ts.engine.engine_instance = instance;
>> +
>> +       i915_query_items(i915, &item, 1);
>> +
>> +       return item.length != -ENODEV;
>> +}
>
>
>Let's refactor the duplicated code
>
>static void __query_cs_cycles(int i915, void *data)
>{
>       struct drm_i915_query_item item = {
>               .query_id = DRM_I915_QUERY_CS_CYCLES,
>               .data_ptr = to_user_pointer(data),
>               .length = sizeof(struct drm_i915_query_cs_cycles),
>       };
>
>       i915_query_items(i915, &item, 1);
>       return item.length;
>}
>
>static bool query_cs_cycles_supported(int fd)
>{

Thanks for breaking this down. I sent out a new version with these 
changes. The only thing different is that I need to pass .length = 0 to 
query for support. Otherwise I see EFAULT due to NULL data on platforms 
that support this query.

Regards,
Umesh

>	return __query_cs_cycles(fd, NULL) > 0;
>}
>
>static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
>{
>       struct drm_i915_query_cs_cycles ts = {
>	       .engine = { class, instance }
>       };
>
>       return __query_cs_cycles(i915, &ts) != -ENODEV;
>}
>
>> +static void
>> +__cs_cycles(int i915, struct i915_engine_class_instance *engine)
>> +{
>> +       struct drm_i915_query_cs_cycles ts1 = {};
>> +       struct drm_i915_query_cs_cycles ts2 = {};
>> +       uint64_t delta_cpu, delta_cs, delta_delta;
>> +       int i, usable = 0;
>> +       struct {
>> +               int32_t id;
>> +               const char *name;
>> +       } clock[] = {
>> +               { CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
>> +               { CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
>> +               { CLOCK_REALTIME, "CLOCK_REALTIME" },
>> +               { CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
>> +               { CLOCK_TAI, "CLOCK_TAI" },
>> +       };
>> +
>> +       igt_debug("engine[%u:%u]\n",
>> +                 engine->engine_class,
>> +                 engine->engine_instance);
>> +
>> +       /* Try a new clock every 10 iterations. */
>> +#define NUM_SNAPSHOTS 10
>> +       for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
>> +               int index = i / NUM_SNAPSHOTS;
>> +
>> +               ts1.engine = *engine;
>> +               ts1.clockid = clock[index].id;
>> +
>> +               ts2.engine = *engine;
>> +               ts2.clockid = clock[index].id;
>> +
>> +               __query_cs_cycles(i915, &ts1, 0);
>> +               __query_cs_cycles(i915, &ts2, 0);
>
>igt_assert_eq(__query_cs_cycles(i915, &ts1), 0);
>igt_assert_eq(__query_cs_cycles(i915, &ts2), 0);
>
>> +
>> +               igt_debug("[1] cpu_ts before %llu, reg read time %llu\n",
>> +                         ts1.cpu_timestamp[0],
>> +                         ts1.cpu_timestamp[1]);
>> +               igt_debug("[1] cs_ts %llu, freq %llu Hz\n",
>> +                         ts1.cs_cycles, ts1.cs_frequency);
>> +
>> +               igt_debug("[2] cpu_ts before %llu, reg read time %llu\n",
>> +                         ts2.cpu_timestamp[0],
>> +                         ts2.cpu_timestamp[1]);
>> +               igt_debug("[2] cs_ts %llu, freq %llu Hz\n",
>> +                         ts2.cs_cycles, ts2.cs_frequency);
>> +
>> +               delta_cpu = ts2.cpu_timestamp[0] - ts1.cpu_timestamp[0];
>> +               delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
>> +                          NSEC_PER_SEC / ts1.cs_frequency;
>> +
>> +               igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
>> +                         delta_cpu, delta_cs);
>> +
>> +               delta_delta = delta_cpu > delta_cs ?
>> +                              delta_cpu - delta_cs :
>> +                              delta_cs - delta_cpu;
>> +               igt_debug("delta_delta %lu\n", delta_delta);
>> +
>> +               if (delta_delta < 5000)
>> +                       usable++;
>
>Nothing is keeping the CS awake, its counter is allowed to switch off
>between reads.
>
>I would run this test with a spinner in the background
>
>uint32_t ctx = gem_context_create_for_engine(i915, engine.class, engine.instance);
>igt_spin_t *spin = igt_spin_new(i915, ctx);
>gem_context_destroy(i915, ctx);
>
>...
>
>igt_spin_free(i915, spin);
>
>And even repeat the test to see if the counter does switch off. Although
>we can hypothesis that one day it may be replaced by an always running
>counter.
>
>> +
>> +               /*
>> +                * User needs few good snapshots of the timestamps to
>> +                * synchronize cpu time with cs time. Check if we have enough
>> +                * usable values before moving to the next clockid.
>> +                */
>> +               if (!((i + 1) % NUM_SNAPSHOTS)) {
>> +                       igt_debug("clock %s\n", clock[index].name);
>> +                       igt_debug("usable %d\n", usable);
>> +                       igt_assert(usable > 2);
>> +                       usable = 0;
>> +               }
>> +       }
>> +}
>> +
>> +static void test_cs_cycles(int i915)
>> +{
>> +       const struct intel_execution_engine2 *e;
>> +       struct i915_engine_class_instance engine;
>> +
>> +       __for_each_physical_engine(i915, e) {
>> +               if (engine_has_cs_cycles(i915, e->class, e->instance)) {
>> +                       engine.engine_class = e->class;
>> +                       engine.engine_instance = e->instance;
>> +                       __cs_cycles(i915, &engine);
>> +               }
>> +       }
>> +}
>> +
>> +static void test_cs_cycles_invalid(int i915)
>> +{
>> +       struct i915_engine_class_instance engine;
>> +       const struct intel_execution_engine2 *e;
>> +       struct drm_i915_query_cs_cycles ts = {};
>> +
>> +       /* get one engine */
>> +       __for_each_physical_engine(i915, e)
>> +               break;
>
>	/* sanity check engine selection is valid */
>	ts.engine.engine_class = e->class;
>	ts.engine.engine_instance = e->instance;
>	igt_assert_eq(__query_cs_cycles(i915, &ts), 0);
>
>Otherwise you won't know that the EINVALs are because it didn't like the
>flags or class or instance in a moment.
>
>> +       /* bad engines */
>> +       ts.engine.engine_class = e->class;
>> +       ts.engine.engine_instance = -1;
>> +       __query_cs_cycles(i915, &ts, EINVAL);
>
>	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
>	...
>
>> +
>> +       ts.engine.engine_class = -1;
>> +       ts.engine.engine_instance = e->instance;
>> +       __query_cs_cycles(i915, &ts, EINVAL);
>> +
>> +       ts.engine.engine_class = -1;
>> +       ts.engine.engine_instance = -1;
>> +       __query_cs_cycles(i915, &ts, EINVAL);
>> +
>> +       /* non zero flags */
>> +       ts.flags = 1;
>> +       ts.engine.engine_class = e->class;
>> +       ts.engine.engine_instance = e->instance;
>> +       __query_cs_cycles(i915, &ts, EINVAL);
>> +
>> +       /* non zero rsvd field */
>> +       ts.flags = 0;
>> +       ts.rsvd = 1;
>> +       __query_cs_cycles(i915, &ts, EINVAL);
>> +
>> +       /* bad clockid */
>> +       ts.rsvd = 0;
>> +       ts.clockid = -1;
>> +       __query_cs_cycles(i915, &ts, EINVAL);
>> +
>> +       /* sanity check */
>> +       engine.engine_class = e->class;
>> +       engine.engine_instance = e->instance;
>> +       __cs_cycles(i915, &engine);
>> +}
>> +
>>  /*
>>   * Verify that we get coherent values between the legacy getparam slice/subslice
>>   * masks and the new topology query.
>> @@ -783,6 +959,19 @@ igt_main
>>                         engines(fd);
>>         }
>>
>> +       igt_subtest_group {
>> +               igt_fixture {
>> +                       igt_require(intel_gen(devid) >= 6);
>> +                       igt_require(query_cs_cycles_supported(fd));
>
>query_cs_cycles_supported() should cover gen >= 6, and the test itself
>is not gen specific (i.e no instructions that require a later gen).
>
>> +               }
>> +
>> +               igt_subtest("cs-cycles")
>> +                       test_cs_cycles(fd);
>> +
>> +               igt_subtest("cs-cycles-invalid")
>> +                       test_cs_cycles_invalid(fd);
>
>Do the invalid check first, it's just neater flow when using --run cs-cycles*
>
>> +       }
>> +
>>         igt_fixture {
>>                 close(fd);
>>         }
>> --
>> 2.20.1
>>
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
@ 2021-03-12 19:18 Umesh Nerlige Ramappa
  0 siblings, 0 replies; 13+ messages in thread
From: Umesh Nerlige Ramappa @ 2021-03-12 19:18 UTC (permalink / raw)
  To: igt-dev, Chris Wilson, Lionel G Landwerlin

Add tests to query CS timestamps for different engines.

v2:
- remove flag parameter
- assert for minimum usable values rather than maximum

v3:
- use clock id for cpu timestamps (Lionel)
- check if query is supported (Ashutosh)
- test bad queries

v4: (Chris, Tvrtko)
- cs_timestamp is a misnomer, use cs_cycles instead
- use cs cycle frequency returned in the query
- omit size parameter

v5:
- use __for_each_physical_engine (Lionel)
- check for ENODEV (Umesh)

v6: Use 2 cpu timestamps to calculate reg read time (Lionel)
v7: Refactor test code and add a spinner (Chris)

Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
 include/drm-uapi/i915_drm.h |  48 +++++++++
 tests/i915/i915_query.c     | 194 ++++++++++++++++++++++++++++++++++++
 2 files changed, 242 insertions(+)

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index bf9ea471..0e50302f 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
 #define DRM_I915_QUERY_TOPOLOGY_INFO    1
 #define DRM_I915_QUERY_ENGINE_INFO	2
 #define DRM_I915_QUERY_PERF_CONFIG      3
+	/**
+	 * Query Command Streamer timestamp register.
+	 */
+#define DRM_I915_QUERY_CS_CYCLES	4
 /* Must be kept compact -- no holes and well documented */
 
 	/*
@@ -2309,6 +2313,50 @@ struct drm_i915_engine_info {
 	__u64 rsvd1[4];
 };
 
+/**
+ * struct drm_i915_query_cs_cycles
+ *
+ * The query returns the command streamer cycles and the frequency that can be
+ * used to calculate the command streamer timestamp. In addition the query
+ * returns a set of cpu timestamps that indicate when the command streamer cycle
+ * count was captured.
+ */
+struct drm_i915_query_cs_cycles {
+	/** Engine for which command streamer cycles is queried. */
+	struct i915_engine_class_instance engine;
+
+	/** Must be zero. */
+	__u32 flags;
+
+	/**
+	 * Command streamer cycles as read from the command streamer
+	 * register at 0x358 offset.
+	 */
+	__u64 cs_cycles;
+
+	/** Frequency of the cs cycles in Hz. */
+	__u64 cs_frequency;
+
+	/**
+	 * CPU timestamps in ns. cpu_timestamp[0] is captured before reading the
+	 * cs_cycles register using the reference clockid set by the user.
+	 * cpu_timestamp[1] is the time taken in ns to read the lower dword of
+	 * the cs_cycles register.
+	 */
+	__u64 cpu_timestamp[2];
+
+	/**
+	 * Reference clock id for CPU timestamp. For definition, see
+	 * clock_gettime(2) and perf_event_open(2). Supported clock ids are
+	 * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
+	 * CLOCK_TAI.
+	 */
+	__s32 clockid;
+
+	/** Must be zero. */
+	__u32 rsvd;
+};
+
 /**
  * struct drm_i915_query_engine_info
  *
diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
index 29b938e9..9f639c74 100644
--- a/tests/i915/i915_query.c
+++ b/tests/i915/i915_query.c
@@ -267,6 +267,188 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
 				eu / 8] >> (eu % 8)) & 1;
 }
 
+static int __query_cs_cycles(int i915, void *data)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+		.data_ptr = to_user_pointer(data),
+		.length = sizeof(struct drm_i915_query_cs_cycles),
+	};
+
+	i915_query_items(i915, &item, 1);
+	return item.length;
+}
+
+static bool query_cs_cycles_supported(int fd)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+	};
+
+	i915_query_items(fd, &item, 1);
+	return item.length > 0;
+}
+
+static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
+{
+	struct drm_i915_query_cs_cycles ts = {
+		.engine = { class, instance }
+	};
+
+	return __query_cs_cycles(i915, &ts) != -ENODEV;
+}
+
+static void
+__cs_cycles(int i915, struct i915_engine_class_instance *engine)
+{
+	struct drm_i915_query_cs_cycles ts1 = {};
+	struct drm_i915_query_cs_cycles ts2 = {};
+	uint64_t delta_cpu, delta_cs, delta_delta;
+	int i, usable = 0;
+	igt_spin_t *spin;
+	uint32_t ctx;
+	struct {
+		int32_t id;
+		const char *name;
+	} clock[] = {
+		{ CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
+		{ CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
+		{ CLOCK_REALTIME, "CLOCK_REALTIME" },
+		{ CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
+		{ CLOCK_TAI, "CLOCK_TAI" },
+	};
+
+	igt_debug("engine[%u:%u]\n",
+		  engine->engine_class,
+		  engine->engine_instance);
+
+	ctx = gem_context_create_for_engine(i915,
+					    engine->engine_class,
+					    engine->engine_instance);
+	spin = igt_spin_new(i915, ctx);
+
+	/* Try a new clock every 10 iterations. */
+#define NUM_SNAPSHOTS 10
+	for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
+		int index = i / NUM_SNAPSHOTS;
+
+		ts1.engine = *engine;
+		ts1.clockid = clock[index].id;
+
+		ts2.engine = *engine;
+		ts2.clockid = clock[index].id;
+
+		igt_assert_eq(__query_cs_cycles(i915, &ts1), sizeof(ts1));
+		igt_assert_eq(__query_cs_cycles(i915, &ts2), sizeof(ts2));
+
+		igt_debug("[1] cpu_ts before %llu, reg read time %llu\n",
+			  ts1.cpu_timestamp[0],
+			  ts1.cpu_timestamp[1]);
+		igt_debug("[1] cs_ts %llu, freq %llu Hz\n",
+			  ts1.cs_cycles, ts1.cs_frequency);
+
+		igt_debug("[2] cpu_ts before %llu, reg read time %llu\n",
+			  ts2.cpu_timestamp[0],
+			  ts2.cpu_timestamp[1]);
+		igt_debug("[2] cs_ts %llu, freq %llu Hz\n",
+			  ts2.cs_cycles, ts2.cs_frequency);
+
+		delta_cpu = ts2.cpu_timestamp[0] - ts1.cpu_timestamp[0];
+		delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
+			   NSEC_PER_SEC / ts1.cs_frequency;
+
+		igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
+			  delta_cpu, delta_cs);
+
+		delta_delta = delta_cpu > delta_cs ?
+			       delta_cpu - delta_cs :
+			       delta_cs - delta_cpu;
+		igt_debug("delta_delta %lu\n", delta_delta);
+
+		if (delta_delta < 5000)
+			usable++;
+
+		/*
+		 * User needs few good snapshots of the timestamps to
+		 * synchronize cpu time with cs time. Check if we have enough
+		 * usable values before moving to the next clockid.
+		 */
+		if (!((i + 1) % NUM_SNAPSHOTS)) {
+			igt_debug("clock %s\n", clock[index].name);
+			igt_debug("usable %d\n", usable);
+			igt_assert(usable > 2);
+			usable = 0;
+		}
+	}
+
+	gem_context_destroy(i915, ctx);
+	igt_spin_free(i915, spin);
+}
+
+static void test_cs_cycles(int i915)
+{
+	const struct intel_execution_engine2 *e;
+	struct i915_engine_class_instance engine;
+
+	__for_each_physical_engine(i915, e) {
+		if (engine_has_cs_cycles(i915, e->class, e->instance)) {
+			engine.engine_class = e->class;
+			engine.engine_instance = e->instance;
+			__cs_cycles(i915, &engine);
+		}
+	}
+}
+
+static void test_cs_cycles_invalid(int i915)
+{
+	struct i915_engine_class_instance engine;
+	const struct intel_execution_engine2 *e;
+	struct drm_i915_query_cs_cycles ts = {};
+
+	/* get one engine */
+	__for_each_physical_engine(i915, e)
+		break;
+
+	/* sanity check engine selection is valid */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), sizeof(ts));
+
+	/* bad engines */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* non zero flags */
+	ts.flags = 1;
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* non zero rsvd field */
+	ts.flags = 0;
+	ts.rsvd = 1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* bad clockid */
+	ts.rsvd = 0;
+	ts.clockid = -1;
+	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
+
+	/* sanity check */
+	engine.engine_class = e->class;
+	engine.engine_instance = e->instance;
+	__cs_cycles(i915, &engine);
+}
+
 /*
  * Verify that we get coherent values between the legacy getparam slice/subslice
  * masks and the new topology query.
@@ -783,6 +965,18 @@ igt_main
 			engines(fd);
 	}
 
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(query_cs_cycles_supported(fd));
+		}
+
+		igt_subtest("cs-cycles-invalid")
+			test_cs_cycles_invalid(fd);
+
+		igt_subtest("cs-cycles")
+			test_cs_cycles(fd);
+	}
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.20.1

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

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

* Re: [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
  2021-03-05 19:37 Umesh Nerlige Ramappa
  2021-03-05 19:41 ` Umesh Nerlige Ramappa
@ 2021-03-05 20:33 ` Chris Wilson
  2021-03-13  6:04   ` Umesh Nerlige Ramappa
  1 sibling, 1 reply; 13+ messages in thread
From: Chris Wilson @ 2021-03-05 20:33 UTC (permalink / raw)
  To: Lionel G Landwerlin, Tvrtko Ursulin, Umesh Nerlige Ramappa, igt-dev

Quoting Umesh Nerlige Ramappa (2021-03-05 19:37:08)
> Add tests to query CS timestamps for different engines.
> 
> v2:
> - remove flag parameter
> - assert for minimum usable values rather than maximum
> 
> v3:
> - use clock id for cpu timestamps (Lionel)
> - check if query is supported (Ashutosh)
> - test bad queries
> 
> v4: (Chris, Tvrtko)
> - cs_timestamp is a misnomer, use cs_cycles instead
> - use cs cycle frequency returned in the query
> - omit size parameter
> 
> v5:
> - use __for_each_physical_engine (Lionel)
> - check for ENODEV (Umesh)
> 
> v6: Use 2 cpu timestamps to calculate reg read time (Lionel)
> 
> Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
> ---
>  include/drm-uapi/i915_drm.h |  48 +++++++++
>  tests/i915/i915_query.c     | 189 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 237 insertions(+)
> 
> diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
> index bf9ea471..0e50302f 100644
> --- a/include/drm-uapi/i915_drm.h
> +++ b/include/drm-uapi/i915_drm.h
> @@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
>  #define DRM_I915_QUERY_TOPOLOGY_INFO    1
>  #define DRM_I915_QUERY_ENGINE_INFO     2
>  #define DRM_I915_QUERY_PERF_CONFIG      3
> +       /**
> +        * Query Command Streamer timestamp register.
> +        */
> +#define DRM_I915_QUERY_CS_CYCLES       4
>  /* Must be kept compact -- no holes and well documented */
>  
>         /*
> @@ -2309,6 +2313,50 @@ struct drm_i915_engine_info {
>         __u64 rsvd1[4];
>  };
>  
> +/**
> + * struct drm_i915_query_cs_cycles
> + *
> + * The query returns the command streamer cycles and the frequency that can be
> + * used to calculate the command streamer timestamp. In addition the query
> + * returns a set of cpu timestamps that indicate when the command streamer cycle
> + * count was captured.
> + */
> +struct drm_i915_query_cs_cycles {
> +       /** Engine for which command streamer cycles is queried. */
> +       struct i915_engine_class_instance engine;
> +
> +       /** Must be zero. */
> +       __u32 flags;
> +
> +       /**
> +        * Command streamer cycles as read from the command streamer
> +        * register at 0x358 offset.
> +        */
> +       __u64 cs_cycles;
> +
> +       /** Frequency of the cs cycles in Hz. */
> +       __u64 cs_frequency;
> +
> +       /**
> +        * CPU timestamps in ns. cpu_timestamp[0] is captured before reading the
> +        * cs_cycles register using the reference clockid set by the user.
> +        * cpu_timestamp[1] is the time taken in ns to read the lower dword of
> +        * the cs_cycles register.
> +        */
> +       __u64 cpu_timestamp[2];
> +
> +       /**
> +        * Reference clock id for CPU timestamp. For definition, see
> +        * clock_gettime(2) and perf_event_open(2). Supported clock ids are
> +        * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
> +        * CLOCK_TAI.
> +        */
> +       __s32 clockid;
> +
> +       /** Must be zero. */
> +       __u32 rsvd;
> +};
> +
>  /**
>   * struct drm_i915_query_engine_info
>   *
> diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
> index 29b938e9..2ab3905b 100644
> --- a/tests/i915/i915_query.c
> +++ b/tests/i915/i915_query.c
> @@ -267,6 +267,182 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
>                                 eu / 8] >> (eu % 8)) & 1;
>  }
>  
> +static bool query_cs_cycles_supported(int fd)
> +{
> +       struct drm_i915_query_item item = {
> +               .query_id = DRM_I915_QUERY_CS_CYCLES,
> +       };
> +
> +       return __i915_query_items(fd, &item, 1) == 0 && item.length > 0;
> +}
> +
> +static void __query_cs_cycles(int i915, void *data, int err)
> +{
> +       struct drm_i915_query_item item = {
> +               .query_id = DRM_I915_QUERY_CS_CYCLES,
> +               .data_ptr = to_user_pointer(data),
> +               .length = sizeof(struct drm_i915_query_cs_cycles),
> +       };
> +
> +       i915_query_items(i915, &item, 1);
> +
> +       if (err)
> +               igt_assert(item.length == -err);

igt_assert_eq(item.length, -err);

s/err/expect/

I was looking for how err was being returned from i915_query_items....

And might as well pass in -EINVAL.


> +}
> +
> +static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
> +{
> +       struct drm_i915_query_cs_cycles ts = {};
> +       struct drm_i915_query_item item = {
> +               .query_id = DRM_I915_QUERY_CS_CYCLES,
> +               .data_ptr = to_user_pointer(&ts),
> +               .length = sizeof(struct drm_i915_query_cs_cycles),
> +       };
> +
> +       ts.engine.engine_class = class;
> +       ts.engine.engine_instance = instance;
> +
> +       i915_query_items(i915, &item, 1);
> +
> +       return item.length != -ENODEV;
> +}


Let's refactor the duplicated code

static void __query_cs_cycles(int i915, void *data)
{
       struct drm_i915_query_item item = {
               .query_id = DRM_I915_QUERY_CS_CYCLES,
               .data_ptr = to_user_pointer(data),
               .length = sizeof(struct drm_i915_query_cs_cycles),
       };

       i915_query_items(i915, &item, 1);
       return item.length;
}

static bool query_cs_cycles_supported(int fd)
{
	return __query_cs_cycles(fd, NULL) > 0;
}

static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
{
       struct drm_i915_query_cs_cycles ts = {
	       .engine = { class, instance }
       };

       return __query_cs_cycles(i915, &ts) != -ENODEV;
}

> +static void
> +__cs_cycles(int i915, struct i915_engine_class_instance *engine)
> +{
> +       struct drm_i915_query_cs_cycles ts1 = {};
> +       struct drm_i915_query_cs_cycles ts2 = {};
> +       uint64_t delta_cpu, delta_cs, delta_delta;
> +       int i, usable = 0;
> +       struct {
> +               int32_t id;
> +               const char *name;
> +       } clock[] = {
> +               { CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
> +               { CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
> +               { CLOCK_REALTIME, "CLOCK_REALTIME" },
> +               { CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
> +               { CLOCK_TAI, "CLOCK_TAI" },
> +       };
> +
> +       igt_debug("engine[%u:%u]\n",
> +                 engine->engine_class,
> +                 engine->engine_instance);
> +
> +       /* Try a new clock every 10 iterations. */
> +#define NUM_SNAPSHOTS 10
> +       for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
> +               int index = i / NUM_SNAPSHOTS;
> +
> +               ts1.engine = *engine;
> +               ts1.clockid = clock[index].id;
> +
> +               ts2.engine = *engine;
> +               ts2.clockid = clock[index].id;
> +
> +               __query_cs_cycles(i915, &ts1, 0);
> +               __query_cs_cycles(i915, &ts2, 0);

igt_assert_eq(__query_cs_cycles(i915, &ts1), 0);
igt_assert_eq(__query_cs_cycles(i915, &ts2), 0);

> +
> +               igt_debug("[1] cpu_ts before %llu, reg read time %llu\n",
> +                         ts1.cpu_timestamp[0],
> +                         ts1.cpu_timestamp[1]);
> +               igt_debug("[1] cs_ts %llu, freq %llu Hz\n",
> +                         ts1.cs_cycles, ts1.cs_frequency);
> +
> +               igt_debug("[2] cpu_ts before %llu, reg read time %llu\n",
> +                         ts2.cpu_timestamp[0],
> +                         ts2.cpu_timestamp[1]);
> +               igt_debug("[2] cs_ts %llu, freq %llu Hz\n",
> +                         ts2.cs_cycles, ts2.cs_frequency);
> +
> +               delta_cpu = ts2.cpu_timestamp[0] - ts1.cpu_timestamp[0];
> +               delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
> +                          NSEC_PER_SEC / ts1.cs_frequency;
> +
> +               igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
> +                         delta_cpu, delta_cs);
> +
> +               delta_delta = delta_cpu > delta_cs ?
> +                              delta_cpu - delta_cs :
> +                              delta_cs - delta_cpu;
> +               igt_debug("delta_delta %lu\n", delta_delta);
> +
> +               if (delta_delta < 5000)
> +                       usable++;

Nothing is keeping the CS awake, its counter is allowed to switch off
between reads.

I would run this test with a spinner in the background

uint32_t ctx = gem_context_create_for_engine(i915, engine.class, engine.instance);
igt_spin_t *spin = igt_spin_new(i915, ctx);
gem_context_destroy(i915, ctx);

...

igt_spin_free(i915, spin);

And even repeat the test to see if the counter does switch off. Although
we can hypothesis that one day it may be replaced by an always running
counter.

> +
> +               /*
> +                * User needs few good snapshots of the timestamps to
> +                * synchronize cpu time with cs time. Check if we have enough
> +                * usable values before moving to the next clockid.
> +                */
> +               if (!((i + 1) % NUM_SNAPSHOTS)) {
> +                       igt_debug("clock %s\n", clock[index].name);
> +                       igt_debug("usable %d\n", usable);
> +                       igt_assert(usable > 2);
> +                       usable = 0;
> +               }
> +       }
> +}
> +
> +static void test_cs_cycles(int i915)
> +{
> +       const struct intel_execution_engine2 *e;
> +       struct i915_engine_class_instance engine;
> +
> +       __for_each_physical_engine(i915, e) {
> +               if (engine_has_cs_cycles(i915, e->class, e->instance)) {
> +                       engine.engine_class = e->class;
> +                       engine.engine_instance = e->instance;
> +                       __cs_cycles(i915, &engine);
> +               }
> +       }
> +}
> +
> +static void test_cs_cycles_invalid(int i915)
> +{
> +       struct i915_engine_class_instance engine;
> +       const struct intel_execution_engine2 *e;
> +       struct drm_i915_query_cs_cycles ts = {};
> +
> +       /* get one engine */
> +       __for_each_physical_engine(i915, e)
> +               break;

	/* sanity check engine selection is valid */
	ts.engine.engine_class = e->class;
	ts.engine.engine_instance = e->instance;
	igt_assert_eq(__query_cs_cycles(i915, &ts), 0);

Otherwise you won't know that the EINVALs are because it didn't like the
flags or class or instance in a moment.

> +       /* bad engines */
> +       ts.engine.engine_class = e->class;
> +       ts.engine.engine_instance = -1;
> +       __query_cs_cycles(i915, &ts, EINVAL);

	igt_assert_eq(__query_cs_cycles(i915, &ts), -EINVAL);
	...

> +
> +       ts.engine.engine_class = -1;
> +       ts.engine.engine_instance = e->instance;
> +       __query_cs_cycles(i915, &ts, EINVAL);
> +
> +       ts.engine.engine_class = -1;
> +       ts.engine.engine_instance = -1;
> +       __query_cs_cycles(i915, &ts, EINVAL);
> +
> +       /* non zero flags */
> +       ts.flags = 1;
> +       ts.engine.engine_class = e->class;
> +       ts.engine.engine_instance = e->instance;
> +       __query_cs_cycles(i915, &ts, EINVAL);
> +
> +       /* non zero rsvd field */
> +       ts.flags = 0;
> +       ts.rsvd = 1;
> +       __query_cs_cycles(i915, &ts, EINVAL);
> +
> +       /* bad clockid */
> +       ts.rsvd = 0;
> +       ts.clockid = -1;
> +       __query_cs_cycles(i915, &ts, EINVAL);
> +
> +       /* sanity check */
> +       engine.engine_class = e->class;
> +       engine.engine_instance = e->instance;
> +       __cs_cycles(i915, &engine);
> +}
> +
>  /*
>   * Verify that we get coherent values between the legacy getparam slice/subslice
>   * masks and the new topology query.
> @@ -783,6 +959,19 @@ igt_main
>                         engines(fd);
>         }
>  
> +       igt_subtest_group {
> +               igt_fixture {
> +                       igt_require(intel_gen(devid) >= 6);
> +                       igt_require(query_cs_cycles_supported(fd));

query_cs_cycles_supported() should cover gen >= 6, and the test itself
is not gen specific (i.e no instructions that require a later gen).

> +               }
> +
> +               igt_subtest("cs-cycles")
> +                       test_cs_cycles(fd);
> +
> +               igt_subtest("cs-cycles-invalid")
> +                       test_cs_cycles_invalid(fd);

Do the invalid check first, it's just neater flow when using --run cs-cycles*

> +       }
> +
>         igt_fixture {
>                 close(fd);
>         }
> -- 
> 2.20.1
>
---------------------------------------------------------------------
Intel Corporation (UK) Limited
Registered No. 1134945 (England)
Registered Office: Pipers Way, Swindon SN3 1RJ
VAT No: 860 2173 47

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
  2021-03-05 19:37 Umesh Nerlige Ramappa
@ 2021-03-05 19:41 ` Umesh Nerlige Ramappa
  2021-03-05 20:33 ` Chris Wilson
  1 sibling, 0 replies; 13+ messages in thread
From: Umesh Nerlige Ramappa @ 2021-03-05 19:41 UTC (permalink / raw)
  To: igt-dev

On Fri, Mar 05, 2021 at 11:37:08AM -0800, Umesh Nerlige Ramappa wrote:
>Add tests to query CS timestamps for different engines.
>
>v2:
>- remove flag parameter
>- assert for minimum usable values rather than maximum
>
>v3:
>- use clock id for cpu timestamps (Lionel)
>- check if query is supported (Ashutosh)
>- test bad queries
>
>v4: (Chris, Tvrtko)
>- cs_timestamp is a misnomer, use cs_cycles instead
>- use cs cycle frequency returned in the query
>- omit size parameter
>
>v5:
>- use __for_each_physical_engine (Lionel)
>- check for ENODEV (Umesh)
>
>v6: Use 2 cpu timestamps to calculate reg read time (Lionel)
>
>Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>

Missed out the previous R-b from Lionel. The only additional change is 
logs printing time taken to read the register.

Thanks,
Umesh

>---
> include/drm-uapi/i915_drm.h |  48 +++++++++
> tests/i915/i915_query.c     | 189 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 237 insertions(+)
>
>diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
>index bf9ea471..0e50302f 100644
>--- a/include/drm-uapi/i915_drm.h
>+++ b/include/drm-uapi/i915_drm.h
>@@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
> #define DRM_I915_QUERY_TOPOLOGY_INFO    1
> #define DRM_I915_QUERY_ENGINE_INFO	2
> #define DRM_I915_QUERY_PERF_CONFIG      3
>+	/**
>+	 * Query Command Streamer timestamp register.
>+	 */
>+#define DRM_I915_QUERY_CS_CYCLES	4
> /* Must be kept compact -- no holes and well documented */
>
> 	/*
>@@ -2309,6 +2313,50 @@ struct drm_i915_engine_info {
> 	__u64 rsvd1[4];
> };
>
>+/**
>+ * struct drm_i915_query_cs_cycles
>+ *
>+ * The query returns the command streamer cycles and the frequency that can be
>+ * used to calculate the command streamer timestamp. In addition the query
>+ * returns a set of cpu timestamps that indicate when the command streamer cycle
>+ * count was captured.
>+ */
>+struct drm_i915_query_cs_cycles {
>+	/** Engine for which command streamer cycles is queried. */
>+	struct i915_engine_class_instance engine;
>+
>+	/** Must be zero. */
>+	__u32 flags;
>+
>+	/**
>+	 * Command streamer cycles as read from the command streamer
>+	 * register at 0x358 offset.
>+	 */
>+	__u64 cs_cycles;
>+
>+	/** Frequency of the cs cycles in Hz. */
>+	__u64 cs_frequency;
>+
>+	/**
>+	 * CPU timestamps in ns. cpu_timestamp[0] is captured before reading the
>+	 * cs_cycles register using the reference clockid set by the user.
>+	 * cpu_timestamp[1] is the time taken in ns to read the lower dword of
>+	 * the cs_cycles register.
>+	 */
>+	__u64 cpu_timestamp[2];
>+
>+	/**
>+	 * Reference clock id for CPU timestamp. For definition, see
>+	 * clock_gettime(2) and perf_event_open(2). Supported clock ids are
>+	 * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
>+	 * CLOCK_TAI.
>+	 */
>+	__s32 clockid;
>+
>+	/** Must be zero. */
>+	__u32 rsvd;
>+};
>+
> /**
>  * struct drm_i915_query_engine_info
>  *
>diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
>index 29b938e9..2ab3905b 100644
>--- a/tests/i915/i915_query.c
>+++ b/tests/i915/i915_query.c
>@@ -267,6 +267,182 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
> 				eu / 8] >> (eu % 8)) & 1;
> }
>
>+static bool query_cs_cycles_supported(int fd)
>+{
>+	struct drm_i915_query_item item = {
>+		.query_id = DRM_I915_QUERY_CS_CYCLES,
>+	};
>+
>+	return __i915_query_items(fd, &item, 1) == 0 && item.length > 0;
>+}
>+
>+static void __query_cs_cycles(int i915, void *data, int err)
>+{
>+	struct drm_i915_query_item item = {
>+		.query_id = DRM_I915_QUERY_CS_CYCLES,
>+		.data_ptr = to_user_pointer(data),
>+		.length = sizeof(struct drm_i915_query_cs_cycles),
>+	};
>+
>+	i915_query_items(i915, &item, 1);
>+
>+	if (err)
>+		igt_assert(item.length == -err);
>+}
>+
>+static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
>+{
>+	struct drm_i915_query_cs_cycles ts = {};
>+	struct drm_i915_query_item item = {
>+		.query_id = DRM_I915_QUERY_CS_CYCLES,
>+		.data_ptr = to_user_pointer(&ts),
>+		.length = sizeof(struct drm_i915_query_cs_cycles),
>+	};
>+
>+	ts.engine.engine_class = class;
>+	ts.engine.engine_instance = instance;
>+
>+	i915_query_items(i915, &item, 1);
>+
>+	return item.length != -ENODEV;
>+}
>+
>+static void
>+__cs_cycles(int i915, struct i915_engine_class_instance *engine)
>+{
>+	struct drm_i915_query_cs_cycles ts1 = {};
>+	struct drm_i915_query_cs_cycles ts2 = {};
>+	uint64_t delta_cpu, delta_cs, delta_delta;
>+	int i, usable = 0;
>+	struct {
>+		int32_t id;
>+		const char *name;
>+	} clock[] = {
>+		{ CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
>+		{ CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
>+		{ CLOCK_REALTIME, "CLOCK_REALTIME" },
>+		{ CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
>+		{ CLOCK_TAI, "CLOCK_TAI" },
>+	};
>+
>+	igt_debug("engine[%u:%u]\n",
>+		  engine->engine_class,
>+		  engine->engine_instance);
>+
>+	/* Try a new clock every 10 iterations. */
>+#define NUM_SNAPSHOTS 10
>+	for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
>+		int index = i / NUM_SNAPSHOTS;
>+
>+		ts1.engine = *engine;
>+		ts1.clockid = clock[index].id;
>+
>+		ts2.engine = *engine;
>+		ts2.clockid = clock[index].id;
>+
>+		__query_cs_cycles(i915, &ts1, 0);
>+		__query_cs_cycles(i915, &ts2, 0);
>+
>+		igt_debug("[1] cpu_ts before %llu, reg read time %llu\n",
>+			  ts1.cpu_timestamp[0],
>+			  ts1.cpu_timestamp[1]);
>+		igt_debug("[1] cs_ts %llu, freq %llu Hz\n",
>+			  ts1.cs_cycles, ts1.cs_frequency);
>+
>+		igt_debug("[2] cpu_ts before %llu, reg read time %llu\n",
>+			  ts2.cpu_timestamp[0],
>+			  ts2.cpu_timestamp[1]);
>+		igt_debug("[2] cs_ts %llu, freq %llu Hz\n",
>+			  ts2.cs_cycles, ts2.cs_frequency);
>+
>+		delta_cpu = ts2.cpu_timestamp[0] - ts1.cpu_timestamp[0];
>+		delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
>+			   NSEC_PER_SEC / ts1.cs_frequency;
>+
>+		igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
>+			  delta_cpu, delta_cs);
>+
>+		delta_delta = delta_cpu > delta_cs ?
>+			       delta_cpu - delta_cs :
>+			       delta_cs - delta_cpu;
>+		igt_debug("delta_delta %lu\n", delta_delta);
>+
>+		if (delta_delta < 5000)
>+			usable++;
>+
>+		/*
>+		 * User needs few good snapshots of the timestamps to
>+		 * synchronize cpu time with cs time. Check if we have enough
>+		 * usable values before moving to the next clockid.
>+		 */
>+		if (!((i + 1) % NUM_SNAPSHOTS)) {
>+			igt_debug("clock %s\n", clock[index].name);
>+			igt_debug("usable %d\n", usable);
>+			igt_assert(usable > 2);
>+			usable = 0;
>+		}
>+	}
>+}
>+
>+static void test_cs_cycles(int i915)
>+{
>+	const struct intel_execution_engine2 *e;
>+	struct i915_engine_class_instance engine;
>+
>+	__for_each_physical_engine(i915, e) {
>+		if (engine_has_cs_cycles(i915, e->class, e->instance)) {
>+			engine.engine_class = e->class;
>+			engine.engine_instance = e->instance;
>+			__cs_cycles(i915, &engine);
>+		}
>+	}
>+}
>+
>+static void test_cs_cycles_invalid(int i915)
>+{
>+	struct i915_engine_class_instance engine;
>+	const struct intel_execution_engine2 *e;
>+	struct drm_i915_query_cs_cycles ts = {};
>+
>+	/* get one engine */
>+	__for_each_physical_engine(i915, e)
>+		break;
>+
>+	/* bad engines */
>+	ts.engine.engine_class = e->class;
>+	ts.engine.engine_instance = -1;
>+	__query_cs_cycles(i915, &ts, EINVAL);
>+
>+	ts.engine.engine_class = -1;
>+	ts.engine.engine_instance = e->instance;
>+	__query_cs_cycles(i915, &ts, EINVAL);
>+
>+	ts.engine.engine_class = -1;
>+	ts.engine.engine_instance = -1;
>+	__query_cs_cycles(i915, &ts, EINVAL);
>+
>+	/* non zero flags */
>+	ts.flags = 1;
>+	ts.engine.engine_class = e->class;
>+	ts.engine.engine_instance = e->instance;
>+	__query_cs_cycles(i915, &ts, EINVAL);
>+
>+	/* non zero rsvd field */
>+	ts.flags = 0;
>+	ts.rsvd = 1;
>+	__query_cs_cycles(i915, &ts, EINVAL);
>+
>+	/* bad clockid */
>+	ts.rsvd = 0;
>+	ts.clockid = -1;
>+	__query_cs_cycles(i915, &ts, EINVAL);
>+
>+	/* sanity check */
>+	engine.engine_class = e->class;
>+	engine.engine_instance = e->instance;
>+	__cs_cycles(i915, &engine);
>+}
>+
> /*
>  * Verify that we get coherent values between the legacy getparam slice/subslice
>  * masks and the new topology query.
>@@ -783,6 +959,19 @@ igt_main
> 			engines(fd);
> 	}
>
>+	igt_subtest_group {
>+		igt_fixture {
>+			igt_require(intel_gen(devid) >= 6);
>+			igt_require(query_cs_cycles_supported(fd));
>+		}
>+
>+		igt_subtest("cs-cycles")
>+			test_cs_cycles(fd);
>+
>+		igt_subtest("cs-cycles-invalid")
>+			test_cs_cycles_invalid(fd);
>+	}
>+
> 	igt_fixture {
> 		close(fd);
> 	}
>-- 
>2.20.1
>
>_______________________________________________
>igt-dev mailing list
>igt-dev@lists.freedesktop.org
>https://lists.freedesktop.org/mailman/listinfo/igt-dev
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
@ 2021-03-05 19:37 Umesh Nerlige Ramappa
  2021-03-05 19:41 ` Umesh Nerlige Ramappa
  2021-03-05 20:33 ` Chris Wilson
  0 siblings, 2 replies; 13+ messages in thread
From: Umesh Nerlige Ramappa @ 2021-03-05 19:37 UTC (permalink / raw)
  To: igt-dev, Lionel G Landwerlin, Tvrtko Ursulin, Chris Wilson

Add tests to query CS timestamps for different engines.

v2:
- remove flag parameter
- assert for minimum usable values rather than maximum

v3:
- use clock id for cpu timestamps (Lionel)
- check if query is supported (Ashutosh)
- test bad queries

v4: (Chris, Tvrtko)
- cs_timestamp is a misnomer, use cs_cycles instead
- use cs cycle frequency returned in the query
- omit size parameter

v5:
- use __for_each_physical_engine (Lionel)
- check for ENODEV (Umesh)

v6: Use 2 cpu timestamps to calculate reg read time (Lionel)

Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
---
 include/drm-uapi/i915_drm.h |  48 +++++++++
 tests/i915/i915_query.c     | 189 ++++++++++++++++++++++++++++++++++++
 2 files changed, 237 insertions(+)

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index bf9ea471..0e50302f 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
 #define DRM_I915_QUERY_TOPOLOGY_INFO    1
 #define DRM_I915_QUERY_ENGINE_INFO	2
 #define DRM_I915_QUERY_PERF_CONFIG      3
+	/**
+	 * Query Command Streamer timestamp register.
+	 */
+#define DRM_I915_QUERY_CS_CYCLES	4
 /* Must be kept compact -- no holes and well documented */
 
 	/*
@@ -2309,6 +2313,50 @@ struct drm_i915_engine_info {
 	__u64 rsvd1[4];
 };
 
+/**
+ * struct drm_i915_query_cs_cycles
+ *
+ * The query returns the command streamer cycles and the frequency that can be
+ * used to calculate the command streamer timestamp. In addition the query
+ * returns a set of cpu timestamps that indicate when the command streamer cycle
+ * count was captured.
+ */
+struct drm_i915_query_cs_cycles {
+	/** Engine for which command streamer cycles is queried. */
+	struct i915_engine_class_instance engine;
+
+	/** Must be zero. */
+	__u32 flags;
+
+	/**
+	 * Command streamer cycles as read from the command streamer
+	 * register at 0x358 offset.
+	 */
+	__u64 cs_cycles;
+
+	/** Frequency of the cs cycles in Hz. */
+	__u64 cs_frequency;
+
+	/**
+	 * CPU timestamps in ns. cpu_timestamp[0] is captured before reading the
+	 * cs_cycles register using the reference clockid set by the user.
+	 * cpu_timestamp[1] is the time taken in ns to read the lower dword of
+	 * the cs_cycles register.
+	 */
+	__u64 cpu_timestamp[2];
+
+	/**
+	 * Reference clock id for CPU timestamp. For definition, see
+	 * clock_gettime(2) and perf_event_open(2). Supported clock ids are
+	 * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
+	 * CLOCK_TAI.
+	 */
+	__s32 clockid;
+
+	/** Must be zero. */
+	__u32 rsvd;
+};
+
 /**
  * struct drm_i915_query_engine_info
  *
diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
index 29b938e9..2ab3905b 100644
--- a/tests/i915/i915_query.c
+++ b/tests/i915/i915_query.c
@@ -267,6 +267,182 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
 				eu / 8] >> (eu % 8)) & 1;
 }
 
+static bool query_cs_cycles_supported(int fd)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+	};
+
+	return __i915_query_items(fd, &item, 1) == 0 && item.length > 0;
+}
+
+static void __query_cs_cycles(int i915, void *data, int err)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+		.data_ptr = to_user_pointer(data),
+		.length = sizeof(struct drm_i915_query_cs_cycles),
+	};
+
+	i915_query_items(i915, &item, 1);
+
+	if (err)
+		igt_assert(item.length == -err);
+}
+
+static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
+{
+	struct drm_i915_query_cs_cycles ts = {};
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+		.data_ptr = to_user_pointer(&ts),
+		.length = sizeof(struct drm_i915_query_cs_cycles),
+	};
+
+	ts.engine.engine_class = class;
+	ts.engine.engine_instance = instance;
+
+	i915_query_items(i915, &item, 1);
+
+	return item.length != -ENODEV;
+}
+
+static void
+__cs_cycles(int i915, struct i915_engine_class_instance *engine)
+{
+	struct drm_i915_query_cs_cycles ts1 = {};
+	struct drm_i915_query_cs_cycles ts2 = {};
+	uint64_t delta_cpu, delta_cs, delta_delta;
+	int i, usable = 0;
+	struct {
+		int32_t id;
+		const char *name;
+	} clock[] = {
+		{ CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
+		{ CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
+		{ CLOCK_REALTIME, "CLOCK_REALTIME" },
+		{ CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
+		{ CLOCK_TAI, "CLOCK_TAI" },
+	};
+
+	igt_debug("engine[%u:%u]\n",
+		  engine->engine_class,
+		  engine->engine_instance);
+
+	/* Try a new clock every 10 iterations. */
+#define NUM_SNAPSHOTS 10
+	for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
+		int index = i / NUM_SNAPSHOTS;
+
+		ts1.engine = *engine;
+		ts1.clockid = clock[index].id;
+
+		ts2.engine = *engine;
+		ts2.clockid = clock[index].id;
+
+		__query_cs_cycles(i915, &ts1, 0);
+		__query_cs_cycles(i915, &ts2, 0);
+
+		igt_debug("[1] cpu_ts before %llu, reg read time %llu\n",
+			  ts1.cpu_timestamp[0],
+			  ts1.cpu_timestamp[1]);
+		igt_debug("[1] cs_ts %llu, freq %llu Hz\n",
+			  ts1.cs_cycles, ts1.cs_frequency);
+
+		igt_debug("[2] cpu_ts before %llu, reg read time %llu\n",
+			  ts2.cpu_timestamp[0],
+			  ts2.cpu_timestamp[1]);
+		igt_debug("[2] cs_ts %llu, freq %llu Hz\n",
+			  ts2.cs_cycles, ts2.cs_frequency);
+
+		delta_cpu = ts2.cpu_timestamp[0] - ts1.cpu_timestamp[0];
+		delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
+			   NSEC_PER_SEC / ts1.cs_frequency;
+
+		igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
+			  delta_cpu, delta_cs);
+
+		delta_delta = delta_cpu > delta_cs ?
+			       delta_cpu - delta_cs :
+			       delta_cs - delta_cpu;
+		igt_debug("delta_delta %lu\n", delta_delta);
+
+		if (delta_delta < 5000)
+			usable++;
+
+		/*
+		 * User needs few good snapshots of the timestamps to
+		 * synchronize cpu time with cs time. Check if we have enough
+		 * usable values before moving to the next clockid.
+		 */
+		if (!((i + 1) % NUM_SNAPSHOTS)) {
+			igt_debug("clock %s\n", clock[index].name);
+			igt_debug("usable %d\n", usable);
+			igt_assert(usable > 2);
+			usable = 0;
+		}
+	}
+}
+
+static void test_cs_cycles(int i915)
+{
+	const struct intel_execution_engine2 *e;
+	struct i915_engine_class_instance engine;
+
+	__for_each_physical_engine(i915, e) {
+		if (engine_has_cs_cycles(i915, e->class, e->instance)) {
+			engine.engine_class = e->class;
+			engine.engine_instance = e->instance;
+			__cs_cycles(i915, &engine);
+		}
+	}
+}
+
+static void test_cs_cycles_invalid(int i915)
+{
+	struct i915_engine_class_instance engine;
+	const struct intel_execution_engine2 *e;
+	struct drm_i915_query_cs_cycles ts = {};
+
+	/* get one engine */
+	__for_each_physical_engine(i915, e)
+		break;
+
+	/* bad engines */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = -1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = e->instance;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = -1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* non zero flags */
+	ts.flags = 1;
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* non zero rsvd field */
+	ts.flags = 0;
+	ts.rsvd = 1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* bad clockid */
+	ts.rsvd = 0;
+	ts.clockid = -1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* sanity check */
+	engine.engine_class = e->class;
+	engine.engine_instance = e->instance;
+	__cs_cycles(i915, &engine);
+}
+
 /*
  * Verify that we get coherent values between the legacy getparam slice/subslice
  * masks and the new topology query.
@@ -783,6 +959,19 @@ igt_main
 			engines(fd);
 	}
 
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(intel_gen(devid) >= 6);
+			igt_require(query_cs_cycles_supported(fd));
+		}
+
+		igt_subtest("cs-cycles")
+			test_cs_cycles(fd);
+
+		igt_subtest("cs-cycles-invalid")
+			test_cs_cycles_invalid(fd);
+	}
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.20.1

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

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

* Re: [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
  2021-03-03 21:28 Umesh Nerlige Ramappa
@ 2021-03-05 11:55 ` Lionel Landwerlin
  0 siblings, 0 replies; 13+ messages in thread
From: Lionel Landwerlin @ 2021-03-05 11:55 UTC (permalink / raw)
  To: Umesh Nerlige Ramappa, igt-dev, Tvrtko Ursulin, Chris Wilson

On 03/03/2021 23:28, Umesh Nerlige Ramappa wrote:
> Add tests to query CS timestamps for different engines.
>
> v2:
> - remove flag parameter
> - assert for minimum usable values rather than maximum
>
> v3:
> - use clock id for cpu timestamps (Lionel)
> - check if query is supported (Ashutosh)
> - test bad queries
>
> v4: (Chris, Tvrtko)
> - cs_timestamp is a misnomer, use cs_cycles instead
> - use cs cycle frequency returned in the query
> - omit size parameter
>
> v5:
> - use __for_each_physical_engine (Lionel)
> - check for ENODEV (Umesh)
>
> v6: Use 2 cpu timestamps to calculate reg read time (Lionel)
>
> Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>


Looks good:


Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>


Thanks!


> ---
>   include/drm-uapi/i915_drm.h |  47 +++++++++
>   tests/i915/i915_query.c     | 191 ++++++++++++++++++++++++++++++++++++
>   2 files changed, 238 insertions(+)
>
> diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
> index bf9ea471..e95e17f9 100644
> --- a/include/drm-uapi/i915_drm.h
> +++ b/include/drm-uapi/i915_drm.h
> @@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
>   #define DRM_I915_QUERY_TOPOLOGY_INFO    1
>   #define DRM_I915_QUERY_ENGINE_INFO	2
>   #define DRM_I915_QUERY_PERF_CONFIG      3
> +	/**
> +	 * Query Command Streamer timestamp register.
> +	 */
> +#define DRM_I915_QUERY_CS_CYCLES	4
>   /* Must be kept compact -- no holes and well documented */
>   
>   	/*
> @@ -2309,6 +2313,49 @@ struct drm_i915_engine_info {
>   	__u64 rsvd1[4];
>   };
>   
> +/**
> + * struct drm_i915_query_cs_cycles
> + *
> + * The query returns the command streamer cycles and the frequency that can be
> + * used to calculate the command streamer timestamp. In addition the query
> + * returns the cpu timestamp that indicates when the command streamer cycle
> + * count was captured.
> + */
> +struct drm_i915_query_cs_cycles {
> +	/** Engine for which command streamer cycles is queried. */
> +	struct i915_engine_class_instance engine;
> +
> +	/** Must be zero. */
> +	__u32 flags;
> +
> +	/**
> +	 * Command streamer cycles as read from the command streamer
> +	 * register at 0x358 offset.
> +	 */
> +	__u64 cs_cycles;
> +
> +	/** Frequency of the cs cycles in Hz. */
> +	__u64 cs_frequency;
> +
> +	/**
> +	 * CPU timestamp in nanoseconds. cpu_timestamp[0] is captured before
> +	 * reading the cs_cycles register and cpu_timestamp[1] is captured after
> +	 * reading the register.
> +	 **/
> +	__u64 cpu_timestamp[2];
> +
> +	/**
> +	 * Reference clock id for CPU timestamp. For definition, see
> +	 * clock_gettime(2) and perf_event_open(2). Supported clock ids are
> +	 * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
> +	 * CLOCK_TAI.
> +	 */
> +	__s32 clockid;
> +
> +	/** Must be zero. */
> +	__u32 rsvd;
> +};
> +
>   /**
>    * struct drm_i915_query_engine_info
>    *
> diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
> index 29b938e9..e1c5f93d 100644
> --- a/tests/i915/i915_query.c
> +++ b/tests/i915/i915_query.c
> @@ -267,6 +267,184 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
>   				eu / 8] >> (eu % 8)) & 1;
>   }
>   
> +static bool query_cs_cycles_supported(int fd)
> +{
> +	struct drm_i915_query_item item = {
> +		.query_id = DRM_I915_QUERY_CS_CYCLES,
> +	};
> +
> +	return __i915_query_items(fd, &item, 1) == 0 && item.length > 0;
> +}
> +
> +static void __query_cs_cycles(int i915, void *data, int err)
> +{
> +	struct drm_i915_query_item item = {
> +		.query_id = DRM_I915_QUERY_CS_CYCLES,
> +		.data_ptr = to_user_pointer(data),
> +		.length = sizeof(struct drm_i915_query_cs_cycles),
> +	};
> +
> +	i915_query_items(i915, &item, 1);
> +
> +	if (err)
> +		igt_assert(item.length == -err);
> +}
> +
> +static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
> +{
> +	struct drm_i915_query_cs_cycles ts = {};
> +	struct drm_i915_query_item item = {
> +		.query_id = DRM_I915_QUERY_CS_CYCLES,
> +		.data_ptr = to_user_pointer(&ts),
> +		.length = sizeof(struct drm_i915_query_cs_cycles),
> +	};
> +
> +	ts.engine.engine_class = class;
> +	ts.engine.engine_instance = instance;
> +
> +	i915_query_items(i915, &item, 1);
> +
> +	return item.length != -ENODEV;
> +}
> +
> +static void
> +__cs_cycles(int i915, struct i915_engine_class_instance *engine)
> +{
> +	struct drm_i915_query_cs_cycles ts1 = {};
> +	struct drm_i915_query_cs_cycles ts2 = {};
> +	uint64_t delta_cpu, delta_cs, delta_delta;
> +	int i, usable = 0;
> +	struct {
> +		int32_t id;
> +		const char *name;
> +	} clock[] = {
> +		{ CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
> +		{ CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
> +		{ CLOCK_REALTIME, "CLOCK_REALTIME" },
> +		{ CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
> +		{ CLOCK_TAI, "CLOCK_TAI" },
> +	};
> +
> +	igt_debug("engine[%u:%u]\n",
> +		  engine->engine_class,
> +		  engine->engine_instance);
> +
> +	/* Try a new clock every 10 iterations. */
> +#define NUM_SNAPSHOTS 10
> +	for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
> +		int index = i / NUM_SNAPSHOTS;
> +
> +		ts1.engine = *engine;
> +		ts1.clockid = clock[index].id;
> +
> +		ts2.engine = *engine;
> +		ts2.clockid = clock[index].id;
> +
> +		__query_cs_cycles(i915, &ts1, 0);
> +		__query_cs_cycles(i915, &ts2, 0);
> +
> +		igt_debug("[1] cpu_ts before %llu, cpu_ts after %llu, reg read time %llu\n",
> +			  ts1.cpu_timestamp[0],
> +			  ts1.cpu_timestamp[1],
> +			  ts1.cpu_timestamp[1] - ts1.cpu_timestamp[0]);
> +		igt_debug("[1] cs_ts %llu, freq %llu Hz\n",
> +			  ts1.cs_cycles, ts1.cs_frequency);
> +
> +		igt_debug("[2] cpu_ts before %llu, cpu_ts after %llu, reg read time %llu\n",
> +			  ts2.cpu_timestamp[0],
> +			  ts2.cpu_timestamp[1],
> +			  ts2.cpu_timestamp[1] - ts2.cpu_timestamp[0]);
> +		igt_debug("[2] cs_ts %llu, freq %llu Hz\n",
> +			  ts2.cs_cycles, ts2.cs_frequency);
> +
> +		delta_cpu = ts2.cpu_timestamp[0] - ts1.cpu_timestamp[0];
> +		delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
> +			   NSEC_PER_SEC / ts1.cs_frequency;
> +
> +		igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
> +			  delta_cpu, delta_cs);
> +
> +		delta_delta = delta_cpu > delta_cs ?
> +			       delta_cpu - delta_cs :
> +			       delta_cs - delta_cpu;
> +		igt_debug("delta_delta %lu\n", delta_delta);
> +
> +		if (delta_delta < 5000)
> +			usable++;
> +
> +		/*
> +		 * User needs few good snapshots of the timestamps to
> +		 * synchronize cpu time with cs time. Check if we have enough
> +		 * usable values before moving to the next clockid.
> +		 */
> +		if (!((i + 1) % NUM_SNAPSHOTS)) {
> +			igt_debug("clock %s\n", clock[index].name);
> +			igt_debug("usable %d\n", usable);
> +			igt_assert(usable > 2);
> +			usable = 0;
> +		}
> +	}
> +}
> +
> +static void test_cs_cycles(int i915)
> +{
> +	const struct intel_execution_engine2 *e;
> +	struct i915_engine_class_instance engine;
> +
> +	__for_each_physical_engine(i915, e) {
> +		if (engine_has_cs_cycles(i915, e->class, e->instance)) {
> +			engine.engine_class = e->class;
> +			engine.engine_instance = e->instance;
> +			__cs_cycles(i915, &engine);
> +		}
> +	}
> +}
> +
> +static void test_cs_cycles_invalid(int i915)
> +{
> +	struct i915_engine_class_instance engine;
> +	const struct intel_execution_engine2 *e;
> +	struct drm_i915_query_cs_cycles ts = {};
> +
> +	/* get one engine */
> +	__for_each_physical_engine(i915, e)
> +		break;
> +
> +	/* bad engines */
> +	ts.engine.engine_class = e->class;
> +	ts.engine.engine_instance = -1;
> +	__query_cs_cycles(i915, &ts, EINVAL);
> +
> +	ts.engine.engine_class = -1;
> +	ts.engine.engine_instance = e->instance;
> +	__query_cs_cycles(i915, &ts, EINVAL);
> +
> +	ts.engine.engine_class = -1;
> +	ts.engine.engine_instance = -1;
> +	__query_cs_cycles(i915, &ts, EINVAL);
> +
> +	/* non zero flags */
> +	ts.flags = 1;
> +	ts.engine.engine_class = e->class;
> +	ts.engine.engine_instance = e->instance;
> +	__query_cs_cycles(i915, &ts, EINVAL);
> +
> +	/* non zero rsvd field */
> +	ts.flags = 0;
> +	ts.rsvd = 1;
> +	__query_cs_cycles(i915, &ts, EINVAL);
> +
> +	/* bad clockid */
> +	ts.rsvd = 0;
> +	ts.clockid = -1;
> +	__query_cs_cycles(i915, &ts, EINVAL);
> +
> +	/* sanity check */
> +	engine.engine_class = e->class;
> +	engine.engine_instance = e->instance;
> +	__cs_cycles(i915, &engine);
> +}
> +
>   /*
>    * Verify that we get coherent values between the legacy getparam slice/subslice
>    * masks and the new topology query.
> @@ -783,6 +961,19 @@ igt_main
>   			engines(fd);
>   	}
>   
> +	igt_subtest_group {
> +		igt_fixture {
> +			igt_require(intel_gen(devid) >= 6);
> +			igt_require(query_cs_cycles_supported(fd));
> +		}
> +
> +		igt_subtest("cs-cycles")
> +			test_cs_cycles(fd);
> +
> +		igt_subtest("cs-cycles-invalid")
> +			test_cs_cycles_invalid(fd);
> +	}
> +
>   	igt_fixture {
>   		close(fd);
>   	}


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

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

* [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
@ 2021-03-03 21:28 Umesh Nerlige Ramappa
  2021-03-05 11:55 ` Lionel Landwerlin
  0 siblings, 1 reply; 13+ messages in thread
From: Umesh Nerlige Ramappa @ 2021-03-03 21:28 UTC (permalink / raw)
  To: igt-dev, Lionel G Landwerlin, Tvrtko Ursulin, Chris Wilson

Add tests to query CS timestamps for different engines.

v2:
- remove flag parameter
- assert for minimum usable values rather than maximum

v3:
- use clock id for cpu timestamps (Lionel)
- check if query is supported (Ashutosh)
- test bad queries

v4: (Chris, Tvrtko)
- cs_timestamp is a misnomer, use cs_cycles instead
- use cs cycle frequency returned in the query
- omit size parameter

v5:
- use __for_each_physical_engine (Lionel)
- check for ENODEV (Umesh)

v6: Use 2 cpu timestamps to calculate reg read time (Lionel)

Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
---
 include/drm-uapi/i915_drm.h |  47 +++++++++
 tests/i915/i915_query.c     | 191 ++++++++++++++++++++++++++++++++++++
 2 files changed, 238 insertions(+)

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index bf9ea471..e95e17f9 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
 #define DRM_I915_QUERY_TOPOLOGY_INFO    1
 #define DRM_I915_QUERY_ENGINE_INFO	2
 #define DRM_I915_QUERY_PERF_CONFIG      3
+	/**
+	 * Query Command Streamer timestamp register.
+	 */
+#define DRM_I915_QUERY_CS_CYCLES	4
 /* Must be kept compact -- no holes and well documented */
 
 	/*
@@ -2309,6 +2313,49 @@ struct drm_i915_engine_info {
 	__u64 rsvd1[4];
 };
 
+/**
+ * struct drm_i915_query_cs_cycles
+ *
+ * The query returns the command streamer cycles and the frequency that can be
+ * used to calculate the command streamer timestamp. In addition the query
+ * returns the cpu timestamp that indicates when the command streamer cycle
+ * count was captured.
+ */
+struct drm_i915_query_cs_cycles {
+	/** Engine for which command streamer cycles is queried. */
+	struct i915_engine_class_instance engine;
+
+	/** Must be zero. */
+	__u32 flags;
+
+	/**
+	 * Command streamer cycles as read from the command streamer
+	 * register at 0x358 offset.
+	 */
+	__u64 cs_cycles;
+
+	/** Frequency of the cs cycles in Hz. */
+	__u64 cs_frequency;
+
+	/**
+	 * CPU timestamp in nanoseconds. cpu_timestamp[0] is captured before
+	 * reading the cs_cycles register and cpu_timestamp[1] is captured after
+	 * reading the register.
+	 **/
+	__u64 cpu_timestamp[2];
+
+	/**
+	 * Reference clock id for CPU timestamp. For definition, see
+	 * clock_gettime(2) and perf_event_open(2). Supported clock ids are
+	 * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
+	 * CLOCK_TAI.
+	 */
+	__s32 clockid;
+
+	/** Must be zero. */
+	__u32 rsvd;
+};
+
 /**
  * struct drm_i915_query_engine_info
  *
diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
index 29b938e9..e1c5f93d 100644
--- a/tests/i915/i915_query.c
+++ b/tests/i915/i915_query.c
@@ -267,6 +267,184 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
 				eu / 8] >> (eu % 8)) & 1;
 }
 
+static bool query_cs_cycles_supported(int fd)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+	};
+
+	return __i915_query_items(fd, &item, 1) == 0 && item.length > 0;
+}
+
+static void __query_cs_cycles(int i915, void *data, int err)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+		.data_ptr = to_user_pointer(data),
+		.length = sizeof(struct drm_i915_query_cs_cycles),
+	};
+
+	i915_query_items(i915, &item, 1);
+
+	if (err)
+		igt_assert(item.length == -err);
+}
+
+static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
+{
+	struct drm_i915_query_cs_cycles ts = {};
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+		.data_ptr = to_user_pointer(&ts),
+		.length = sizeof(struct drm_i915_query_cs_cycles),
+	};
+
+	ts.engine.engine_class = class;
+	ts.engine.engine_instance = instance;
+
+	i915_query_items(i915, &item, 1);
+
+	return item.length != -ENODEV;
+}
+
+static void
+__cs_cycles(int i915, struct i915_engine_class_instance *engine)
+{
+	struct drm_i915_query_cs_cycles ts1 = {};
+	struct drm_i915_query_cs_cycles ts2 = {};
+	uint64_t delta_cpu, delta_cs, delta_delta;
+	int i, usable = 0;
+	struct {
+		int32_t id;
+		const char *name;
+	} clock[] = {
+		{ CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
+		{ CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
+		{ CLOCK_REALTIME, "CLOCK_REALTIME" },
+		{ CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
+		{ CLOCK_TAI, "CLOCK_TAI" },
+	};
+
+	igt_debug("engine[%u:%u]\n",
+		  engine->engine_class,
+		  engine->engine_instance);
+
+	/* Try a new clock every 10 iterations. */
+#define NUM_SNAPSHOTS 10
+	for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
+		int index = i / NUM_SNAPSHOTS;
+
+		ts1.engine = *engine;
+		ts1.clockid = clock[index].id;
+
+		ts2.engine = *engine;
+		ts2.clockid = clock[index].id;
+
+		__query_cs_cycles(i915, &ts1, 0);
+		__query_cs_cycles(i915, &ts2, 0);
+
+		igt_debug("[1] cpu_ts before %llu, cpu_ts after %llu, reg read time %llu\n",
+			  ts1.cpu_timestamp[0],
+			  ts1.cpu_timestamp[1],
+			  ts1.cpu_timestamp[1] - ts1.cpu_timestamp[0]);
+		igt_debug("[1] cs_ts %llu, freq %llu Hz\n",
+			  ts1.cs_cycles, ts1.cs_frequency);
+
+		igt_debug("[2] cpu_ts before %llu, cpu_ts after %llu, reg read time %llu\n",
+			  ts2.cpu_timestamp[0],
+			  ts2.cpu_timestamp[1],
+			  ts2.cpu_timestamp[1] - ts2.cpu_timestamp[0]);
+		igt_debug("[2] cs_ts %llu, freq %llu Hz\n",
+			  ts2.cs_cycles, ts2.cs_frequency);
+
+		delta_cpu = ts2.cpu_timestamp[0] - ts1.cpu_timestamp[0];
+		delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
+			   NSEC_PER_SEC / ts1.cs_frequency;
+
+		igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
+			  delta_cpu, delta_cs);
+
+		delta_delta = delta_cpu > delta_cs ?
+			       delta_cpu - delta_cs :
+			       delta_cs - delta_cpu;
+		igt_debug("delta_delta %lu\n", delta_delta);
+
+		if (delta_delta < 5000)
+			usable++;
+
+		/*
+		 * User needs few good snapshots of the timestamps to
+		 * synchronize cpu time with cs time. Check if we have enough
+		 * usable values before moving to the next clockid.
+		 */
+		if (!((i + 1) % NUM_SNAPSHOTS)) {
+			igt_debug("clock %s\n", clock[index].name);
+			igt_debug("usable %d\n", usable);
+			igt_assert(usable > 2);
+			usable = 0;
+		}
+	}
+}
+
+static void test_cs_cycles(int i915)
+{
+	const struct intel_execution_engine2 *e;
+	struct i915_engine_class_instance engine;
+
+	__for_each_physical_engine(i915, e) {
+		if (engine_has_cs_cycles(i915, e->class, e->instance)) {
+			engine.engine_class = e->class;
+			engine.engine_instance = e->instance;
+			__cs_cycles(i915, &engine);
+		}
+	}
+}
+
+static void test_cs_cycles_invalid(int i915)
+{
+	struct i915_engine_class_instance engine;
+	const struct intel_execution_engine2 *e;
+	struct drm_i915_query_cs_cycles ts = {};
+
+	/* get one engine */
+	__for_each_physical_engine(i915, e)
+		break;
+
+	/* bad engines */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = -1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = e->instance;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = -1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* non zero flags */
+	ts.flags = 1;
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* non zero rsvd field */
+	ts.flags = 0;
+	ts.rsvd = 1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* bad clockid */
+	ts.rsvd = 0;
+	ts.clockid = -1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* sanity check */
+	engine.engine_class = e->class;
+	engine.engine_instance = e->instance;
+	__cs_cycles(i915, &engine);
+}
+
 /*
  * Verify that we get coherent values between the legacy getparam slice/subslice
  * masks and the new topology query.
@@ -783,6 +961,19 @@ igt_main
 			engines(fd);
 	}
 
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(intel_gen(devid) >= 6);
+			igt_require(query_cs_cycles_supported(fd));
+		}
+
+		igt_subtest("cs-cycles")
+			test_cs_cycles(fd);
+
+		igt_subtest("cs-cycles-invalid")
+			test_cs_cycles_invalid(fd);
+	}
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.20.1

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

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

* [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp
@ 2021-03-02 18:30 Umesh Nerlige Ramappa
  0 siblings, 0 replies; 13+ messages in thread
From: Umesh Nerlige Ramappa @ 2021-03-02 18:30 UTC (permalink / raw)
  To: igt-dev, Lionel G Landwerlin, Tvrtko Ursulin, Chris Wilson

Add tests to query CS timestamps for different engines.

v2:
- remove flag parameter
- assert for minimum usable values rather than maximum

v3:
- use clock id for cpu timestamps (Lionel)
- check if query is supported (Ashutosh)
- test bad queries

v4: (Chris, Tvrtko)
- cs_timestamp is a misnomer, use cs_cycles instead
- use cs cycle frequency returned in the query
- omit size parameter

v5:
- use __for_each_physical_engine (Lionel)
- check for ENODEV (Umesh)

Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
---
 include/drm-uapi/i915_drm.h |  43 +++++++++
 tests/i915/i915_query.c     | 186 ++++++++++++++++++++++++++++++++++++
 2 files changed, 229 insertions(+)

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index bf9ea471..a29f8578 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -2176,6 +2176,10 @@ struct drm_i915_query_item {
 #define DRM_I915_QUERY_TOPOLOGY_INFO    1
 #define DRM_I915_QUERY_ENGINE_INFO	2
 #define DRM_I915_QUERY_PERF_CONFIG      3
+	/**
+	 * Query Command Streamer timestamp register.
+	 */
+#define DRM_I915_QUERY_CS_CYCLES	4
 /* Must be kept compact -- no holes and well documented */
 
 	/*
@@ -2309,6 +2313,45 @@ struct drm_i915_engine_info {
 	__u64 rsvd1[4];
 };
 
+/**
+ * struct drm_i915_query_cs_cycles
+ *
+ * The query returns the command streamer cycles and the frequency that can be
+ * used to calculate the command streamer timestamp. In addition the query
+ * returns the cpu timestamp that indicates when the command streamer cycle
+ * count was captured.
+ */
+struct drm_i915_query_cs_cycles {
+	/** Engine for which command streamer cycles is queried. */
+	struct i915_engine_class_instance engine;
+
+	/** Must be zero. */
+	__u32 flags;
+
+	/**
+	 * Command streamer cycles as read from the command streamer
+	 * register at 0x358 offset.
+	 */
+	__u64 cs_cycles;
+
+	/** Frequency of the cs cycles in Hz. */
+	__u64 cs_frequency;
+
+	/** CPU timestamp in nanoseconds. */
+	__u64 cpu_timestamp;
+
+	/**
+	 * Reference clock id for CPU timestamp. For definition, see
+	 * clock_gettime(2) and perf_event_open(2). Supported clock ids are
+	 * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME,
+	 * CLOCK_TAI.
+	 */
+	__s32 clockid;
+
+	/** Must be zero. */
+	__u32 rsvd;
+};
+
 /**
  * struct drm_i915_query_engine_info
  *
diff --git a/tests/i915/i915_query.c b/tests/i915/i915_query.c
index 29b938e9..0d7f3256 100644
--- a/tests/i915/i915_query.c
+++ b/tests/i915/i915_query.c
@@ -267,6 +267,179 @@ eu_available(const struct drm_i915_query_topology_info *topo_info,
 				eu / 8] >> (eu % 8)) & 1;
 }
 
+static bool query_cs_cycles_supported(int fd)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+	};
+
+	return __i915_query_items(fd, &item, 1) == 0 && item.length > 0;
+}
+
+static void __query_cs_cycles(int i915, void *data, int err)
+{
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+		.data_ptr = to_user_pointer(data),
+		.length = sizeof(struct drm_i915_query_cs_cycles),
+	};
+
+	i915_query_items(i915, &item, 1);
+
+	if (err)
+		igt_assert(item.length == -err);
+}
+
+static bool engine_has_cs_cycles(int i915, uint16_t class, uint16_t instance)
+{
+	struct drm_i915_query_cs_cycles ts = {};
+	struct drm_i915_query_item item = {
+		.query_id = DRM_I915_QUERY_CS_CYCLES,
+		.data_ptr = to_user_pointer(&ts),
+		.length = sizeof(struct drm_i915_query_cs_cycles),
+	};
+
+	ts.engine.engine_class = class;
+	ts.engine.engine_instance = instance;
+
+	i915_query_items(i915, &item, 1);
+
+	return item.length != -ENODEV;
+}
+
+static void
+__cs_cycles(int i915, struct i915_engine_class_instance *engine)
+{
+	struct drm_i915_query_cs_cycles ts1 = {};
+	struct drm_i915_query_cs_cycles ts2 = {};
+	uint64_t delta_cpu, delta_cs, delta_delta;
+	int i, usable = 0;
+	struct {
+		int32_t id;
+		const char *name;
+	} clock[] = {
+		{ CLOCK_MONOTONIC, "CLOCK_MONOTONIC" },
+		{ CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW" },
+		{ CLOCK_REALTIME, "CLOCK_REALTIME" },
+		{ CLOCK_BOOTTIME, "CLOCK_BOOTTIME" },
+		{ CLOCK_TAI, "CLOCK_TAI" },
+	};
+
+	igt_debug("engine[%u:%u]\n",
+		  engine->engine_class,
+		  engine->engine_instance);
+
+	/* Try a new clock every 10 iterations. */
+#define NUM_SNAPSHOTS 10
+	for (i = 0; i < NUM_SNAPSHOTS * ARRAY_SIZE(clock); i++) {
+		int index = i / NUM_SNAPSHOTS;
+
+		ts1.engine = *engine;
+		ts1.clockid = clock[index].id;
+
+		ts2.engine = *engine;
+		ts2.clockid = clock[index].id;
+
+		__query_cs_cycles(i915, &ts1, 0);
+		__query_cs_cycles(i915, &ts2, 0);
+
+		igt_debug("cpu_ts1[%llu], cs_ts1[%llu], freq %llu Hz\n",
+			  ts1.cpu_timestamp,
+			  ts1.cs_cycles,
+			  ts1.cs_frequency);
+		igt_debug("cpu_ts2[%llu], cs_ts2[%llu], freq %llu Hz\n",
+			  ts2.cpu_timestamp,
+			  ts2.cs_cycles,
+			  ts2.cs_frequency);
+
+		delta_cpu = ts2.cpu_timestamp - ts1.cpu_timestamp;
+		delta_cs = (ts2.cs_cycles - ts1.cs_cycles) *
+			   NSEC_PER_SEC / ts1.cs_frequency;
+
+		igt_debug("delta_cpu[%lu], delta_cs[%lu]\n",
+			  delta_cpu, delta_cs);
+
+		delta_delta = delta_cpu > delta_cs ?
+			       delta_cpu - delta_cs :
+			       delta_cs - delta_cpu;
+		igt_debug("delta_delta %lu\n", delta_delta);
+
+		if (delta_delta < 5000)
+			usable++;
+
+		/*
+		 * User needs few good snapshots of the timestamps to
+		 * synchronize cpu time with cs time. Check if we have enough
+		 * usable values before moving to the next clockid.
+		 */
+		if (!((i + 1) % NUM_SNAPSHOTS)) {
+			igt_debug("clock %s\n", clock[index].name);
+			igt_debug("usable %d\n", usable);
+			igt_assert(usable > 2);
+			usable = 0;
+		}
+	}
+}
+
+static void test_cs_cycles(int i915)
+{
+	const struct intel_execution_engine2 *e;
+	struct i915_engine_class_instance engine;
+
+	__for_each_physical_engine(i915, e) {
+		if (engine_has_cs_cycles(i915, e->class, e->instance)) {
+			engine.engine_class = e->class;
+			engine.engine_instance = e->instance;
+			__cs_cycles(i915, &engine);
+		}
+	}
+}
+
+static void test_cs_cycles_invalid(int i915)
+{
+	struct i915_engine_class_instance engine;
+	const struct intel_execution_engine2 *e;
+	struct drm_i915_query_cs_cycles ts = {};
+
+	/* get one engine */
+	__for_each_physical_engine(i915, e)
+		break;
+
+	/* bad engines */
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = -1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = e->instance;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	ts.engine.engine_class = -1;
+	ts.engine.engine_instance = -1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* non zero flags */
+	ts.flags = 1;
+	ts.engine.engine_class = e->class;
+	ts.engine.engine_instance = e->instance;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* non zero rsvd field */
+	ts.flags = 0;
+	ts.rsvd = 1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* bad clockid */
+	ts.rsvd = 0;
+	ts.clockid = -1;
+	__query_cs_cycles(i915, &ts, EINVAL);
+
+	/* sanity check */
+	engine.engine_class = e->class;
+	engine.engine_instance = e->instance;
+	__cs_cycles(i915, &engine);
+}
+
 /*
  * Verify that we get coherent values between the legacy getparam slice/subslice
  * masks and the new topology query.
@@ -783,6 +956,19 @@ igt_main
 			engines(fd);
 	}
 
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(intel_gen(devid) >= 6);
+			igt_require(query_cs_cycles_supported(fd));
+		}
+
+		igt_subtest("cs-cycles")
+			test_cs_cycles(fd);
+
+		igt_subtest("cs-cycles-invalid")
+			test_cs_cycles_invalid(fd);
+	}
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.20.1

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

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

end of thread, other threads:[~2021-05-04  0:10 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-29  0:29 [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp Umesh Nerlige Ramappa
2021-04-29  1:25 ` [igt-dev] ✓ Fi.CI.BAT: success for i915/perf: Add test to query CS timestamp (rev6) Patchwork
2021-04-29  2:42 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  -- strict thread matches above, loose matches on Subject: below --
2021-05-04  0:10 [igt-dev] [PATCH i-g-t] i915/perf: Add test to query CS timestamp Umesh Nerlige Ramappa
2021-04-21 17:20 Umesh Nerlige Ramappa
2021-03-12 19:18 Umesh Nerlige Ramappa
2021-03-05 19:37 Umesh Nerlige Ramappa
2021-03-05 19:41 ` Umesh Nerlige Ramappa
2021-03-05 20:33 ` Chris Wilson
2021-03-13  6:04   ` Umesh Nerlige Ramappa
2021-03-03 21:28 Umesh Nerlige Ramappa
2021-03-05 11:55 ` Lionel Landwerlin
2021-03-02 18:30 Umesh Nerlige Ramappa

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.