All of lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [RFC PATCH v10 0/6] new engine discovery interface
@ 2019-03-05 13:16 Andi Shyti
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 1/6] include/drm-uapi: import i915_drm.h header file Andi Shyti
                   ` (7 more replies)
  0 siblings, 8 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-05 13:16 UTC (permalink / raw)
  To: IGT dev; +Cc: Andi Shyti

Hi,

In this patchset I propose an alternative way of engine discovery
thanks to the new interfaces developed by Tvrtko and Chris[4].

Thanks Tvrtko, Chris, Antonio and Petri for your comments in the
previous RFCs.

Andi

v9 --> v10
==========
RFC v9: [11]
also this time quite many changes, thanks Chris for the reviews,
here the most relevant of them.
- gem_query.[ch] have been renamed to gem_engine_topology.[ch]
  and all the functions ended up there as they are referring to
  the topology of the engines.
- the functions 'get_active_engines()',
  'gem_set_context_get_engines()' and
  'igt_require_gem_engine_list()' will be the main interface to
  the gem_engine_topology library, refer to patch 2 for details.
- the define 'for_each_engine2()' doesn't expose anymore the
  iterator.
- 'gem_context_has_engine()' has been moved from ioctl_wrappers.c
  to gem_context.c.
- the gem_exec_basic exec-ctx subtest does not abort if the new
  getparam/setparam and query apis are not implemented as it can
  work with both (as it was done at the beginning).

v8 --> v9
=========
RFC v8: [10]
quite many changes, please refer to the review in [10]. Thanks
Chris for the review. These are the most relevant:
- all the allocation in gem_query have been made in stack, not
  anymore allocated dynamically.
- removed get/set_context as it was already implemented and I
  didn't know.
- renamed some functions and variables to hopefully more
  meaningful names.

V7 --> v8
=========
RFC v7: [9]
- all functions have been moved from lib/igt_gt.{c,h} and
  lib/ioctl_wrappers.{c,h} to lib/i916/gem_query.{c,h}. (thanks
  Chris)
- 'for_each_engine_ctx' has been renamed to 'for_each_engine2' to
  be consistent with the '2' that indicates the new 'struct
  intel_execution_engine2' data structure.

V6 --> V7
=========
RFC v6: [8]
- a new patch has been added (patch 3) which adds a new
  requirement check through the igt_require_gem_engine_list()
  function. (thanks Chris) This function will initialize the
  engine list instead of the instead of igt_require_gem() as it
  was in v6
- all the ioctls have been wrapped (thanks Chris and Antonio) and
  new library functions have been added and assert the ioctls
- gem_init_engine_list() function returns the errno from the
  GETPARAM ioctl in order to be used as a requirement. (thanks
  Chris)
- fixed few requires/asserts
- The engine list "intel_active_engines2" is allocated of the
  number of engines instead of a political 64 (thanks Antonio).
- some parameter renaming in gem_has_ring_by_idx(). (thanks
  Chris).
- the original "intel_execution_engines2" has not been renamed,
  because it is used to create subtests before even executing any
  test/ioctl. By renaming it, some subtest generations failed.
  (thanks Petri)

V5 --> V6
=========
RFC v5: [7]
- Chris implemented the getparam ioctl which allows to the test
  to figure otu whether the new interface has been implemented.
  This way the for_each_engine_ctx() is able to work with new and
  old kernel uapi (thanks Chris)

V4 --> V5
=========
RFC v4: [6]
- the engine list is now built in 'igt_require_gem()' instead of
  '__open_driver()' so that we keep this discovery method
  specific to the i915 driver (thanks Chris).
- All the query/setparam structures dynamic allocation based on
  the number of engines, now are politically allocated 64 times,
  to avoid extra ioctl calls that retrieve the engine number
  (thanks Chris)
- use igt_ioctl instead of ioctl (thanks Chris)
- allocate intel_execution_engines2 dynamically instead of
  statically (thanks Tvrtko)
- simplify the test in 'gem_exec_basic()' so that simply checks
  the presence of the engine instead of executing a buffer
  (thank Chris)
- a new patch has been added (patch 3) that extends the
  'gem_has_ring()' boolean function. The new version sets the
  index as it's mapped in the kernel.The previous function is now
  a wrapper to the new function.

V3 --> V4
=========
PATCH v3: [3]
- re-architectured the discovery mechanism based on Tvrtko's
  sugestion and reviews.. In this version the discovery is done
  during the device opening and stored in a NULL terminated
  array, which replaces the existing intel_execution_engines2
  that is mainly used as a reference.

V2 --> V3
=========
RFC v2: [2]
- removed a standalone gem_query_engines_demo test and added the
  exec-ctx subtest inside gem_exec_basic (thanks Tvrtko).
- fixed most of Tvrtko's comments in [5], which consist in
  putting the mallocs igt_assert and ictls in igt_require and few
  refactoring (thanks Tvrtko).

V1 --> V2
=========
RFC v1: [1]
- added a demo test that simply queries the driver about the
  engines and executes a buffer (thanks Tvrtko)
- refactored the for_each_engine_ctx() macro so that what in the
  previous version was done by the "bind" function, now it's done
  in the first iteration. (Thanks Crhis)
- removed the "gem_has_ring_ctx()" because it was out of the
  scope.
- rename functions to more meaningful names

[1] RFC v1: https://lists.freedesktop.org/archives/igt-dev/2018-November/007025.html
[2] RFC v2: https://lists.freedesktop.org/archives/igt-dev/2018-November/007079.html
[3] PATCH v3: https://lists.freedesktop.org/archives/igt-dev/2018-November/007148.html
[4] https://cgit.freedesktop.org/~tursulin/drm-intel/log/?h=media
[5] https://lists.freedesktop.org/archives/igt-dev/2018-November/007100.html
[6] https://lists.freedesktop.org/archives/igt-dev/2019-January/008029.html
[7] https://lists.freedesktop.org/archives/igt-dev/2019-January/008165.html
[8] https://lists.freedesktop.org/archives/igt-dev/2019-February/008902.html
[9] https://lists.freedesktop.org/archives/igt-dev/2019-February/009185.html
[10] https://lists.freedesktop.org/archives/igt-dev/2019-February/009205.html
[11] https://lists.freedesktop.org/archives/igt-dev/2019-February/009277.html

Andi Shyti (6):
  include/drm-uapi: import i915_drm.h header file
  lib/i915: add gem_engine_topology library
  lib/igt_gt: use for_each_engine2 to loop through engines
  lib: ioctl_wrappers: reach engines by index as well
  lib: move gem_context_has_engine from ioctl_wrappers to gem_context
  tests: gem_exec_basic: add "exec-ctx" buffer execution demo test

 include/drm-uapi/i915_drm.h    | 389 ++++++++++++++++++++++++++-------
 lib/Makefile.sources           |   2 +
 lib/i915/gem_context.c         |  21 ++
 lib/i915/gem_context.h         |   2 +
 lib/i915/gem_engine_topology.c | 199 +++++++++++++++++
 lib/i915/gem_engine_topology.h |  39 ++++
 lib/igt_gt.c                   |   2 +-
 lib/igt_gt.h                   |  10 +-
 lib/ioctl_wrappers.c           |  19 --
 lib/ioctl_wrappers.h           |   3 +-
 lib/meson.build                |   1 +
 tests/i915/gem_exec_basic.c    |  12 +
 12 files changed, 604 insertions(+), 95 deletions(-)
 create mode 100644 lib/i915/gem_engine_topology.c
 create mode 100644 lib/i915/gem_engine_topology.h

-- 
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] 30+ messages in thread

* [igt-dev] [RFC PATCH v10 1/6] include/drm-uapi: import i915_drm.h header file
  2019-03-05 13:16 [igt-dev] [RFC PATCH v10 0/6] new engine discovery interface Andi Shyti
@ 2019-03-05 13:16 ` Andi Shyti
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library Andi Shyti
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-05 13:16 UTC (permalink / raw)
  To: IGT dev; +Cc: Andi Shyti

This header file is imported in order to include the two new
ioctls DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM,
DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM and DRM_IOCTL_I915_QUERY.

Signed-off-by: Andi Shyti <andi.shyti@intel.com>
---
 include/drm-uapi/i915_drm.h | 389 +++++++++++++++++++++++++++++-------
 1 file changed, 316 insertions(+), 73 deletions(-)

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index 43fb8ede2fe0..12e14cdad451 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -62,6 +62,26 @@ extern "C" {
 #define I915_ERROR_UEVENT		"ERROR"
 #define I915_RESET_UEVENT		"RESET"
 
+/*
+ * i915_user_extension: Base class for defining a chain of extensions
+ *
+ * Many interfaces need to grow over time. In most cases we can simply
+ * extend the struct and have userspace pass in more data. Another option,
+ * as demonstrated by Vulkan's approach to providing extensions for forward
+ * and backward compatibility, is to use a list of optional structs to
+ * provide those extra details.
+ *
+ * The key advantage to using an extension chain is that it allows us to
+ * redefine the interface more easily than an ever growing struct of
+ * increasing complexity, and for large parts of that interface to be
+ * entirely optional. The downside is more pointer chasing; chasing across
+ * the boundary with pointers encapsulated inside u64.
+ */
+struct i915_user_extension {
+	__u64 next_extension;
+	__u64 name;
+};
+
 /*
  * MOCS indexes used for GPU surfaces, defining the cacheability of the
  * surface data and the coherency for this data wrt. CPU vs. GPU accesses.
@@ -99,9 +119,14 @@ enum drm_i915_gem_engine_class {
 	I915_ENGINE_CLASS_VIDEO		= 2,
 	I915_ENGINE_CLASS_VIDEO_ENHANCE	= 3,
 
+	/* should be kept compact */
+
 	I915_ENGINE_CLASS_INVALID	= -1
 };
 
+#define I915_ENGINE_CLASS_INVALID_NONE -1
+#define I915_ENGINE_CLASS_INVALID_VIRTUAL 0
+
 /**
  * DOC: perf_events exposed by i915 through /sys/bus/event_sources/drivers/i915
  *
@@ -319,6 +344,9 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_PERF_ADD_CONFIG	0x37
 #define DRM_I915_PERF_REMOVE_CONFIG	0x38
 #define DRM_I915_QUERY			0x39
+#define DRM_I915_GEM_VM_CREATE		0x3a
+#define DRM_I915_GEM_VM_DESTROY		0x3b
+/* Must be kept compact -- no holes */
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -367,6 +395,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
 #define DRM_IOCTL_I915_GEM_WAIT		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait)
 #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create)
+#define DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create_ext)
 #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy)
 #define DRM_IOCTL_I915_REG_READ			DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read)
 #define DRM_IOCTL_I915_GET_RESET_STATS		DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats)
@@ -377,6 +406,8 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_PERF_ADD_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config)
 #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64)
 #define DRM_IOCTL_I915_QUERY			DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query)
+#define DRM_IOCTL_I915_GEM_VM_CREATE	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_VM_CREATE, struct drm_i915_gem_vm_control)
+#define DRM_IOCTL_I915_GEM_VM_DESTROY	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_VM_DESTROY, struct drm_i915_gem_vm_control)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -476,6 +507,7 @@ typedef struct drm_i915_irq_wait {
 #define   I915_SCHEDULER_CAP_ENABLED	(1ul << 0)
 #define   I915_SCHEDULER_CAP_PRIORITY	(1ul << 1)
 #define   I915_SCHEDULER_CAP_PREEMPTION	(1ul << 2)
+#define   I915_SCHEDULER_CAP_SEMAPHORES	(1ul << 3)
 
 #define I915_PARAM_HUC_STATUS		 42
 
@@ -559,6 +591,14 @@ typedef struct drm_i915_irq_wait {
  */
 #define I915_PARAM_MMAP_GTT_COHERENT	52
 
+/*
+ * Query whether DRM_I915_GEM_EXECBUFFER2 supports coordination of parallel
+ * execution through use of explicit fence support.
+ * See I915_EXEC_FENCE_OUT and I915_EXEC_FENCE_SUBMIT.
+ */
+#define I915_PARAM_HAS_EXEC_SUBMIT_FENCE 53
+/* Must be kept compact -- no holes and well documented */
+
 typedef struct drm_i915_getparam {
 	__s32 param;
 	/*
@@ -574,6 +614,7 @@ typedef struct drm_i915_getparam {
 #define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY             2
 #define I915_SETPARAM_ALLOW_BATCHBUFFER                   3
 #define I915_SETPARAM_NUM_USED_FENCES                     4
+/* Must be kept compact -- no holes */
 
 typedef struct drm_i915_setparam {
 	int param;
@@ -972,7 +1013,7 @@ struct drm_i915_gem_execbuffer2 {
 	 * struct drm_i915_gem_exec_fence *fences.
 	 */
 	__u64 cliprects_ptr;
-#define I915_EXEC_RING_MASK              (7<<0)
+#define I915_EXEC_RING_MASK              (0x3f)
 #define I915_EXEC_DEFAULT                (0<<0)
 #define I915_EXEC_RENDER                 (1<<0)
 #define I915_EXEC_BSD                    (2<<0)
@@ -1078,7 +1119,16 @@ struct drm_i915_gem_execbuffer2 {
  */
 #define I915_EXEC_FENCE_ARRAY   (1<<19)
 
-#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_ARRAY<<1))
+/*
+ * Setting I915_EXEC_FENCE_SUBMIT implies that lower_32_bits(rsvd2) represent
+ * a sync_file fd to wait upon (in a nonblocking manner) prior to executing
+ * the batch.
+ *
+ * Returns -EINVAL if the sync_file fd cannot be found.
+ */
+#define I915_EXEC_FENCE_SUBMIT		(1 << 20)
+
+#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SUBMIT << 1))
 
 #define I915_EXEC_CONTEXT_ID_MASK	(0xffffffff)
 #define i915_execbuffer2_set_context_id(eb2, context) \
@@ -1120,32 +1170,34 @@ struct drm_i915_gem_busy {
 	 * as busy may become idle before the ioctl is completed.
 	 *
 	 * Furthermore, if the object is busy, which engine is busy is only
-	 * provided as a guide. There are race conditions which prevent the
-	 * report of which engines are busy from being always accurate.
-	 * However, the converse is not true. If the object is idle, the
-	 * result of the ioctl, that all engines are idle, is accurate.
+	 * provided as a guide and only indirectly by reporting its class
+	 * (there may be more than one engine in each class). There are race
+	 * conditions which prevent the report of which engines are busy from
+	 * being always accurate.  However, the converse is not true. If the
+	 * object is idle, the result of the ioctl, that all engines are idle,
+	 * is accurate.
 	 *
 	 * The returned dword is split into two fields to indicate both
-	 * the engines on which the object is being read, and the
-	 * engine on which it is currently being written (if any).
+	 * the engine classess on which the object is being read, and the
+	 * engine class on which it is currently being written (if any).
 	 *
 	 * The low word (bits 0:15) indicate if the object is being written
 	 * to by any engine (there can only be one, as the GEM implicit
 	 * synchronisation rules force writes to be serialised). Only the
-	 * engine for the last write is reported.
+	 * engine class (offset by 1, I915_ENGINE_CLASS_RENDER is reported as
+	 * 1 not 0 etc) for the last write is reported.
 	 *
-	 * The high word (bits 16:31) are a bitmask of which engines are
-	 * currently reading from the object. Multiple engines may be
+	 * The high word (bits 16:31) are a bitmask of which engines classes
+	 * are currently reading from the object. Multiple engines may be
 	 * reading from the object simultaneously.
 	 *
-	 * The value of each engine is the same as specified in the
-	 * EXECBUFFER2 ioctl, i.e. I915_EXEC_RENDER, I915_EXEC_BSD etc.
-	 * Note I915_EXEC_DEFAULT is a symbolic value and is mapped to
-	 * the I915_EXEC_RENDER engine for execution, and so it is never
+	 * The value of each engine class is the same as specified in the
+	 * I915_CONTEXT_SET_ENGINES parameter and via perf, i.e.
+	 * I915_ENGINE_CLASS_RENDER, I915_ENGINE_CLASS_COPY, etc.
 	 * reported as active itself. Some hardware may have parallel
 	 * execution engines, e.g. multiple media engines, which are
-	 * mapped to the same identifier in the EXECBUFFER2 ioctl and
-	 * so are not separately reported for busyness.
+	 * mapped to the same class identifier and so are not separately
+	 * reported for busyness.
 	 *
 	 * Caveat emptor:
 	 * Only the boolean result of this query is reliable; that is whether
@@ -1412,65 +1464,18 @@ struct drm_i915_gem_wait {
 };
 
 struct drm_i915_gem_context_create {
-	/*  output: id of new context*/
-	__u32 ctx_id;
-	__u32 pad;
-};
-
-struct drm_i915_gem_context_destroy {
-	__u32 ctx_id;
-	__u32 pad;
-};
-
-struct drm_i915_reg_read {
-	/*
-	 * Register offset.
-	 * For 64bit wide registers where the upper 32bits don't immediately
-	 * follow the lower 32bits, the offset of the lower 32bits must
-	 * be specified
-	 */
-	__u64 offset;
-#define I915_REG_READ_8B_WA (1ul << 0)
-
-	__u64 val; /* Return value */
-};
-/* Known registers:
- *
- * Render engine timestamp - 0x2358 + 64bit - gen7+
- * - Note this register returns an invalid value if using the default
- *   single instruction 8byte read, in order to workaround that pass
- *   flag I915_REG_READ_8B_WA in offset field.
- *
- */
-
-struct drm_i915_reset_stats {
-	__u32 ctx_id;
-	__u32 flags;
-
-	/* All resets since boot/module reload, for all contexts */
-	__u32 reset_count;
-
-	/* Number of batches lost when active in GPU, for this context */
-	__u32 batch_active;
-
-	/* Number of batches lost pending for execution, for this context */
-	__u32 batch_pending;
-
+	__u32 ctx_id; /* output: id of new context*/
 	__u32 pad;
 };
 
-struct drm_i915_gem_userptr {
-	__u64 user_ptr;
-	__u64 user_size;
+struct drm_i915_gem_context_create_ext {
+	__u32 ctx_id; /* output: id of new context*/
 	__u32 flags;
-#define I915_USERPTR_READ_ONLY 0x1
-#define I915_USERPTR_UNSYNCHRONIZED 0x80000000
-	/**
-	 * Returned handle for the object.
-	 *
-	 * Object handles are nonzero.
-	 */
-	__u32 handle;
+#define I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS	(1u << 0)
+#define I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE	(1u << 1)
+#define I915_CONTEXT_CREATE_FLAGS_UNKNOWN \
+	(-(I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE << 1))
+	__u64 extensions;
 };
 
 struct drm_i915_gem_context_param {
@@ -1511,6 +1516,43 @@ struct drm_i915_gem_context_param {
  * On creation, all new contexts are marked as recoverable.
  */
 #define I915_CONTEXT_PARAM_RECOVERABLE	0x8
+
+	/*
+	 * The id of the associated virtual memory address space (ppGTT) of
+	 * this context. Can be retrieved and passed to another context
+	 * (on the same fd) for both to use the same ppGTT and so share
+	 * address layouts, and avoid reloading the page tables on context
+	 * switches between themselves.
+	 *
+	 * See DRM_I915_GEM_VM_CREATE and DRM_I915_GEM_VM_DESTROY.
+	 */
+#define I915_CONTEXT_PARAM_VM		0x9
+
+/*
+ * I915_CONTEXT_PARAM_ENGINES:
+ *
+ * Bind this context to operate on this subset of available engines. Henceforth,
+ * the I915_EXEC_RING selector for DRM_IOCTL_I915_GEM_EXECBUFFER2 operates as
+ * an index into this array of engines; I915_EXEC_DEFAULT selecting engine[0]
+ * and upwards. Slots 0...N are filled in using the specified (class, instance).
+ * Use
+ *	engine_class: I915_ENGINE_CLASS_INVALID,
+ *	engine_instance: I915_ENGINE_CLASS_INVALID_NONE
+ * to specify a gap in the array that can be filled in later, e.g. by a
+ * virtual engine used for load balancing.
+ *
+ * Setting the number of engines bound to the context to 0, by passing a zero
+ * sized argument, will revert back to default settings.
+ *
+ * See struct i915_context_param_engines.
+ *
+ * Extensions:
+ *   i915_context_engines_load_balance (I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE)
+ *   i915_context_engines_bond (I915_CONTEXT_ENGINES_EXT_BOND)
+ */
+#define I915_CONTEXT_PARAM_ENGINES	0xa
+/* Must be kept compact -- no holes and well documented */
+
 	__u64 value;
 };
 
@@ -1543,9 +1585,10 @@ struct drm_i915_gem_context_param_sseu {
 	__u16 engine_instance;
 
 	/*
-	 * Unused for now. Must be cleared to zero.
+	 * Unknown flags must be cleared to zero.
 	 */
 	__u32 flags;
+#define I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX (1u << 0)
 
 	/*
 	 * Mask of slices to enable for the context. Valid values are a subset
@@ -1573,6 +1616,160 @@ struct drm_i915_gem_context_param_sseu {
 	__u32 rsvd;
 };
 
+/*
+ * i915_context_engines_load_balance:
+ *
+ * Enable load balancing across this set of engines.
+ *
+ * Into the I915_EXEC_DEFAULT slot [0], a virtual engine is created that when
+ * used will proxy the execbuffer request onto one of the set of engines
+ * in such a way as to distribute the load evenly across the set.
+ *
+ * The set of engines must be compatible (e.g. the same HW class) as they
+ * will share the same logical GPU context and ring.
+ *
+ * To intermix rendering with the virtual engine and direct rendering onto
+ * the backing engines (bypassing the load balancing proxy), the context must
+ * be defined to use a single timeline for all engines.
+ */
+struct i915_context_engines_load_balance {
+	struct i915_user_extension base;
+
+	__u16 engine_index;
+	__u16 mbz16; /* reserved for future use; must be zero */
+	__u32 flags; /* all undefined flags must be zero */
+
+	__u64 engines_mask; /* selection mask of engines[] */
+
+	__u64 mbz64[4]; /* reserved for future use; must be zero */
+};
+
+/*
+ * i915_context_engines_bond:
+ *
+ */
+struct i915_context_engines_bond {
+	struct i915_user_extension base;
+
+	__u16 engine_index;
+	__u16 mbz;
+
+	__u16 master_class;
+	__u16 master_instance;
+
+	__u64 sibling_mask;
+	__u64 flags; /* all undefined flags must be zero */
+};
+
+struct i915_context_param_engines {
+	__u64 extensions; /* linked chain of extension blocks, 0 terminates */
+#define I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE 0
+#define I915_CONTEXT_ENGINES_EXT_BOND 1
+
+	struct {
+		__u16 engine_class; /* see enum drm_i915_gem_engine_class */
+		__u16 engine_instance;
+	} class_instance[0];
+} __attribute__((packed));
+
+struct drm_i915_gem_context_create_ext_setparam {
+#define I915_CONTEXT_CREATE_EXT_SETPARAM 0
+	struct i915_user_extension base;
+	struct drm_i915_gem_context_param setparam;
+};
+
+struct drm_i915_gem_context_create_ext_clone {
+#define I915_CONTEXT_CREATE_EXT_CLONE 1
+	struct i915_user_extension base;
+	__u32 clone;
+	__u32 flags;
+#define I915_CONTEXT_CLONE_FLAGS	(1u << 0)
+#define I915_CONTEXT_CLONE_SCHED	(1u << 1)
+#define I915_CONTEXT_CLONE_SSEU		(1u << 2)
+#define I915_CONTEXT_CLONE_TIMELINE	(1u << 3)
+#define I915_CONTEXT_CLONE_VM		(1u << 4)
+#define I915_CONTEXT_CLONE_ENGINES	(1u << 5)
+#define I915_CONTEXT_CLONE_UNKNOWN -(I915_CONTEXT_CLONE_ENGINES << 1)
+	__u64 rsvd;
+};
+
+struct drm_i915_gem_context_destroy {
+	__u32 ctx_id;
+	__u32 pad;
+};
+
+/*
+ * DRM_I915_GEM_VM_CREATE -
+ *
+ * Create a new virtual memory address space (ppGTT) for use within a context
+ * on the same file. Extensions can be provided to configure exactly how the
+ * address space is setup upon creation.
+ *
+ * The id of new VM (bound to the fd) for use with I915_CONTEXT_PARAM_VM is
+ * returned.
+ *
+ * DRM_I915_GEM_VM_DESTROY -
+ *
+ * Destroys a previously created VM id.
+ */
+struct drm_i915_gem_vm_control {
+	__u64 extensions;
+	__u32 flags;
+	__u32 id;
+};
+
+struct drm_i915_reg_read {
+	/*
+	 * Register offset.
+	 * For 64bit wide registers where the upper 32bits don't immediately
+	 * follow the lower 32bits, the offset of the lower 32bits must
+	 * be specified
+	 */
+	__u64 offset;
+#define I915_REG_READ_8B_WA (1ul << 0)
+
+	__u64 val; /* Return value */
+};
+
+/* Known registers:
+ *
+ * Render engine timestamp - 0x2358 + 64bit - gen7+
+ * - Note this register returns an invalid value if using the default
+ *   single instruction 8byte read, in order to workaround that pass
+ *   flag I915_REG_READ_8B_WA in offset field.
+ *
+ */
+
+struct drm_i915_reset_stats {
+	__u32 ctx_id;
+	__u32 flags;
+
+	/* All resets since boot/module reload, for all contexts */
+	__u32 reset_count;
+
+	/* Number of batches lost when active in GPU, for this context */
+	__u32 batch_active;
+
+	/* Number of batches lost pending for execution, for this context */
+	__u32 batch_pending;
+
+	__u32 pad;
+};
+
+struct drm_i915_gem_userptr {
+	__u64 user_ptr;
+	__u64 user_size;
+	__u32 flags;
+#define I915_USERPTR_READ_ONLY 0x1
+#define I915_USERPTR_UNSYNCHRONIZED 0x80000000
+	/**
+	 * Returned handle for the object.
+	 *
+	 * Object handles are nonzero.
+	 */
+	__u32 handle;
+};
+
 enum drm_i915_oa_format {
 	I915_OA_FORMAT_A13 = 1,	    /* HSW only */
 	I915_OA_FORMAT_A29,	    /* HSW only */
@@ -1734,6 +1931,8 @@ struct drm_i915_perf_oa_config {
 struct drm_i915_query_item {
 	__u64 query_id;
 #define DRM_I915_QUERY_TOPOLOGY_INFO    1
+#define DRM_I915_QUERY_ENGINE_INFO	2
+/* Must be kept compact -- no holes and well documented */
 
 	/*
 	 * When set to zero by userspace, this is filled with the size of the
@@ -1831,6 +2030,50 @@ struct drm_i915_query_topology_info {
 	__u8 data[];
 };
 
+/**
+ * struct drm_i915_engine_info
+ *
+ * Describes one engine and it's capabilities as known to the driver.
+ */
+struct drm_i915_engine_info {
+	/** Engine class as in enum drm_i915_gem_engine_class. */
+	__u16 engine_class;
+
+	/** Engine instance number. */
+	__u16 engine_instance;
+
+	/** Reserved field. */
+	__u32 rsvd0;
+
+	/** Engine flags. */
+	__u64 flags;
+
+	/** Capabilities of this engine. */
+	__u64 capabilities;
+#define I915_VIDEO_CLASS_CAPABILITY_HEVC		(1 << 0)
+#define I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC	(1 << 1)
+
+	/** Reserved fields. */
+	__u64 rsvd1[4];
+};
+
+/**
+ * struct drm_i915_query_engine_info
+ *
+ * Engine info query enumerates all engines known to the driver by filling in
+ * an array of struct drm_i915_engine_info structures.
+ */
+struct drm_i915_query_engine_info {
+	/** Number of struct drm_i915_engine_info structs following. */
+	__u32 num_engines;
+
+	/** MBZ */
+	__u32 rsvd[3];
+
+	/** Marker for drm_i915_engine_info structures. */
+	struct drm_i915_engine_info engines[];
+};
+
 #if defined(__cplusplus)
 }
 #endif
-- 
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] 30+ messages in thread

* [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library
  2019-03-05 13:16 [igt-dev] [RFC PATCH v10 0/6] new engine discovery interface Andi Shyti
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 1/6] include/drm-uapi: import i915_drm.h header file Andi Shyti
@ 2019-03-05 13:16 ` Andi Shyti
  2019-03-05 13:24   ` Chris Wilson
  2019-03-07 12:05   ` Tvrtko Ursulin
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines Andi Shyti
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-05 13:16 UTC (permalink / raw)
  To: IGT dev; +Cc: Andi Shyti

The gem_engine_topology library is a set of functions that
interface with the query and getparam/setparam ioctls.

The library's three main access points are:

 - get_active_engines()
 - gem_set_context_get_engines()
 - igt_require_gem_engine_list()

The first two functions are similar, with the difference that the
'gem_set_context_get_engines()' sets the engine before returning
the engine list in a 'intel_execution_engine2' type array.
Another improtant difference is that the first function works
only with the getparam/setparam and query ioctls are implemented
and it return 'NULL' in the other case.

'gem_set_context_get_engines()' function, at the first call
generates the array of active engines (either physical or
virtual) called 'intel_active_engines2'.
If the driver cannot be queried, the 'intel_active_engines2'
array points to the exisiting 'intel_execution_engines2' which
has been previously defined.

The value of the 'intel_active_engines2' will be used in further
calls to check whether the above mentioned ioctls are implemented
without the need to call getparam().

The 'igt_require_gem_engine_list()' causes the test to fail in
case the required ioctls are not implemented.

Signed-off-by: Andi Shyti <andi.shyti@intel.com>
---
 lib/Makefile.sources           |   2 +
 lib/i915/gem_engine_topology.c | 199 +++++++++++++++++++++++++++++++++
 lib/i915/gem_engine_topology.h |  39 +++++++
 lib/igt_gt.c                   |   2 +-
 lib/igt_gt.h                   |   2 +-
 lib/meson.build                |   1 +
 6 files changed, 243 insertions(+), 2 deletions(-)
 create mode 100644 lib/i915/gem_engine_topology.c
 create mode 100644 lib/i915/gem_engine_topology.h

diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index cf2720981707..757bd7a17ebe 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -13,6 +13,8 @@ lib_source_list =	 	\
 	i915/gem_ring.c	\
 	i915/gem_mman.c	\
 	i915/gem_mman.h	\
+	i915/gem_engine_topology.c	\
+	i915/gem_engine_topology.h	\
 	i915_3d.h		\
 	i915_reg.h		\
 	i915_pciids.h		\
diff --git a/lib/i915/gem_engine_topology.c b/lib/i915/gem_engine_topology.c
new file mode 100644
index 000000000000..9376b4792441
--- /dev/null
+++ b/lib/i915/gem_engine_topology.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "drmtest.h"
+#include "igt_gt.h"
+#include "ioctl_wrappers.h"
+
+#include "i915/gem_engine_topology.h"
+
+#define SIZEOF_CTX_PARAM	offsetof(struct i915_context_param_engines, \
+					class_instance[I915_EXEC_RING_MASK + 1])
+#define SIZEOF_QUERY		offsetof(struct drm_i915_query_engine_info, \
+					engines[I915_EXEC_RING_MASK + 1])
+
+static struct intel_execution_engine2 *intel_active_engines2;
+
+int __gem_query(int fd, struct drm_i915_query *q)
+{
+	int err = 0;
+
+	if (igt_ioctl(fd, DRM_IOCTL_I915_QUERY, q))
+		err = -errno;
+
+	errno = 0;
+	return err;
+}
+
+void gem_query(int fd, struct drm_i915_query *q)
+{
+	igt_assert_eq(__gem_query(fd, q), 0);
+}
+
+static void query_engines(int fd,
+			  struct drm_i915_query_engine_info *query_engines)
+{
+	struct drm_i915_query_item item = { };
+	struct drm_i915_query query = { };
+
+	item.query_id = DRM_I915_QUERY_ENGINE_INFO;
+	query.items_ptr = to_user_pointer(&item);
+	query.num_items = 1;
+	item.length = SIZEOF_QUERY;
+
+	item.data_ptr = to_user_pointer(query_engines);
+
+	gem_query(fd, &query);
+}
+
+bool gem_has_engine_topology(void)
+{
+	return intel_active_engines2 != intel_execution_engines2;
+}
+
+static void set_ctx_param_engines(int fd, uint32_t ctx_id)
+{
+	struct i915_context_param_engines *ctx_engine;
+	struct drm_i915_gem_context_param ctx_param;
+	const struct intel_execution_engine2 *e2;
+	uint8_t buff[SIZEOF_CTX_PARAM] = { };
+	int i;
+
+	if (!gem_has_engine_topology())
+		return;
+
+	ctx_engine = (struct i915_context_param_engines *) buff;
+
+	ctx_param.ctx_id = ctx_id;
+	ctx_param.param = I915_CONTEXT_PARAM_ENGINES;
+
+	ctx_engine->extensions = 0;
+	for (i = 0, e2 = intel_active_engines2; e2->name; i++, e2++) {
+		ctx_engine->class_instance[i].engine_class = e2->class;
+		ctx_engine->class_instance[i].engine_instance = e2->instance;
+	}
+
+	ctx_param.size = offsetof(typeof(*ctx_engine), class_instance[i + 1]);
+	ctx_param.value = to_user_pointer(ctx_engine);
+
+	gem_context_set_param(fd, &ctx_param);
+}
+
+/*
+ * Initializes the list of engines.
+ *
+ * Returns:
+ *
+ *  - 0 in case of success and the get/set_param ioctls are implemented
+ *  - -ENODEV in case of success but I915_CONTEXT_PARAM_ENGINES is not
+ *    implemented in DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM ioctl.
+ */
+static int init_engine_list(int fd)
+{
+	const char *class_names[] = { "rcs", "bcs", "vcs", "vecs" };
+	struct drm_i915_query_engine_info *query_engine;
+	unsigned char query_buffer[SIZEOF_QUERY] = { };
+	struct drm_i915_gem_context_param ctx_param = {
+		.param = I915_CONTEXT_PARAM_ENGINES,
+	};
+	int i;
+
+	/* the list is already initialized */
+	if (intel_active_engines2)
+		return gem_has_engine_topology() ? 0 : -ENODEV;
+
+	/*
+	 * We check first whether the I915_CONTEXT_PARAM_ENGINES parameter is
+	 * supported by the running kernel. If not, __gem_context_get_param()
+	 * will return -EINVAL which, at this point, is not necessarily a
+	 * failure but it means that we need to fall beck to polling the engines
+	 * directly from intel_execution_engines2[].
+	 *
+	 * We will return -ENODEV with the meaning of missing interface
+	 */
+	if (__gem_context_get_param(fd, &ctx_param)) {
+		intel_active_engines2 = intel_execution_engines2;
+		return -ENODEV;
+	}
+
+	query_engine = (struct drm_i915_query_engine_info *) query_buffer;
+	query_engines(fd, query_engine);
+
+	igt_assert(query_engine->num_engines < I915_EXEC_RING_MASK + 1);
+
+	intel_active_engines2 = malloc((query_engine->num_engines + 1) *
+				       sizeof(*intel_active_engines2));
+	igt_assert(intel_active_engines2);
+
+	for (i = 0; i < query_engine->num_engines; i++) {
+		char *name;
+		int class = query_engine->engines[i].engine_class;
+		int instance = query_engine->engines[i].engine_instance;
+
+		intel_active_engines2[i].class = class;
+		intel_active_engines2[i].instance = instance;
+
+		/* if we don't recognise the class, then we mark it as "unk" */
+		if (class >= ARRAY_SIZE(class_names) || !class_names[class])
+			igt_assert(asprintf(&name, "unk-%d:%d",
+					    class, instance) > 0);
+		else
+			igt_assert(asprintf(&name, "%s%d",
+					    class_names[class], instance) > 0);
+
+		intel_active_engines2[i].name = name;
+	}
+
+	/* NULL value sentinel */
+	intel_active_engines2[i].name = NULL;
+
+	return 0;
+}
+
+struct intel_execution_engine2 *get_active_engines(int fd)
+{
+	if (init_engine_list(fd)) {
+		igt_info("using pre-allocated engine list\n");
+		return NULL;
+	}
+
+	return intel_active_engines2;
+}
+
+struct intel_execution_engine2 *gem_set_context_get_engines(int fd,
+							    uint32_t ctx_id)
+{
+	struct intel_execution_engine2 *active_engines = get_active_engines(fd);
+
+	if (!active_engines)
+		return intel_execution_engines2;
+
+	set_ctx_param_engines(fd, ctx_id);
+
+	return intel_active_engines2;
+}
+
+void igt_require_gem_engine_list(int fd)
+{
+	igt_require(!init_engine_list(fd));
+}
diff --git a/lib/i915/gem_engine_topology.h b/lib/i915/gem_engine_topology.h
new file mode 100644
index 000000000000..be5e81481dba
--- /dev/null
+++ b/lib/i915/gem_engine_topology.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef GEM_QUERY_H
+#define GEM_QUERY_H
+
+int __gem_query(int fd, struct drm_i915_query *q);
+void gem_query(int fd, struct drm_i915_query *q);
+
+bool gem_has_engine_topology(void);
+struct intel_execution_engine2 *get_active_engines(int fd);
+struct intel_execution_engine2 *gem_set_context_get_engines(int fd,
+							    uint32_t ctx_id);
+
+void igt_require_gem_engine_list(int fd);
+
+#define gem_get_engines() gem_context_get_engines(0, 0)
+
+#endif /* GEM_QUEY_H */
diff --git a/lib/igt_gt.c b/lib/igt_gt.c
index c98a7553b7fe..54c71e5e7186 100644
--- a/lib/igt_gt.c
+++ b/lib/igt_gt.c
@@ -577,7 +577,7 @@ bool gem_can_store_dword(int fd, unsigned int engine)
 	return true;
 }
 
-const struct intel_execution_engine2 intel_execution_engines2[] = {
+struct intel_execution_engine2 intel_execution_engines2[] = {
 	{ "rcs0", I915_ENGINE_CLASS_RENDER, 0 },
 	{ "bcs0", I915_ENGINE_CLASS_COPY, 0 },
 	{ "vcs0", I915_ENGINE_CLASS_VIDEO, 0 },
diff --git a/lib/igt_gt.h b/lib/igt_gt.h
index 54e95da98084..f4bd6c22a81a 100644
--- a/lib/igt_gt.h
+++ b/lib/igt_gt.h
@@ -91,7 +91,7 @@ bool gem_ring_has_physical_engine(int fd, unsigned int ring);
 
 bool gem_can_store_dword(int fd, unsigned int engine);
 
-extern const struct intel_execution_engine2 {
+extern struct intel_execution_engine2 {
 	const char *name;
 	int class;
 	int instance;
diff --git a/lib/meson.build b/lib/meson.build
index 0eb5585d72b9..3cc52f97c8bf 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -5,6 +5,7 @@ lib_sources = [
 	'i915/gem_submission.c',
 	'i915/gem_ring.c',
 	'i915/gem_mman.c',
+	'i915/gem_engine_topology.c',
 	'igt_color_encoding.c',
 	'igt_debugfs.c',
 	'igt_device.c',
-- 
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] 30+ messages in thread

* [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines
  2019-03-05 13:16 [igt-dev] [RFC PATCH v10 0/6] new engine discovery interface Andi Shyti
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 1/6] include/drm-uapi: import i915_drm.h header file Andi Shyti
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library Andi Shyti
@ 2019-03-05 13:16 ` Andi Shyti
  2019-03-05 13:36   ` Chris Wilson
                     ` (2 more replies)
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well Andi Shyti
                   ` (4 subsequent siblings)
  7 siblings, 3 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-05 13:16 UTC (permalink / raw)
  To: IGT dev; +Cc: Andi Shyti

'for_each_engine2()' defines a loop through the gpu engines.

It can work with both active and pre-defined engines.

In case we are looping through active engines (i.e. the running
kernel has the query and get/setparam ioctls), the
intel_active_engines2 points to an array that contains only the
list engines dynamically allocated after having interrogated the
driver.

While, if we are looping through pre-defined engines,
intel_active_engines2 points to the 'intel_execution_engines2'
array and works exactly as for_each_engine() but using the
new 'struct intel_execution_engine2' data type.

Signed-off-by: Andi Shyti <andi.shyti@intel.com>
---
 lib/igt_gt.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lib/igt_gt.h b/lib/igt_gt.h
index f4bd6c22a81a..f8bdaa62899f 100644
--- a/lib/igt_gt.h
+++ b/lib/igt_gt.h
@@ -30,6 +30,8 @@
 
 #include "i915_drm.h"
 
+#include "i915/gem_engine_topology.h"
+
 void igt_require_hang_ring(int fd, int ring);
 
 typedef struct igt_hang {
@@ -86,6 +88,12 @@ extern const struct intel_execution_engine {
 	     e__++) \
 		for_if (gem_ring_has_physical_engine(fd__, flags__ = e__->exec_id | e__->flags))
 
+#define for_each_engine2(fd, ctx) \
+		for (struct intel_execution_engine2 *e2__ = \
+		     gem_set_context_get_engines(fd, ctx); e2__->name; e2__++) \
+			for_if (gem_has_engine_topology() || \
+				gem_has_engine(fd, e2__->class, e2__->instance))
+
 bool gem_ring_is_physical_engine(int fd, unsigned int ring);
 bool gem_ring_has_physical_engine(int fd, unsigned int ring);
 
-- 
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] 30+ messages in thread

* [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well
  2019-03-05 13:16 [igt-dev] [RFC PATCH v10 0/6] new engine discovery interface Andi Shyti
                   ` (2 preceding siblings ...)
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines Andi Shyti
@ 2019-03-05 13:16 ` Andi Shyti
  2019-03-05 13:27   ` Chris Wilson
  2019-03-07 12:10   ` Tvrtko Ursulin
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 5/6] lib: move gem_context_has_engine from ioctl_wrappers to gem_context Andi Shyti
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-05 13:16 UTC (permalink / raw)
  To: IGT dev; +Cc: Andi Shyti

With the new engine query method engines are reachable through
an index and context they are combined with.

The 'gem_has_ring()' becomes 'gem_context_has_engine()' that
requires the index that the engine is mapped within the driver.

The previous 'gem_has_ring()' function becomes a wrapper to the new
'gem_context_has_engine()'.

Signed-off-by: Andi Shyti <andi.shyti@intel.com>
---
 lib/ioctl_wrappers.c | 4 +++-
 lib/ioctl_wrappers.h | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
index 39920f8707d2..a2597e282704 100644
--- a/lib/ioctl_wrappers.c
+++ b/lib/ioctl_wrappers.c
@@ -1252,7 +1252,7 @@ void igt_require_gem(int fd)
 	igt_require_f(err == 0, "Unresponsive i915/GEM device\n");
 }
 
-bool gem_has_ring(int fd, unsigned ring)
+bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx)
 {
 	struct drm_i915_gem_execbuffer2 execbuf;
 	struct drm_i915_gem_exec_object2 exec;
@@ -1268,6 +1268,8 @@ bool gem_has_ring(int fd, unsigned ring)
 	execbuf.buffers_ptr = to_user_pointer(&exec);
 	execbuf.buffer_count = 1;
 	execbuf.flags = ring;
+	execbuf.rsvd1 = ctx;
+
 	return __gem_execbuf(fd, &execbuf) == -ENOENT;
 }
 
diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
index f0be26080da6..446e973b7449 100644
--- a/lib/ioctl_wrappers.h
+++ b/lib/ioctl_wrappers.h
@@ -142,11 +142,13 @@ bool gem_has_exec_fence(int fd);
 
 /* check functions which auto-skip tests by calling igt_skip() */
 void gem_require_caching(int fd);
-bool gem_has_ring(int fd, unsigned ring);
+bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx);
 void gem_require_ring(int fd, unsigned ring);
 bool gem_has_mocs_registers(int fd);
 void gem_require_mocs_registers(int fd);
 
+#define gem_has_ring(fd, ring) gem_context_has_engine(fd, ring, 0)
+
 /* prime */
 struct local_dma_buf_sync {
 	uint64_t flags;
-- 
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] 30+ messages in thread

* [igt-dev] [RFC PATCH v10 5/6] lib: move gem_context_has_engine from ioctl_wrappers to gem_context
  2019-03-05 13:16 [igt-dev] [RFC PATCH v10 0/6] new engine discovery interface Andi Shyti
                   ` (3 preceding siblings ...)
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well Andi Shyti
@ 2019-03-05 13:16 ` Andi Shyti
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 6/6] tests: gem_exec_basic: add "exec-ctx" buffer execution demo test Andi Shyti
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-05 13:16 UTC (permalink / raw)
  To: IGT dev; +Cc: Andi Shyti

Function 'gem_has_ring()' has been renamed to
'gem_context_has_engine()' which acts more on an engine in
context domain. Move it to the gem_context library where it is
more appropriate.

Signed-off-by: Andi Shyti <andi.shyti@intel.com>
---
 lib/i915/gem_context.c | 21 +++++++++++++++++++++
 lib/i915/gem_context.h |  2 ++
 lib/ioctl_wrappers.c   | 21 ---------------------
 lib/ioctl_wrappers.h   |  1 -
 4 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/lib/i915/gem_context.c b/lib/i915/gem_context.c
index 16004685e920..b56cac9f46c9 100644
--- a/lib/i915/gem_context.c
+++ b/lib/i915/gem_context.c
@@ -275,3 +275,24 @@ void gem_context_set_priority(int fd, uint32_t ctx_id, int prio)
 {
 	igt_assert(__gem_context_set_priority(fd, ctx_id, prio) == 0);
 }
+
+bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx)
+{
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec;
+
+	/* silly ABI, the kernel thinks everyone who has BSD also has BSD2 */
+	if ((ring & ~(3<<13)) == I915_EXEC_BSD) {
+		if (ring & (3 << 13) && !gem_has_bsd2(fd))
+			return false;
+	}
+
+	memset(&exec, 0, sizeof(exec));
+	memset(&execbuf, 0, sizeof(execbuf));
+	execbuf.buffers_ptr = to_user_pointer(&exec);
+	execbuf.buffer_count = 1;
+	execbuf.flags = ring;
+	execbuf.rsvd1 = ctx;
+
+	return __gem_execbuf(fd, &execbuf) == -ENOENT;
+}
diff --git a/lib/i915/gem_context.h b/lib/i915/gem_context.h
index aef68dda6b26..1b7b0eefb344 100644
--- a/lib/i915/gem_context.h
+++ b/lib/i915/gem_context.h
@@ -45,4 +45,6 @@ int __gem_context_get_param(int fd, struct drm_i915_gem_context_param *p);
 int __gem_context_set_priority(int fd, uint32_t ctx, int prio);
 void gem_context_set_priority(int fd, uint32_t ctx, int prio);
 
+bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx);
+
 #endif /* GEM_CONTEXT_H */
diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
index a2597e282704..280fdd624529 100644
--- a/lib/ioctl_wrappers.c
+++ b/lib/ioctl_wrappers.c
@@ -1252,27 +1252,6 @@ void igt_require_gem(int fd)
 	igt_require_f(err == 0, "Unresponsive i915/GEM device\n");
 }
 
-bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx)
-{
-	struct drm_i915_gem_execbuffer2 execbuf;
-	struct drm_i915_gem_exec_object2 exec;
-
-	/* silly ABI, the kernel thinks everyone who has BSD also has BSD2 */
-	if ((ring & ~(3<<13)) == I915_EXEC_BSD) {
-		if (ring & (3 << 13) && !gem_has_bsd2(fd))
-			return false;
-	}
-
-	memset(&exec, 0, sizeof(exec));
-	memset(&execbuf, 0, sizeof(execbuf));
-	execbuf.buffers_ptr = to_user_pointer(&exec);
-	execbuf.buffer_count = 1;
-	execbuf.flags = ring;
-	execbuf.rsvd1 = ctx;
-
-	return __gem_execbuf(fd, &execbuf) == -ENOENT;
-}
-
 /**
  * gem_require_ring:
  * @fd: open i915 drm file descriptor
diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
index 446e973b7449..470e12f362d8 100644
--- a/lib/ioctl_wrappers.h
+++ b/lib/ioctl_wrappers.h
@@ -142,7 +142,6 @@ bool gem_has_exec_fence(int fd);
 
 /* check functions which auto-skip tests by calling igt_skip() */
 void gem_require_caching(int fd);
-bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx);
 void gem_require_ring(int fd, unsigned ring);
 bool gem_has_mocs_registers(int fd);
 void gem_require_mocs_registers(int 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] 30+ messages in thread

* [igt-dev] [RFC PATCH v10 6/6] tests: gem_exec_basic: add "exec-ctx" buffer execution demo test
  2019-03-05 13:16 [igt-dev] [RFC PATCH v10 0/6] new engine discovery interface Andi Shyti
                   ` (4 preceding siblings ...)
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 5/6] lib: move gem_context_has_engine from ioctl_wrappers to gem_context Andi Shyti
@ 2019-03-05 13:16 ` Andi Shyti
  2019-03-05 14:13 ` [igt-dev] ✓ Fi.CI.BAT: success for new engine discovery interface Patchwork
  2019-03-05 15:22 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  7 siblings, 0 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-05 13:16 UTC (permalink / raw)
  To: IGT dev; +Cc: Andi Shyti

The "exec-ctx" is a demo subtest inserted in the gem_exec_basic
test. The main goal is to reach the engines by using
the new uapi interfacing with igt_require_gem_engine_list().

The "exec-ctx" subtest simply gets the list of engines, binds
them to a context and executes a buffer. This is done through a
new "for_each_engine2" loop which iterates through the
engines.

Signed-off-by: Andi Shyti <andi.shyti@intel.com>
---
 tests/i915/gem_exec_basic.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/tests/i915/gem_exec_basic.c b/tests/i915/gem_exec_basic.c
index dcb83864b1c1..5d955179c2a5 100644
--- a/tests/i915/gem_exec_basic.c
+++ b/tests/i915/gem_exec_basic.c
@@ -135,6 +135,18 @@ igt_main
 			gtt(fd, e->exec_id | e->flags);
 	}
 
+	igt_subtest("exec-ctx") {
+		uint32_t ctx_id;
+		int index_map = 0;
+
+		ctx_id = gem_context_create(fd);
+		for_each_engine2(fd, ctx_id)
+			igt_assert(gem_context_has_engine(fd, ++index_map,
+							  ctx_id));
+
+		gem_context_destroy(fd, ctx_id);
+	}
+
 	igt_fixture {
 		igt_stop_hang_detector();
 		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] 30+ messages in thread

* Re: [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library Andi Shyti
@ 2019-03-05 13:24   ` Chris Wilson
  2019-03-07 13:00     ` Andi Shyti
  2019-03-07 12:05   ` Tvrtko Ursulin
  1 sibling, 1 reply; 30+ messages in thread
From: Chris Wilson @ 2019-03-05 13:24 UTC (permalink / raw)
  To: Andi Shyti, IGT dev; +Cc: Andi Shyti

Quoting Andi Shyti (2019-03-05 13:16:07)
> The gem_engine_topology library is a set of functions that
> interface with the query and getparam/setparam ioctls.
> 
> The library's three main access points are:
> 
>  - get_active_engines()
>  - gem_set_context_get_engines()
>  - igt_require_gem_engine_list()
> 
> The first two functions are similar, with the difference that the
> 'gem_set_context_get_engines()' sets the engine before returning
> the engine list in a 'intel_execution_engine2' type array.
> Another improtant difference is that the first function works
> only with the getparam/setparam and query ioctls are implemented
> and it return 'NULL' in the other case.
> 
> 'gem_set_context_get_engines()' function, at the first call
> generates the array of active engines (either physical or
> virtual) called 'intel_active_engines2'.
> If the driver cannot be queried, the 'intel_active_engines2'
> array points to the exisiting 'intel_execution_engines2' which
> has been previously defined.
> 
> The value of the 'intel_active_engines2' will be used in further
> calls to check whether the above mentioned ioctls are implemented
> without the need to call getparam().
> 
> The 'igt_require_gem_engine_list()' causes the test to fail in
> case the required ioctls are not implemented.
> 
> Signed-off-by: Andi Shyti <andi.shyti@intel.com>
> ---
>  lib/Makefile.sources           |   2 +
>  lib/i915/gem_engine_topology.c | 199 +++++++++++++++++++++++++++++++++
>  lib/i915/gem_engine_topology.h |  39 +++++++
>  lib/igt_gt.c                   |   2 +-
>  lib/igt_gt.h                   |   2 +-
>  lib/meson.build                |   1 +
>  6 files changed, 243 insertions(+), 2 deletions(-)
>  create mode 100644 lib/i915/gem_engine_topology.c
>  create mode 100644 lib/i915/gem_engine_topology.h
> 
> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> index cf2720981707..757bd7a17ebe 100644
> --- a/lib/Makefile.sources
> +++ b/lib/Makefile.sources
> @@ -13,6 +13,8 @@ lib_source_list =             \
>         i915/gem_ring.c \
>         i915/gem_mman.c \
>         i915/gem_mman.h \
> +       i915/gem_engine_topology.c      \
> +       i915/gem_engine_topology.h      \
>         i915_3d.h               \
>         i915_reg.h              \
>         i915_pciids.h           \
> diff --git a/lib/i915/gem_engine_topology.c b/lib/i915/gem_engine_topology.c
> new file mode 100644
> index 000000000000..9376b4792441
> --- /dev/null
> +++ b/lib/i915/gem_engine_topology.c
> @@ -0,0 +1,199 @@
> +/*
> + * Copyright © 2019 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include "drmtest.h"
> +#include "igt_gt.h"
> +#include "ioctl_wrappers.h"
> +
> +#include "i915/gem_engine_topology.h"
> +
> +#define SIZEOF_CTX_PARAM       offsetof(struct i915_context_param_engines, \
> +                                       class_instance[I915_EXEC_RING_MASK + 1])
> +#define SIZEOF_QUERY           offsetof(struct drm_i915_query_engine_info, \
> +                                       engines[I915_EXEC_RING_MASK + 1])
> +
> +static struct intel_execution_engine2 *intel_active_engines2;
> +
> +int __gem_query(int fd, struct drm_i915_query *q)
> +{
> +       int err = 0;
> +
> +       if (igt_ioctl(fd, DRM_IOCTL_I915_QUERY, q))
> +               err = -errno;
> +
> +       errno = 0;
> +       return err;
> +}
> +
> +void gem_query(int fd, struct drm_i915_query *q)
> +{
> +       igt_assert_eq(__gem_query(fd, q), 0);
> +}
> +
> +static void query_engines(int fd,
> +                         struct drm_i915_query_engine_info *query_engines)
> +{
> +       struct drm_i915_query_item item = { };
> +       struct drm_i915_query query = { };
> +
> +       item.query_id = DRM_I915_QUERY_ENGINE_INFO;
> +       query.items_ptr = to_user_pointer(&item);
> +       query.num_items = 1;
> +       item.length = SIZEOF_QUERY;
> +
> +       item.data_ptr = to_user_pointer(query_engines);
> +
> +       gem_query(fd, &query);
> +}
> +
> +bool gem_has_engine_topology(void)
> +{
> +       return intel_active_engines2 != intel_execution_engines2;
> +}
> +
> +static void set_ctx_param_engines(int fd, uint32_t ctx_id)
> +{
> +       struct i915_context_param_engines *ctx_engine;
> +       struct drm_i915_gem_context_param ctx_param;
> +       const struct intel_execution_engine2 *e2;
> +       uint8_t buff[SIZEOF_CTX_PARAM] = { };
> +       int i;
> +
> +       if (!gem_has_engine_topology())
> +               return;

Why would different fd have the same topology?
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well Andi Shyti
@ 2019-03-05 13:27   ` Chris Wilson
  2019-03-07 12:10   ` Tvrtko Ursulin
  1 sibling, 0 replies; 30+ messages in thread
From: Chris Wilson @ 2019-03-05 13:27 UTC (permalink / raw)
  To: Andi Shyti, IGT dev; +Cc: Andi Shyti

Quoting Andi Shyti (2019-03-05 13:16:09)
> With the new engine query method engines are reachable through
> an index and context they are combined with.
> 
> The 'gem_has_ring()' becomes 'gem_context_has_engine()' that
> requires the index that the engine is mapped within the driver.
> 
> The previous 'gem_has_ring()' function becomes a wrapper to the new
> 'gem_context_has_engine()'.
> 
> Signed-off-by: Andi Shyti <andi.shyti@intel.com>
> ---
>  lib/ioctl_wrappers.c | 4 +++-
>  lib/ioctl_wrappers.h | 4 +++-
>  2 files changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
> index 39920f8707d2..a2597e282704 100644
> --- a/lib/ioctl_wrappers.c
> +++ b/lib/ioctl_wrappers.c
> @@ -1252,7 +1252,7 @@ void igt_require_gem(int fd)
>         igt_require_f(err == 0, "Unresponsive i915/GEM device\n");
>  }
>  
> -bool gem_has_ring(int fd, unsigned ring)
> +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx)

gem_context_has_engine :=> ctx, engine

And reclaim from ioctl_wrappers.
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines Andi Shyti
@ 2019-03-05 13:36   ` Chris Wilson
  2019-03-07 12:07   ` Tvrtko Ursulin
  2019-03-08  7:09   ` Tvrtko Ursulin
  2 siblings, 0 replies; 30+ messages in thread
From: Chris Wilson @ 2019-03-05 13:36 UTC (permalink / raw)
  To: Andi Shyti, IGT dev; +Cc: Andi Shyti

Quoting Andi Shyti (2019-03-05 13:16:08)
> 'for_each_engine2()' defines a loop through the gpu engines.
> 
> It can work with both active and pre-defined engines.
> 
> In case we are looping through active engines (i.e. the running
> kernel has the query and get/setparam ioctls), the
> intel_active_engines2 points to an array that contains only the
> list engines dynamically allocated after having interrogated the
> driver.
> 
> While, if we are looping through pre-defined engines,
> intel_active_engines2 points to the 'intel_execution_engines2'
> array and works exactly as for_each_engine() but using the
> new 'struct intel_execution_engine2' data type.
> 
> Signed-off-by: Andi Shyti <andi.shyti@intel.com>
> ---
>  lib/igt_gt.h | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/lib/igt_gt.h b/lib/igt_gt.h
> index f4bd6c22a81a..f8bdaa62899f 100644
> --- a/lib/igt_gt.h
> +++ b/lib/igt_gt.h
> @@ -30,6 +30,8 @@
>  
>  #include "i915_drm.h"
>  
> +#include "i915/gem_engine_topology.h"
> +
>  void igt_require_hang_ring(int fd, int ring);
>  
>  typedef struct igt_hang {
> @@ -86,6 +88,12 @@ extern const struct intel_execution_engine {
>              e__++) \
>                 for_if (gem_ring_has_physical_engine(fd__, flags__ = e__->exec_id | e__->flags))
>  
> +#define for_each_engine2(fd, ctx) \
> +               for (struct intel_execution_engine2 *e2__ = \
> +                    gem_set_context_get_engines(fd, ctx); e2__->name; e2__++) \
> +                       for_if (gem_has_engine_topology() || \
> +                               gem_has_engine(fd, e2__->class, e2__->instance))
> +

for (struct intel_engine_iter it = intel_engine_iter(fd, ctx); \
     ((e__) = it.pos < it.nengine ? &it.engines[it.pos] : NULL); \
     intel_engine_iter_next(&it))

struct intel_engine_iter {
	int pos;
	int nengine;
	struct intel_execution_engine2 *engines;
};

Allocate the array everytime as it may change for different (fd, ctx).
In intel_engine_iter_next() remember to free that array when pos >=
nengine.

#define for_each_engine2(fd, ctx, e__)

Is that future-proof enough?
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* [igt-dev] ✓ Fi.CI.BAT: success for new engine discovery interface
  2019-03-05 13:16 [igt-dev] [RFC PATCH v10 0/6] new engine discovery interface Andi Shyti
                   ` (5 preceding siblings ...)
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 6/6] tests: gem_exec_basic: add "exec-ctx" buffer execution demo test Andi Shyti
@ 2019-03-05 14:13 ` Patchwork
  2019-03-05 15:22 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  7 siblings, 0 replies; 30+ messages in thread
From: Patchwork @ 2019-03-05 14:13 UTC (permalink / raw)
  To: Andi Shyti; +Cc: igt-dev

== Series Details ==

Series: new engine discovery interface
URL   : https://patchwork.freedesktop.org/series/57578/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_5703 -> IGTPW_2555
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/57578/revisions/1/mbox/

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

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

### IGT changes ###

#### Issues hit ####

  * igt@amdgpu/amd_basic@cs-compute:
    - fi-kbl-8809g:       NOTRUN -> FAIL [fdo#108094]

  * igt@amdgpu/amd_basic@cs-sdma:
    - fi-kbl-7560u:       NOTRUN -> SKIP [fdo#109271] +17

  * igt@i915_module_load@reload-with-fault-injection:
    - fi-kbl-7567u:       PASS -> DMESG-WARN [fdo#105602] / [fdo#108529] +1

  * igt@i915_pm_rpm@module-reload:
    - fi-kbl-7567u:       PASS -> DMESG-WARN [fdo#108529]

  * igt@i915_selftest@live_evict:
    - fi-bsw-kefka:       PASS -> DMESG-WARN [fdo#107709]

  * igt@kms_chamelium@common-hpd-after-suspend:
    - fi-kbl-7567u:       PASS -> DMESG-FAIL [fdo#105079]

  * igt@kms_pipe_crc_basic@nonblocking-crc-pipe-a-frame-sequence:
    - fi-byt-clapper:     PASS -> FAIL [fdo#103191] / [fdo#107362]

  * igt@kms_pipe_crc_basic@nonblocking-crc-pipe-c:
    - fi-kbl-7567u:       PASS -> SKIP [fdo#109271] +33

  * igt@kms_psr@cursor_plane_move:
    - fi-skl-6260u:       NOTRUN -> SKIP [fdo#109271] +37

  * igt@runner@aborted:
    - fi-bsw-kefka:       NOTRUN -> FAIL [fdo#107709]

  
#### Possible fixes ####

  * igt@amdgpu/amd_basic@userptr:
    - fi-kbl-8809g:       DMESG-WARN [fdo#108965] -> PASS

  * igt@i915_module_load@reload-with-fault-injection:
    - fi-kbl-7560u:       INCOMPLETE [fdo#109831] -> PASS

  * igt@i915_pm_rpm@basic-pci-d3-state:
    - fi-byt-j1900:       SKIP [fdo#109271] -> PASS

  * igt@i915_pm_rpm@basic-rte:
    - fi-byt-j1900:       FAIL [fdo#108800] -> PASS

  * igt@i915_pm_rpm@module-reload:
    - fi-skl-6770hq:      FAIL [fdo#108511] -> PASS

  * igt@kms_busy@basic-flip-c:
    - fi-skl-6770hq:      SKIP [fdo#109271] / [fdo#109278] -> PASS +2

  * igt@kms_flip@basic-flip-vs-dpms:
    - fi-skl-6770hq:      SKIP [fdo#109271] -> PASS +33

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
    - fi-byt-clapper:     FAIL [fdo#103191] / [fdo#107362] -> PASS

  
  [fdo#103191]: https://bugs.freedesktop.org/show_bug.cgi?id=103191
  [fdo#105079]: https://bugs.freedesktop.org/show_bug.cgi?id=105079
  [fdo#105602]: https://bugs.freedesktop.org/show_bug.cgi?id=105602
  [fdo#107362]: https://bugs.freedesktop.org/show_bug.cgi?id=107362
  [fdo#107709]: https://bugs.freedesktop.org/show_bug.cgi?id=107709
  [fdo#108094]: https://bugs.freedesktop.org/show_bug.cgi?id=108094
  [fdo#108511]: https://bugs.freedesktop.org/show_bug.cgi?id=108511
  [fdo#108529]: https://bugs.freedesktop.org/show_bug.cgi?id=108529
  [fdo#108800]: https://bugs.freedesktop.org/show_bug.cgi?id=108800
  [fdo#108965]: https://bugs.freedesktop.org/show_bug.cgi?id=108965
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109831]: https://bugs.freedesktop.org/show_bug.cgi?id=109831


Participating hosts (46 -> 41)
------------------------------

  Additional (1): fi-skl-6260u 
  Missing    (6): fi-ilk-m540 fi-hsw-4200u fi-byt-squawks fi-bsw-cyan fi-ctg-p8600 fi-bdw-samus 


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

    * IGT: IGT_4870 -> IGTPW_2555

  CI_DRM_5703: 453da75010eb2a0806e75490b86d24beb6fa76a7 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2555: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2555/
  IGT_4870: ed944b45563c694dc6373bc48dc83b8ba7edb19f @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools



== Testlist changes ==

+igt@gem_exec_basic@exec-ctx

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2555/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* [igt-dev] ✓ Fi.CI.IGT: success for new engine discovery interface
  2019-03-05 13:16 [igt-dev] [RFC PATCH v10 0/6] new engine discovery interface Andi Shyti
                   ` (6 preceding siblings ...)
  2019-03-05 14:13 ` [igt-dev] ✓ Fi.CI.BAT: success for new engine discovery interface Patchwork
@ 2019-03-05 15:22 ` Patchwork
  7 siblings, 0 replies; 30+ messages in thread
From: Patchwork @ 2019-03-05 15:22 UTC (permalink / raw)
  To: Andi Shyti; +Cc: igt-dev

== Series Details ==

Series: new engine discovery interface
URL   : https://patchwork.freedesktop.org/series/57578/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_5703_full -> IGTPW_2555_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/57578/revisions/1/mbox/

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

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

### IGT changes ###

#### Possible regressions ####

  * {igt@gem_exec_basic@exec-ctx} (NEW):
    - shard-kbl:          NOTRUN -> FAIL

  
New tests
---------

  New tests have been introduced between CI_DRM_5703_full and IGTPW_2555_full:

### New IGT tests (1) ###

  * igt@gem_exec_basic@exec-ctx:
    - Statuses : 1 fail(s) 4 pass(s)
    - Exec time: [0.0, 0.05] s

  

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

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

### IGT changes ###

#### Issues hit ####

  * igt@kms_atomic_transition@3x-modeset-transitions:
    - shard-kbl:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +2

  * igt@kms_atomic_transition@5x-modeset-transitions-fencing:
    - shard-apl:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +1

  * igt@kms_atomic_transition@plane-all-modeset-transition:
    - shard-apl:          PASS -> INCOMPLETE [fdo#103927]

  * igt@kms_busy@extended-modeset-hang-newfb-with-reset-render-b:
    - shard-kbl:          PASS -> DMESG-WARN [fdo#107956] +1
    - shard-apl:          NOTRUN -> DMESG-WARN [fdo#107956] +1
    - shard-hsw:          PASS -> DMESG-WARN [fdo#107956]

  * igt@kms_color@pipe-b-ctm-max:
    - shard-apl:          PASS -> FAIL [fdo#108147]
    - shard-kbl:          PASS -> FAIL [fdo#108147]

  * igt@kms_cursor_crc@cursor-128x128-suspend:
    - shard-apl:          PASS -> FAIL [fdo#103191] / [fdo#103232]

  * igt@kms_cursor_crc@cursor-64x21-onscreen:
    - shard-apl:          PASS -> FAIL [fdo#103232] +1

  * igt@kms_cursor_crc@cursor-64x64-random:
    - shard-kbl:          PASS -> FAIL [fdo#103232] +1

  * igt@kms_cursor_crc@cursor-64x64-suspend:
    - shard-kbl:          PASS -> FAIL [fdo#103191] / [fdo#103232]

  * igt@kms_cursor_crc@cursor-alpha-opaque:
    - shard-apl:          PASS -> FAIL [fdo#109350]

  * igt@kms_flip@2x-flip-vs-expired-vblank-interruptible:
    - shard-glk:          PASS -> FAIL [fdo#105363]

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-cpu:
    - shard-apl:          PASS -> FAIL [fdo#103167] +1

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-gtt:
    - shard-kbl:          PASS -> FAIL [fdo#103167]

  * igt@kms_frontbuffer_tracking@fbc-1p-rte:
    - shard-glk:          PASS -> FAIL [fdo#103167] / [fdo#105682]
    - shard-kbl:          PASS -> FAIL [fdo#103167] / [fdo#105682]

  * igt@kms_frontbuffer_tracking@fbc-2p-primscrn-cur-indfb-draw-mmap-wc:
    - shard-glk:          PASS -> FAIL [fdo#103167]

  * igt@kms_frontbuffer_tracking@fbcpsr-indfb-scaledprimary:
    - shard-apl:          NOTRUN -> SKIP [fdo#109271] +13

  * igt@kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-onoff:
    - shard-snb:          NOTRUN -> SKIP [fdo#109271] +106

  * igt@kms_frontbuffer_tracking@psr-1p-primscrn-indfb-plflip-blt:
    - shard-kbl:          NOTRUN -> SKIP [fdo#109271] +25

  * igt@kms_frontbuffer_tracking@psr-2p-primscrn-spr-indfb-draw-mmap-cpu:
    - shard-glk:          NOTRUN -> SKIP [fdo#109271] +23

  * igt@kms_plane@pixel-format-pipe-b-planes:
    - shard-kbl:          PASS -> FAIL [fdo#103166] +2

  * igt@kms_plane_multiple@atomic-pipe-a-tiling-y:
    - shard-glk:          PASS -> FAIL [fdo#103166] +5

  * igt@kms_plane_multiple@atomic-pipe-c-tiling-yf:
    - shard-apl:          PASS -> FAIL [fdo#103166] +6

  * igt@kms_rotation_crc@multiplane-rotation:
    - shard-kbl:          PASS -> FAIL [fdo#109016]

  * igt@kms_setmode@basic:
    - shard-hsw:          PASS -> FAIL [fdo#99912]
    - shard-kbl:          PASS -> FAIL [fdo#99912]

  * igt@kms_vblank@pipe-c-ts-continuation-dpms-rpm:
    - shard-kbl:          PASS -> FAIL [fdo#104894]

  * igt@kms_vblank@pipe-c-ts-continuation-modeset:
    - shard-snb:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +10

  * igt@kms_vblank@pipe-c-ts-continuation-suspend:
    - shard-apl:          PASS -> FAIL [fdo#104894] +2

  
#### Possible fixes ####

  * igt@gem_ctx_isolation@vecs0-s3:
    - shard-kbl:          INCOMPLETE [fdo#103665] -> PASS

  * igt@kms_atomic_transition@1x-modeset-transitions-nonblocking:
    - shard-apl:          FAIL [fdo#109660] -> PASS

  * igt@kms_busy@extended-modeset-hang-newfb-render-b:
    - shard-hsw:          DMESG-WARN [fdo#107956] -> PASS +2
    - shard-kbl:          DMESG-WARN [fdo#107956] -> PASS +2
    - shard-snb:          DMESG-WARN [fdo#107956] -> PASS +1

  * igt@kms_ccs@pipe-a-crc-sprite-planes-basic:
    - shard-glk:          FAIL [fdo#108145] -> PASS

  * igt@kms_color@pipe-a-degamma:
    - shard-apl:          FAIL [fdo#104782] / [fdo#108145] -> PASS

  * igt@kms_color@pipe-c-ctm-max:
    - shard-kbl:          FAIL [fdo#108147] -> PASS
    - shard-apl:          FAIL [fdo#108147] -> PASS

  * igt@kms_cursor_crc@cursor-128x42-onscreen:
    - shard-apl:          FAIL [fdo#103232] -> PASS +4

  * igt@kms_cursor_crc@cursor-256x256-suspend:
    - shard-kbl:          FAIL [fdo#103191] / [fdo#103232] -> PASS
    - shard-hsw:          INCOMPLETE [fdo#103540] -> PASS

  * igt@kms_cursor_crc@cursor-256x85-sliding:
    - shard-kbl:          FAIL [fdo#103232] -> PASS +1

  * igt@kms_draw_crc@draw-method-xrgb8888-render-xtiled:
    - shard-glk:          FAIL [fdo#107791] -> PASS

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-draw-pwrite:
    - shard-apl:          FAIL [fdo#103167] -> PASS +2

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-move:
    - shard-glk:          FAIL [fdo#103167] -> PASS +10

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-onoff:
    - shard-kbl:          FAIL [fdo#103167] -> PASS +1

  * igt@kms_pipe_crc_basic@read-crc-pipe-b-frame-sequence:
    - shard-kbl:          DMESG-WARN [fdo#103558] / [fdo#105602] -> PASS +7

  * igt@kms_plane@plane-position-covered-pipe-a-planes:
    - shard-apl:          FAIL [fdo#103166] -> PASS +2

  * igt@kms_plane_multiple@atomic-pipe-b-tiling-none:
    - shard-glk:          FAIL [fdo#103166] -> PASS +3

  * igt@kms_rotation_crc@multiplane-rotation-cropping-top:
    - shard-kbl:          FAIL [fdo#109016] -> PASS

  * igt@kms_vblank@pipe-a-ts-continuation-suspend:
    - shard-kbl:          FAIL [fdo#104894] -> PASS
    - shard-apl:          FAIL [fdo#104894] -> PASS +1

  * igt@perf_pmu@rc6:
    - shard-kbl:          SKIP [fdo#109271] -> PASS

  
#### Warnings ####

  * igt@kms_flip@2x-flip-vs-expired-vblank:
    - shard-apl:          INCOMPLETE [fdo#103927] -> SKIP [fdo#109271]

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

  [fdo#103166]: https://bugs.freedesktop.org/show_bug.cgi?id=103166
  [fdo#103167]: https://bugs.freedesktop.org/show_bug.cgi?id=103167
  [fdo#103191]: https://bugs.freedesktop.org/show_bug.cgi?id=103191
  [fdo#103232]: https://bugs.freedesktop.org/show_bug.cgi?id=103232
  [fdo#103540]: https://bugs.freedesktop.org/show_bug.cgi?id=103540
  [fdo#103558]: https://bugs.freedesktop.org/show_bug.cgi?id=103558
  [fdo#103665]: https://bugs.freedesktop.org/show_bug.cgi?id=103665
  [fdo#103927]: https://bugs.freedesktop.org/show_bug.cgi?id=103927
  [fdo#104782]: https://bugs.freedesktop.org/show_bug.cgi?id=104782
  [fdo#104894]: https://bugs.freedesktop.org/show_bug.cgi?id=104894
  [fdo#105363]: https://bugs.freedesktop.org/show_bug.cgi?id=105363
  [fdo#105602]: https://bugs.freedesktop.org/show_bug.cgi?id=105602
  [fdo#105682]: https://bugs.freedesktop.org/show_bug.cgi?id=105682
  [fdo#107791]: https://bugs.freedesktop.org/show_bug.cgi?id=107791
  [fdo#107956]: https://bugs.freedesktop.org/show_bug.cgi?id=107956
  [fdo#108145]: https://bugs.freedesktop.org/show_bug.cgi?id=108145
  [fdo#108147]: https://bugs.freedesktop.org/show_bug.cgi?id=108147
  [fdo#109016]: https://bugs.freedesktop.org/show_bug.cgi?id=109016
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109350]: https://bugs.freedesktop.org/show_bug.cgi?id=109350
  [fdo#109660]: https://bugs.freedesktop.org/show_bug.cgi?id=109660
  [fdo#99912]: https://bugs.freedesktop.org/show_bug.cgi?id=99912


Participating hosts (6 -> 5)
------------------------------

  Missing    (1): shard-skl 


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

    * IGT: IGT_4870 -> IGTPW_2555
    * Piglit: piglit_4509 -> None

  CI_DRM_5703: 453da75010eb2a0806e75490b86d24beb6fa76a7 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2555: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2555/
  IGT_4870: ed944b45563c694dc6373bc48dc83b8ba7edb19f @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2555/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library Andi Shyti
  2019-03-05 13:24   ` Chris Wilson
@ 2019-03-07 12:05   ` Tvrtko Ursulin
  2019-03-07 13:42     ` Andi Shyti
  1 sibling, 1 reply; 30+ messages in thread
From: Tvrtko Ursulin @ 2019-03-07 12:05 UTC (permalink / raw)
  To: Andi Shyti, IGT dev; +Cc: Andi Shyti


On 05/03/2019 13:16, Andi Shyti wrote:
> The gem_engine_topology library is a set of functions that
> interface with the query and getparam/setparam ioctls.
> 
> The library's three main access points are:
> 
>   - get_active_engines()
>   - gem_set_context_get_engines()
>   - igt_require_gem_engine_list()
> 
> The first two functions are similar, with the difference that the
> 'gem_set_context_get_engines()' sets the engine before returning
> the engine list in a 'intel_execution_engine2' type array.
> Another improtant difference is that the first function works
> only with the getparam/setparam and query ioctls are implemented
> and it return 'NULL' in the other case.
> 
> 'gem_set_context_get_engines()' function, at the first call
> generates the array of active engines (either physical or
> virtual) called 'intel_active_engines2'.
> If the driver cannot be queried, the 'intel_active_engines2'
> array points to the exisiting 'intel_execution_engines2' which
> has been previously defined.
> 
> The value of the 'intel_active_engines2' will be used in further
> calls to check whether the above mentioned ioctls are implemented
> without the need to call getparam().
> 
> The 'igt_require_gem_engine_list()' causes the test to fail in
> case the required ioctls are not implemented.
> 
> Signed-off-by: Andi Shyti <andi.shyti@intel.com>
> ---
>   lib/Makefile.sources           |   2 +
>   lib/i915/gem_engine_topology.c | 199 +++++++++++++++++++++++++++++++++
>   lib/i915/gem_engine_topology.h |  39 +++++++
>   lib/igt_gt.c                   |   2 +-
>   lib/igt_gt.h                   |   2 +-
>   lib/meson.build                |   1 +
>   6 files changed, 243 insertions(+), 2 deletions(-)
>   create mode 100644 lib/i915/gem_engine_topology.c
>   create mode 100644 lib/i915/gem_engine_topology.h
> 
> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> index cf2720981707..757bd7a17ebe 100644
> --- a/lib/Makefile.sources
> +++ b/lib/Makefile.sources
> @@ -13,6 +13,8 @@ lib_source_list =	 	\
>   	i915/gem_ring.c	\
>   	i915/gem_mman.c	\
>   	i915/gem_mman.h	\
> +	i915/gem_engine_topology.c	\
> +	i915/gem_engine_topology.h	\
>   	i915_3d.h		\
>   	i915_reg.h		\
>   	i915_pciids.h		\
> diff --git a/lib/i915/gem_engine_topology.c b/lib/i915/gem_engine_topology.c
> new file mode 100644
> index 000000000000..9376b4792441
> --- /dev/null
> +++ b/lib/i915/gem_engine_topology.c
> @@ -0,0 +1,199 @@
> +/*
> + * Copyright © 2019 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include "drmtest.h"
> +#include "igt_gt.h"
> +#include "ioctl_wrappers.h"
> +
> +#include "i915/gem_engine_topology.h"
> +
> +#define SIZEOF_CTX_PARAM	offsetof(struct i915_context_param_engines, \
> +					class_instance[I915_EXEC_RING_MASK + 1])
> +#define SIZEOF_QUERY		offsetof(struct drm_i915_query_engine_info, \
> +					engines[I915_EXEC_RING_MASK + 1])

There is no relationship between I915_EXEC_RING_MASK and the number of 
engines we can query. I'll suggest how I think it should work a bit later.

> +
> +static struct intel_execution_engine2 *intel_active_engines2;
> +
> +int __gem_query(int fd, struct drm_i915_query *q)
> +{
> +	int err = 0;
> +
> +	if (igt_ioctl(fd, DRM_IOCTL_I915_QUERY, q))
> +		err = -errno;
> +
> +	errno = 0;
> +	return err;
> +}
> +
> +void gem_query(int fd, struct drm_i915_query *q)
> +{
> +	igt_assert_eq(__gem_query(fd, q), 0);
> +}

I would keep these two static if there are no external callers for now.

> +
> +static void query_engines(int fd,
> +			  struct drm_i915_query_engine_info *query_engines)
> +{
> +	struct drm_i915_query_item item = { };
> +	struct drm_i915_query query = { };
> +
> +	item.query_id = DRM_I915_QUERY_ENGINE_INFO;
> +	query.items_ptr = to_user_pointer(&item);
> +	query.num_items = 1;
> +	item.length = SIZEOF_QUERY;

I think making this function take buffer size and return the queried 
size would be simplest.

> +
> +	item.data_ptr = to_user_pointer(query_engines);
> +
> +	gem_query(fd, &query);
> +}
> +
> +bool gem_has_engine_topology(void)
> +{
> +	return intel_active_engines2 != intel_execution_engines2;

A problem for the exported API if init_engine_list hasn't been called 
yet? Maybe:

	if (!intel_active_engines2)
		init_engine_list(fd);

	return intel_active_engines2 != intel_execution_engines2;

?

> +}
> +
> +static void set_ctx_param_engines(int fd, uint32_t ctx_id)
> +{
> +	struct i915_context_param_engines *ctx_engine;
> +	struct drm_i915_gem_context_param ctx_param;
> +	const struct intel_execution_engine2 *e2;
> +	uint8_t buff[SIZEOF_CTX_PARAM] = { };
> +	int i;
> +
> +	if (!gem_has_engine_topology())
> +		return;

AFAICS this can be assert here.

> +
> +	ctx_engine = (struct i915_context_param_engines *) buff;
> +
> +	ctx_param.ctx_id = ctx_id;
> +	ctx_param.param = I915_CONTEXT_PARAM_ENGINES;
> +
> +	ctx_engine->extensions = 0;
> +	for (i = 0, e2 = intel_active_engines2; e2->name; i++, e2++) {

Here I think is the place where we check that the total number of 
engines does not exceed the engine map execbuf index.

	igt_require(i <= I915_EXEC_RING_MASK);

?

> +		ctx_engine->class_instance[i].engine_class = e2->class;
> +		ctx_engine->class_instance[i].engine_instance = e2->instance;
> +	}
> +
> +	ctx_param.size = offsetof(typeof(*ctx_engine), class_instance[i + 1]);
> +	ctx_param.value = to_user_pointer(ctx_engine);
> +
> +	gem_context_set_param(fd, &ctx_param);
> +}
> +
> +/*
> + * Initializes the list of engines.
> + *
> + * Returns:
> + *
> + *  - 0 in case of success and the get/set_param ioctls are implemented
> + *  - -ENODEV in case of success but I915_CONTEXT_PARAM_ENGINES is not
> + *    implemented in DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM ioctl.
> + */
> +static int init_engine_list(int fd)
> +{
> +	const char *class_names[] = { "rcs", "bcs", "vcs", "vecs" };
> +	struct drm_i915_query_engine_info *query_engine;
> +	unsigned char query_buffer[SIZEOF_QUERY] = { };
> +	struct drm_i915_gem_context_param ctx_param = {
> +		.param = I915_CONTEXT_PARAM_ENGINES,
> +	};
> +	int i;
> +
> +	/* the list is already initialized */
> +	if (intel_active_engines2)
> +		return gem_has_engine_topology() ? 0 : -ENODEV;
> +
> +	/*
> +	 * We check first whether the I915_CONTEXT_PARAM_ENGINES parameter is
> +	 * supported by the running kernel. If not, __gem_context_get_param()
> +	 * will return -EINVAL which, at this point, is not necessarily a
> +	 * failure but it means that we need to fall beck to polling the engines
> +	 * directly from intel_execution_engines2[].
> +	 *
> +	 * We will return -ENODEV with the meaning of missing interface
> +	 */
> +	if (__gem_context_get_param(fd, &ctx_param)) {
> +		intel_active_engines2 = intel_execution_engines2;
> +		return -ENODEV;
> +	}
> +
> +	query_engine = (struct drm_i915_query_engine_info *) query_buffer;
> +	query_engines(fd, query_engine);

Do a two stage query here - first ask for required buffer size, then 
allocate it and query:

	size = query_engines(fd, NULL, 0);
	query_engine = malloc(size);
	query_engines(fd, query_engine, size);

> +
> +	igt_assert(query_engine->num_engines < I915_EXEC_RING_MASK + 1);

Remove this since we don't need to limit the size of the array during 
the query. It is only the engine map that has the limitation.

> +
> +	intel_active_engines2 = malloc((query_engine->num_engines + 1) *
> +				       sizeof(*intel_active_engines2));
> +	igt_assert(intel_active_engines2);
> +
> +	for (i = 0; i < query_engine->num_engines; i++) {
> +		char *name;
> +		int class = query_engine->engines[i].engine_class;
> +		int instance = query_engine->engines[i].engine_instance;

Could use __u16 to match uapi.

> +
> +		intel_active_engines2[i].class = class;
> +		intel_active_engines2[i].instance = instance;
> +
> +		/* if we don't recognise the class, then we mark it as "unk" */
> +		if (class >= ARRAY_SIZE(class_names) || !class_names[class])

Second condition seems to be not needed at the moment.

> +			igt_assert(asprintf(&name, "unk-%d:%d",
> +					    class, instance) > 0);
> +		else
> +			igt_assert(asprintf(&name, "%s%d",
> +					    class_names[class], instance) > 0);
> +
> +		intel_active_engines2[i].name = name;
> +	}
> +
> +	/* NULL value sentinel */
> +	intel_active_engines2[i].name = NULL;
> +
> +	return 0;
> +}
> +
> +struct intel_execution_engine2 *get_active_engines(int fd)

Unexport this one?

> +{
> +	if (init_engine_list(fd)) {
> +		igt_info("using pre-allocated engine list\n");
> +		return NULL;
> +	}
> +
> +	return intel_active_engines2;
> +}
> +
> +struct intel_execution_engine2 *gem_set_context_get_engines(int fd,
> +							    uint32_t ctx_id)

I find the name of this function really confusing (set get what?). Can I 
suggest __gem_prepare_context_engines or something like that?

> +{
> +	struct intel_execution_engine2 *active_engines = get_active_engines(fd);
> +
> +	if (!active_engines)
> +		return intel_execution_engines2;

So without engine discovery the function will not configure the engine 
map. How will the code inside for_each_engine2 be able to work then?

I guess it's okay since we don't expect to see a kernel with ctx engine 
map support and no engine discovery but it feels a bit unnatural.

But I think it effectively means you should have 
igt_require_gem_engine_list in here since it is otherwise not usable 
from the for_each_engine2 iterator.

> +
> +	set_ctx_param_engines(fd, ctx_id);

You need to handle the use case where the context already has a map 
configured instead of overriding it. Should be easy.

> +
> +	return intel_active_engines2;
> +}
> +
> +void igt_require_gem_engine_list(int fd)
> +{
> +	igt_require(!init_engine_list(fd));
> +}
> diff --git a/lib/i915/gem_engine_topology.h b/lib/i915/gem_engine_topology.h
> new file mode 100644
> index 000000000000..be5e81481dba
> --- /dev/null
> +++ b/lib/i915/gem_engine_topology.h
> @@ -0,0 +1,39 @@
> +/*
> + * Copyright © 2019 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#ifndef GEM_QUERY_H
> +#define GEM_QUERY_H

GEM_ENGINE_TOPOLOGY_H

> +
> +int __gem_query(int fd, struct drm_i915_query *q);
> +void gem_query(int fd, struct drm_i915_query *q);
> +
> +bool gem_has_engine_topology(void);
> +struct intel_execution_engine2 *get_active_engines(int fd);
> +struct intel_execution_engine2 *gem_set_context_get_engines(int fd,
> +							    uint32_t ctx_id);
> +
> +void igt_require_gem_engine_list(int fd);
> +
> +#define gem_get_engines() gem_context_get_engines(0, 0)
> +
> +#endif /* GEM_QUEY_H */
> diff --git a/lib/igt_gt.c b/lib/igt_gt.c
> index c98a7553b7fe..54c71e5e7186 100644
> --- a/lib/igt_gt.c
> +++ b/lib/igt_gt.c
> @@ -577,7 +577,7 @@ bool gem_can_store_dword(int fd, unsigned int engine)
>   	return true;
>   }
>   
> -const struct intel_execution_engine2 intel_execution_engines2[] = {
> +struct intel_execution_engine2 intel_execution_engines2[] = {

This one can't stay const?

>   	{ "rcs0", I915_ENGINE_CLASS_RENDER, 0 },
>   	{ "bcs0", I915_ENGINE_CLASS_COPY, 0 },
>   	{ "vcs0", I915_ENGINE_CLASS_VIDEO, 0 },
> diff --git a/lib/igt_gt.h b/lib/igt_gt.h
> index 54e95da98084..f4bd6c22a81a 100644
> --- a/lib/igt_gt.h
> +++ b/lib/igt_gt.h
> @@ -91,7 +91,7 @@ bool gem_ring_has_physical_engine(int fd, unsigned int ring);
>   
>   bool gem_can_store_dword(int fd, unsigned int engine);
>   
> -extern const struct intel_execution_engine2 {
> +extern struct intel_execution_engine2 {
>   	const char *name;
>   	int class;
>   	int instance;
> diff --git a/lib/meson.build b/lib/meson.build
> index 0eb5585d72b9..3cc52f97c8bf 100644
> --- a/lib/meson.build
> +++ b/lib/meson.build
> @@ -5,6 +5,7 @@ lib_sources = [
>   	'i915/gem_submission.c',
>   	'i915/gem_ring.c',
>   	'i915/gem_mman.c',
> +	'i915/gem_engine_topology.c',
>   	'igt_color_encoding.c',
>   	'igt_debugfs.c',
>   	'igt_device.c',
> 

Regards,

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

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

* Re: [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines Andi Shyti
  2019-03-05 13:36   ` Chris Wilson
@ 2019-03-07 12:07   ` Tvrtko Ursulin
  2019-03-07 12:27     ` Tvrtko Ursulin
  2019-03-08  7:09   ` Tvrtko Ursulin
  2 siblings, 1 reply; 30+ messages in thread
From: Tvrtko Ursulin @ 2019-03-07 12:07 UTC (permalink / raw)
  To: Andi Shyti, IGT dev; +Cc: Andi Shyti


On 05/03/2019 13:16, Andi Shyti wrote:
> 'for_each_engine2()' defines a loop through the gpu engines.
> 
> It can work with both active and pre-defined engines.
> 
> In case we are looping through active engines (i.e. the running
> kernel has the query and get/setparam ioctls), the
> intel_active_engines2 points to an array that contains only the
> list engines dynamically allocated after having interrogated the
> driver.
> 
> While, if we are looping through pre-defined engines,
> intel_active_engines2 points to the 'intel_execution_engines2'
> array and works exactly as for_each_engine() but using the
> new 'struct intel_execution_engine2' data type.
> 
> Signed-off-by: Andi Shyti <andi.shyti@intel.com>
> ---
>   lib/igt_gt.h | 8 ++++++++
>   1 file changed, 8 insertions(+)
> 
> diff --git a/lib/igt_gt.h b/lib/igt_gt.h
> index f4bd6c22a81a..f8bdaa62899f 100644
> --- a/lib/igt_gt.h
> +++ b/lib/igt_gt.h
> @@ -30,6 +30,8 @@
>   
>   #include "i915_drm.h"
>   
> +#include "i915/gem_engine_topology.h"
> +
>   void igt_require_hang_ring(int fd, int ring);
>   
>   typedef struct igt_hang {
> @@ -86,6 +88,12 @@ extern const struct intel_execution_engine {
>   	     e__++) \
>   		for_if (gem_ring_has_physical_engine(fd__, flags__ = e__->exec_id | e__->flags))
>   
> +#define for_each_engine2(fd, ctx) \
> +		for (struct intel_execution_engine2 *e2__ = \
> +		     gem_set_context_get_engines(fd, ctx); e2__->name; e2__++) \
> +			for_if (gem_has_engine_topology() || \
> +				gem_has_engine(fd, e2__->class, e2__->instance))

gem_has_engine is a legacy hack which shouldn't be used and can 
hopefully be eliminated by the end of this work.

I think this iterator should assume ctx engine map has been configured 
with only available engines so neiher gem_has_engine_topology or 
gem_has_engine should be needed. Unless I am missing something?

> +
>   bool gem_ring_is_physical_engine(int fd, unsigned int ring);
>   bool gem_ring_has_physical_engine(int fd, unsigned int ring);
>   
> 

Regards,

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

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

* Re: [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well Andi Shyti
  2019-03-05 13:27   ` Chris Wilson
@ 2019-03-07 12:10   ` Tvrtko Ursulin
  2019-03-07 13:54     ` Andi Shyti
  1 sibling, 1 reply; 30+ messages in thread
From: Tvrtko Ursulin @ 2019-03-07 12:10 UTC (permalink / raw)
  To: Andi Shyti, IGT dev; +Cc: Andi Shyti


On 05/03/2019 13:16, Andi Shyti wrote:
> With the new engine query method engines are reachable through
> an index and context they are combined with.
> 
> The 'gem_has_ring()' becomes 'gem_context_has_engine()' that
> requires the index that the engine is mapped within the driver.
> 
> The previous 'gem_has_ring()' function becomes a wrapper to the new
> 'gem_context_has_engine()'.
> 
> Signed-off-by: Andi Shyti <andi.shyti@intel.com>
> ---
>   lib/ioctl_wrappers.c | 4 +++-
>   lib/ioctl_wrappers.h | 4 +++-
>   2 files changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
> index 39920f8707d2..a2597e282704 100644
> --- a/lib/ioctl_wrappers.c
> +++ b/lib/ioctl_wrappers.c
> @@ -1252,7 +1252,7 @@ void igt_require_gem(int fd)
>   	igt_require_f(err == 0, "Unresponsive i915/GEM device\n");
>   }
>   
> -bool gem_has_ring(int fd, unsigned ring)
> +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx)
>   {
>   	struct drm_i915_gem_execbuffer2 execbuf;
>   	struct drm_i915_gem_exec_object2 exec;
> @@ -1268,6 +1268,8 @@ bool gem_has_ring(int fd, unsigned ring)
>   	execbuf.buffers_ptr = to_user_pointer(&exec);
>   	execbuf.buffer_count = 1;
>   	execbuf.flags = ring;
> +	execbuf.rsvd1 = ctx;
> +
>   	return __gem_execbuf(fd, &execbuf) == -ENOENT;
>   }
>   
> diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
> index f0be26080da6..446e973b7449 100644
> --- a/lib/ioctl_wrappers.h
> +++ b/lib/ioctl_wrappers.h
> @@ -142,11 +142,13 @@ bool gem_has_exec_fence(int fd);
>   
>   /* check functions which auto-skip tests by calling igt_skip() */
>   void gem_require_caching(int fd);
> -bool gem_has_ring(int fd, unsigned ring);
> +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx);
>   void gem_require_ring(int fd, unsigned ring);
>   bool gem_has_mocs_registers(int fd);
>   void gem_require_mocs_registers(int fd);
>   
> +#define gem_has_ring(fd, ring) gem_context_has_engine(fd, ring, 0)
> +
>   /* prime */
>   struct local_dma_buf_sync {
>   	uint64_t flags;
> 

I don't understand why this. All current callers of gem_has_ring pass in 
eb flags and not an index so how it can work?

Regards,

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

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

* Re: [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines
  2019-03-07 12:07   ` Tvrtko Ursulin
@ 2019-03-07 12:27     ` Tvrtko Ursulin
  2019-03-07 13:52       ` Andi Shyti
  0 siblings, 1 reply; 30+ messages in thread
From: Tvrtko Ursulin @ 2019-03-07 12:27 UTC (permalink / raw)
  To: Andi Shyti, IGT dev; +Cc: Andi Shyti


On 07/03/2019 12:07, Tvrtko Ursulin wrote:
> 
> On 05/03/2019 13:16, Andi Shyti wrote:
>> 'for_each_engine2()' defines a loop through the gpu engines.
>>
>> It can work with both active and pre-defined engines.
>>
>> In case we are looping through active engines (i.e. the running
>> kernel has the query and get/setparam ioctls), the
>> intel_active_engines2 points to an array that contains only the
>> list engines dynamically allocated after having interrogated the
>> driver.
>>
>> While, if we are looping through pre-defined engines,
>> intel_active_engines2 points to the 'intel_execution_engines2'
>> array and works exactly as for_each_engine() but using the
>> new 'struct intel_execution_engine2' data type.
>>
>> Signed-off-by: Andi Shyti <andi.shyti@intel.com>
>> ---
>>   lib/igt_gt.h | 8 ++++++++
>>   1 file changed, 8 insertions(+)
>>
>> diff --git a/lib/igt_gt.h b/lib/igt_gt.h
>> index f4bd6c22a81a..f8bdaa62899f 100644
>> --- a/lib/igt_gt.h
>> +++ b/lib/igt_gt.h
>> @@ -30,6 +30,8 @@
>>   #include "i915_drm.h"
>> +#include "i915/gem_engine_topology.h"
>> +
>>   void igt_require_hang_ring(int fd, int ring);
>>   typedef struct igt_hang {
>> @@ -86,6 +88,12 @@ extern const struct intel_execution_engine {
>>            e__++) \
>>           for_if (gem_ring_has_physical_engine(fd__, flags__ = 
>> e__->exec_id | e__->flags))
>> +#define for_each_engine2(fd, ctx) \
>> +        for (struct intel_execution_engine2 *e2__ = \
>> +             gem_set_context_get_engines(fd, ctx); e2__->name; e2__++) \
>> +            for_if (gem_has_engine_topology() || \
>> +                gem_has_engine(fd, e2__->class, e2__->instance))
> 
> gem_has_engine is a legacy hack which shouldn't be used and can 
> hopefully be eliminated by the end of this work.
> 
> I think this iterator should assume ctx engine map has been configured 
> with only available engines so neiher gem_has_engine_topology or 
> gem_has_engine should be needed. Unless I am missing something?

I forgot about the desire to run on old kernels.. blah..

But it still doesn't work since whatever is in the loop will use the 
index and the context may not have one.

Would a helper like gem_get_ctx_engine_flags(fd, ctx, e2, i) solve this?

I think something along those lines was in discussion some time back.

bool gem_get_ctx_engine_flags(...)
{
	if (ctx.has_map, or maybe, if gem_has_engine_topology)
		return i;
	else
		return e2->eb_flags;
}

It would need a comeback of index param to the iterator though.

Regards,

Tvrtko

> 
>> +
>>   bool gem_ring_is_physical_engine(int fd, unsigned int ring);
>>   bool gem_ring_has_physical_engine(int fd, unsigned int ring);
>>
> 
> Regards,
> 
> Tvrtko
> _______________________________________________
> 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] 30+ messages in thread

* Re: [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library
  2019-03-05 13:24   ` Chris Wilson
@ 2019-03-07 13:00     ` Andi Shyti
  0 siblings, 0 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-07 13:00 UTC (permalink / raw)
  To: Chris Wilson; +Cc: IGT dev, Andi Shyti

Hi Chris,

thanks for your review,

> > +static void set_ctx_param_engines(int fd, uint32_t ctx_id)
> > +{
> > +       struct i915_context_param_engines *ctx_engine;
> > +       struct drm_i915_gem_context_param ctx_param;
> > +       const struct intel_execution_engine2 *e2;
> > +       uint8_t buff[SIZEOF_CTX_PARAM] = { };
> > +       int i;
> > +
> > +       if (!gem_has_engine_topology())
> > +               return;
> 
> Why would different fd have the same topology?

I see here your point, but I think that being able to handle
multi FDs is a completely different beast and this patch does not
have, by now, any effect on it.

First of all, we would need to address the problem to the driver,
is the i915 able to work with multiple GPUs?

Second, is igt able to work simultaneously with mutliple GPUs?
No, and we can start checking from the opening of the device, and
igt, by now opens one and only one device per time.

If we want to support multiple FDs for a single test, I guess we
would need to combine (in GPU structures?) FD and hardware
properties so that we can address them separately in a single
test.

In any case, definitely this goes beyond the purpose of this
patchset and when, ages ago, I started working on this, I wanted
to keep it as similar to what was already there.

I'm afraid, that if I make this and the next patch future proof,
I'm going to make things more complex and "overstructured" when
we will start working for having IGT able to run on multiple FDs
(as for_each_engine2() will be completely different).

So that, for now, I would suggest to keep things as they are and
address the mutliple FDs issue in a different work set.

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

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

* Re: [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library
  2019-03-07 12:05   ` Tvrtko Ursulin
@ 2019-03-07 13:42     ` Andi Shyti
  2019-03-07 14:16       ` Tvrtko Ursulin
  0 siblings, 1 reply; 30+ messages in thread
From: Andi Shyti @ 2019-03-07 13:42 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: IGT dev, Andi Shyti

Hi Tvrtko,

> > +#include "drmtest.h"
> > +#include "igt_gt.h"
> > +#include "ioctl_wrappers.h"
> > +
> > +#include "i915/gem_engine_topology.h"
> > +
> > +#define SIZEOF_CTX_PARAM	offsetof(struct i915_context_param_engines, \
> > +					class_instance[I915_EXEC_RING_MASK + 1])
> > +#define SIZEOF_QUERY		offsetof(struct drm_i915_query_engine_info, \
> > +					engines[I915_EXEC_RING_MASK + 1])
> 
> There is no relationship between I915_EXEC_RING_MASK and the number of
> engines we can query. I'll suggest how I think it should work a bit later.

I915_EXEC_RING_MASK is the upper limit checked in the driver,
that's why I used that one. I could have hardcoded it to 64, but
I wanted to keep it consistent to the driver.

> > +
> > +static struct intel_execution_engine2 *intel_active_engines2;
> > +
> > +int __gem_query(int fd, struct drm_i915_query *q)
> > +{
> > +	int err = 0;
> > +
> > +	if (igt_ioctl(fd, DRM_IOCTL_I915_QUERY, q))
> > +		err = -errno;
> > +
> > +	errno = 0;
> > +	return err;
> > +}
> > +
> > +void gem_query(int fd, struct drm_i915_query *q)
> > +{
> > +	igt_assert_eq(__gem_query(fd, q), 0);
> > +}
> 
> I would keep these two static if there are no external callers for now.

Yes, I can make them static, I thought someone might need them in
the future.

> > +
> > +static void query_engines(int fd,
> > +			  struct drm_i915_query_engine_info *query_engines)
> > +{
> > +	struct drm_i915_query_item item = { };
> > +	struct drm_i915_query query = { };
> > +
> > +	item.query_id = DRM_I915_QUERY_ENGINE_INFO;
> > +	query.items_ptr = to_user_pointer(&item);
> > +	query.num_items = 1;
> > +	item.length = SIZEOF_QUERY;
> 
> I think making this function take buffer size and return the queried size
> would be simplest.

I haven't really understood, do you mean doing something like:

static int query_engines(...., int size)
{
   [...]
   return size;
}

or calling the gem_query twice, first time for getting the size
and second time for allocating the necessary resources.

Because in the first case, we have the size in query_engines, is
that right?

While if you mean the second case, this is how I did it at the
very beginning, but then with Chris we agreed that 64
(I915_EXEC_RING_MASK) is "big enough". If you are strong with it,
I can revert it back.

> > +
> > +	item.data_ptr = to_user_pointer(query_engines);
> > +
> > +	gem_query(fd, &query);
> > +}
> > +
> > +bool gem_has_engine_topology(void)
> > +{
> > +	return intel_active_engines2 != intel_execution_engines2;
> 
> A problem for the exported API if init_engine_list hasn't been called yet?
> Maybe:
> 
> 	if (!intel_active_engines2)
> 		init_engine_list(fd);
> 
> 	return intel_active_engines2 != intel_execution_engines2;
> 
> ?

Yes, it's indeed prone to be misused, I would need to make a more
generic way, because the two lines

   if (!intel_active_engines2)
          init_engine_list(fd);

are called so many times that I'm having an overdose of them :)

> > +}
> > +
> > +static void set_ctx_param_engines(int fd, uint32_t ctx_id)
> > +{
> > +	struct i915_context_param_engines *ctx_engine;
> > +	struct drm_i915_gem_context_param ctx_param;
> > +	const struct intel_execution_engine2 *e2;
> > +	uint8_t buff[SIZEOF_CTX_PARAM] = { };
> > +	int i;
> > +
> > +	if (!gem_has_engine_topology())
> > +		return;
> 
> AFAICS this can be assert here.

I think this check is redundant as it's never going to happen.
This function is 'static' and the calling function checks that
already. I will remove it.

> > +
> > +	ctx_engine = (struct i915_context_param_engines *) buff;
> > +
> > +	ctx_param.ctx_id = ctx_id;
> > +	ctx_param.param = I915_CONTEXT_PARAM_ENGINES;
> > +
> > +	ctx_engine->extensions = 0;
> > +	for (i = 0, e2 = intel_active_engines2; e2->name; i++, e2++) {
> 
> Here I think is the place where we check that the total number of engines
> does not exceed the engine map execbuf index.
> 
> 	igt_require(i <= I915_EXEC_RING_MASK);
> 
> ?

I can add that, but it would be redundant as the list would have
never been created otherwise... anyway, better be safe than sorry :)

BTW, given my natural confusion between 'require' and 'assert',
you meant 'assert', right?

> > +		ctx_engine->class_instance[i].engine_class = e2->class;
> > +		ctx_engine->class_instance[i].engine_instance = e2->instance;
> > +	}
> > +
> > +	ctx_param.size = offsetof(typeof(*ctx_engine), class_instance[i + 1]);
> > +	ctx_param.value = to_user_pointer(ctx_engine);
> > +
> > +	gem_context_set_param(fd, &ctx_param);
> > +}
> > +
> > +/*
> > + * Initializes the list of engines.
> > + *
> > + * Returns:
> > + *
> > + *  - 0 in case of success and the get/set_param ioctls are implemented
> > + *  - -ENODEV in case of success but I915_CONTEXT_PARAM_ENGINES is not
> > + *    implemented in DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM ioctl.
> > + */
> > +static int init_engine_list(int fd)
> > +{
> > +	const char *class_names[] = { "rcs", "bcs", "vcs", "vecs" };
> > +	struct drm_i915_query_engine_info *query_engine;
> > +	unsigned char query_buffer[SIZEOF_QUERY] = { };
> > +	struct drm_i915_gem_context_param ctx_param = {
> > +		.param = I915_CONTEXT_PARAM_ENGINES,
> > +	};
> > +	int i;
> > +
> > +	/* the list is already initialized */
> > +	if (intel_active_engines2)
> > +		return gem_has_engine_topology() ? 0 : -ENODEV;
> > +
> > +	/*
> > +	 * We check first whether the I915_CONTEXT_PARAM_ENGINES parameter is
> > +	 * supported by the running kernel. If not, __gem_context_get_param()
> > +	 * will return -EINVAL which, at this point, is not necessarily a
> > +	 * failure but it means that we need to fall beck to polling the engines
> > +	 * directly from intel_execution_engines2[].
> > +	 *
> > +	 * We will return -ENODEV with the meaning of missing interface
> > +	 */
> > +	if (__gem_context_get_param(fd, &ctx_param)) {
> > +		intel_active_engines2 = intel_execution_engines2;
> > +		return -ENODEV;
> > +	}
> > +
> > +	query_engine = (struct drm_i915_query_engine_info *) query_buffer;
> > +	query_engines(fd, query_engine);
> 
> Do a two stage query here - first ask for required buffer size, then
> allocate it and query:
> 
> 	size = query_engines(fd, NULL, 0);
> 	query_engine = malloc(size);
> 	query_engines(fd, query_engine, size);

As above :) this is how I did it at the beginning and with Chris
we agreed that 64 is big enough, and then we had some review
rounds on agreeing on buffer size, name, calculation and so
on.

Shall I move back? Honestly I like the double call, as well.

> > +
> > +	igt_assert(query_engine->num_engines < I915_EXEC_RING_MASK + 1);
> 
> Remove this since we don't need to limit the size of the array during the
> query. It is only the engine map that has the limitation.

This came after one of the 10 rounds of review as well :)
It's indeed a bit redundant, It's mainly for the malloc,
to avoid crazy allocation in case something goes wrong.

> > +
> > +	intel_active_engines2 = malloc((query_engine->num_engines + 1) *
> > +				       sizeof(*intel_active_engines2));
> > +	igt_assert(intel_active_engines2);
> > +
> > +	for (i = 0; i < query_engine->num_engines; i++) {
> > +		char *name;
> > +		int class = query_engine->engines[i].engine_class;
> > +		int instance = query_engine->engines[i].engine_instance;
> 
> Could use __u16 to match uapi.

Sure!

> > +
> > +		intel_active_engines2[i].class = class;
> > +		intel_active_engines2[i].instance = instance;
> > +
> > +		/* if we don't recognise the class, then we mark it as "unk" */
> > +		if (class >= ARRAY_SIZE(class_names) || !class_names[class])
> 
> Second condition seems to be not needed at the moment.

Yes, of course, it must be a leftover.

> > +struct intel_execution_engine2 *get_active_engines(int fd)
> 
> Unexport this one?

I thought someone might need it, I will do it static and rework
it with the bool gem_has_engine_topology() as they would become
very similar.

> > +{
> > +	if (init_engine_list(fd)) {
> > +		igt_info("using pre-allocated engine list\n");
> > +		return NULL;
> > +	}
> > +
> > +	return intel_active_engines2;
> > +}
> > +
> > +struct intel_execution_engine2 *gem_set_context_get_engines(int fd,
> > +							    uint32_t ctx_id)
> 
> I find the name of this function really confusing (set get what?). Can I
> suggest __gem_prepare_context_engines or something like that?

The name means "set context and get engines", as it's a "get_"
kind of function. But as it came out, I have a very limited
imagination for names choice. I will call it
__gem_prepare_context_engines(), then.

> > +{
> > +	struct intel_execution_engine2 *active_engines = get_active_engines(fd);
> > +
> > +	if (!active_engines)
> > +		return intel_execution_engines2;
> 
> So without engine discovery the function will not configure the engine map.
> How will the code inside for_each_engine2 be able to work then?

It's this part of the for_each_engine2 that would make it work:

 for_if (gem_has_engine_topology() || \
         gem_has_engine(fd, e2__->class, e2__->instance))

We had quite some discussions about backward compatibility and
the whole thing is designed to be backward compatible, otherwise,
I would have removed quite some code from the above.

> I guess it's okay since we don't expect to see a kernel with ctx engine map
> support and no engine discovery but it feels a bit unnatural.
> 
> But I think it effectively means you should have igt_require_gem_engine_list
> in here since it is otherwise not usable from the for_each_engine2 iterator.
> 
> > +
> > +	set_ctx_param_engines(fd, ctx_id);
> 
> You need to handle the use case where the context already has a map
> configured instead of overriding it. Should be easy.

Yes, this is relevant to your comment above, about the
igt_require(<new_api>). This part is checked in
'get_active_engines(fd)', that returns NULL if we do not have the
new uapi and therefore it returns the old list of engines.

adding the igt_require() (asset?) would be redundant.
Am I missing any use case?

> > +#ifndef GEM_QUERY_H
> > +#define GEM_QUERY_H
> 
> GEM_ENGINE_TOPOLOGY_H

Yes :) This library was affected by an extensive name changing,
due to my lack of imagination :)

> > -const struct intel_execution_engine2 intel_execution_engines2[] = {
> > +struct intel_execution_engine2 intel_execution_engines2[] = {
> 
> This one can't stay const?

Yes, I hate this bit as well! I removed here the const, because I
wanted active_engines2 to point to execution_engine2.

active_engines2 cannot be const, so that I cannot make it point
to this one, therefore I have to remove the const from here.

But, indeed, because now I am using the "get_engine...()" and
because I am going to rework the 'bool has_engine_topology()'
function, approach, I might not need anymore to refer to this
one.

What will happen, though, is that we would then need, at some
point, to patch all the tests that refer to
intel_execution_engines2.

Thanks a lot for your review, Tvrtko,
Andi
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines
  2019-03-07 12:27     ` Tvrtko Ursulin
@ 2019-03-07 13:52       ` Andi Shyti
  0 siblings, 0 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-07 13:52 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: IGT dev, Andi Shyti

Hi Tvrtko,

> > > +#define for_each_engine2(fd, ctx) \
> > > +        for (struct intel_execution_engine2 *e2__ = \
> > > +             gem_set_context_get_engines(fd, ctx); e2__->name; e2__++) \
> > > +            for_if (gem_has_engine_topology() || \
> > > +                gem_has_engine(fd, e2__->class, e2__->instance))
> > 
> > gem_has_engine is a legacy hack which shouldn't be used and can
> > hopefully be eliminated by the end of this work.
> > 
> > I think this iterator should assume ctx engine map has been configured
> > with only available engines so neiher gem_has_engine_topology or
> > gem_has_engine should be needed. Unless I am missing something?
> 
> I forgot about the desire to run on old kernels.. blah..

yes! :)

> But it still doesn't work since whatever is in the loop will use the index
> and the context may not have one.

You think so? Unless I am very likely to be missing something,
this should work in any case, thus the next patch:

'[RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well'

Where, I modified the existing 'gem_has_ring()' to work with both
index and not index. Still in the next patch there is:

> Would a helper like gem_get_ctx_engine_flags(fd, ctx, e2, i) solve this?

it looks like the version in patch v2 or v3 something :D

> I think something along those lines was in discussion some time back.
> 
> bool gem_get_ctx_engine_flags(...)
> {
> 	if (ctx.has_map, or maybe, if gem_has_engine_topology)
> 		return i;
> 	else
> 		return e2->eb_flags;

I was asked not to add anything in 'struct
intel_execution_engine2' :/

> }
> 
> It would need a comeback of index param to the iterator though.

About the iterator we had also some discussions and at the end I
did as Chris asked.

Doing what you ask, it's more an architectural decision, do we
like it as it is now or as it was before?

Personally I like the explicit iterator, and as it is now, with
the changes in patch 4, it works fine with new and old api
without many changes. Right? :)

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

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

* Re: [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well
  2019-03-07 12:10   ` Tvrtko Ursulin
@ 2019-03-07 13:54     ` Andi Shyti
  2019-03-07 14:27       ` Tvrtko Ursulin
  0 siblings, 1 reply; 30+ messages in thread
From: Andi Shyti @ 2019-03-07 13:54 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: IGT dev, Andi Shyti

Hi Tvrtko,

> > With the new engine query method engines are reachable through
> > an index and context they are combined with.
> > 
> > The 'gem_has_ring()' becomes 'gem_context_has_engine()' that
> > requires the index that the engine is mapped within the driver.
> > 
> > The previous 'gem_has_ring()' function becomes a wrapper to the new
> > 'gem_context_has_engine()'.
> > 
> > Signed-off-by: Andi Shyti <andi.shyti@intel.com>
> > ---
> >   lib/ioctl_wrappers.c | 4 +++-
> >   lib/ioctl_wrappers.h | 4 +++-
> >   2 files changed, 6 insertions(+), 2 deletions(-)
> > 
> > diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
> > index 39920f8707d2..a2597e282704 100644
> > --- a/lib/ioctl_wrappers.c
> > +++ b/lib/ioctl_wrappers.c
> > @@ -1252,7 +1252,7 @@ void igt_require_gem(int fd)
> >   	igt_require_f(err == 0, "Unresponsive i915/GEM device\n");
> >   }
> > -bool gem_has_ring(int fd, unsigned ring)
> > +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx)
> >   {
> >   	struct drm_i915_gem_execbuffer2 execbuf;
> >   	struct drm_i915_gem_exec_object2 exec;
> > @@ -1268,6 +1268,8 @@ bool gem_has_ring(int fd, unsigned ring)
> >   	execbuf.buffers_ptr = to_user_pointer(&exec);
> >   	execbuf.buffer_count = 1;
> >   	execbuf.flags = ring;
> > +	execbuf.rsvd1 = ctx;
> > +
> >   	return __gem_execbuf(fd, &execbuf) == -ENOENT;
> >   }
> > diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
> > index f0be26080da6..446e973b7449 100644
> > --- a/lib/ioctl_wrappers.h
> > +++ b/lib/ioctl_wrappers.h
> > @@ -142,11 +142,13 @@ bool gem_has_exec_fence(int fd);
> >   /* check functions which auto-skip tests by calling igt_skip() */
> >   void gem_require_caching(int fd);
> > -bool gem_has_ring(int fd, unsigned ring);
> > +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx);
> >   void gem_require_ring(int fd, unsigned ring);
> >   bool gem_has_mocs_registers(int fd);
> >   void gem_require_mocs_registers(int fd);
> > +#define gem_has_ring(fd, ring) gem_context_has_engine(fd, ring, 0)
> > +
> >   /* prime */
> >   struct local_dma_buf_sync {
> >   	uint64_t flags;
> > 
> 
> I don't understand why this. All current callers of gem_has_ring pass in eb
> flags and not an index so how it can work?

This is because of patch 3/6 this makes the for_each_engine2()
able to work with new and old api.

Have I messed up the patch order?

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

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

* Re: [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library
  2019-03-07 13:42     ` Andi Shyti
@ 2019-03-07 14:16       ` Tvrtko Ursulin
  2019-03-07 14:59         ` Chris Wilson
  0 siblings, 1 reply; 30+ messages in thread
From: Tvrtko Ursulin @ 2019-03-07 14:16 UTC (permalink / raw)
  To: Andi Shyti; +Cc: IGT dev, Andi Shyti


On 07/03/2019 13:42, Andi Shyti wrote:
> Hi Tvrtko,
> 
>>> +#include "drmtest.h"
>>> +#include "igt_gt.h"
>>> +#include "ioctl_wrappers.h"
>>> +
>>> +#include "i915/gem_engine_topology.h"
>>> +
>>> +#define SIZEOF_CTX_PARAM	offsetof(struct i915_context_param_engines, \
>>> +					class_instance[I915_EXEC_RING_MASK + 1])
>>> +#define SIZEOF_QUERY		offsetof(struct drm_i915_query_engine_info, \
>>> +					engines[I915_EXEC_RING_MASK + 1])
>>
>> There is no relationship between I915_EXEC_RING_MASK and the number of
>> engines we can query. I'll suggest how I think it should work a bit later.
> 
> I915_EXEC_RING_MASK is the upper limit checked in the driver,
> that's why I used that one. I could have hardcoded it to 64, but
> I wanted to keep it consistent to the driver.

I'll argue with Chris to remove this limit from the engine map (come eb3 
might not be relevant any more) - nevertheless the query does not have 
this limit so I think it would be best to decouple the code from the start.

>>> +
>>> +static struct intel_execution_engine2 *intel_active_engines2;
>>> +
>>> +int __gem_query(int fd, struct drm_i915_query *q)
>>> +{
>>> +	int err = 0;
>>> +
>>> +	if (igt_ioctl(fd, DRM_IOCTL_I915_QUERY, q))
>>> +		err = -errno;
>>> +
>>> +	errno = 0;
>>> +	return err;
>>> +}
>>> +
>>> +void gem_query(int fd, struct drm_i915_query *q)
>>> +{
>>> +	igt_assert_eq(__gem_query(fd, q), 0);
>>> +}
>>
>> I would keep these two static if there are no external callers for now.
> 
> Yes, I can make them static, I thought someone might need them in
> the future.

Could be but it will be easy to export them at that point. I wanted to 
keep the patch smallest possible for now so I can focus on reviewing the 
important bits.

> 
>>> +
>>> +static void query_engines(int fd,
>>> +			  struct drm_i915_query_engine_info *query_engines)
>>> +{
>>> +	struct drm_i915_query_item item = { };
>>> +	struct drm_i915_query query = { };
>>> +
>>> +	item.query_id = DRM_I915_QUERY_ENGINE_INFO;
>>> +	query.items_ptr = to_user_pointer(&item);
>>> +	query.num_items = 1;
>>> +	item.length = SIZEOF_QUERY;
>>
>> I think making this function take buffer size and return the queried size
>> would be simplest.
> 
> I haven't really understood, do you mean doing something like:
> 
> static int query_engines(...., int size)
> {
>     [...]
>     return size;
> }
> 
> or calling the gem_query twice, first time for getting the size
> and second time for allocating the necessary resources.
> 
> Because in the first case, we have the size in query_engines, is
> that right?
> 
> While if you mean the second case, this is how I did it at the
> very beginning, but then with Chris we agreed that 64
> (I915_EXEC_RING_MASK) is "big enough". If you are strong with it,
> I can revert it back.

Hm.. what happened to the old Chris!? :)) I am not objecting that 
strongly. Especially if you already changed it once then just leave it. 
It can be changed later if someone gets the desire to tidy..

>>> +
>>> +	item.data_ptr = to_user_pointer(query_engines);
>>> +
>>> +	gem_query(fd, &query);
>>> +}
>>> +
>>> +bool gem_has_engine_topology(void)
>>> +{
>>> +	return intel_active_engines2 != intel_execution_engines2;
>>
>> A problem for the exported API if init_engine_list hasn't been called yet?
>> Maybe:
>>
>> 	if (!intel_active_engines2)
>> 		init_engine_list(fd);
>>
>> 	return intel_active_engines2 != intel_execution_engines2;
>>
>> ?
> 
> Yes, it's indeed prone to be misused, I would need to make a more
> generic way, because the two lines
> 
>     if (!intel_active_engines2)
>            init_engine_list(fd);
> 
> are called so many times that I'm having an overdose of them :)

Yes the call chains and responsibilities do feel a bit unobvious.

> 
>>> +}
>>> +
>>> +static void set_ctx_param_engines(int fd, uint32_t ctx_id)
>>> +{
>>> +	struct i915_context_param_engines *ctx_engine;
>>> +	struct drm_i915_gem_context_param ctx_param;
>>> +	const struct intel_execution_engine2 *e2;
>>> +	uint8_t buff[SIZEOF_CTX_PARAM] = { };
>>> +	int i;
>>> +
>>> +	if (!gem_has_engine_topology())
>>> +		return;
>>
>> AFAICS this can be assert here.
> 
> I think this check is redundant as it's never going to happen.
> This function is 'static' and the calling function checks that
> already. I will remove it.

Better to have it as assert but as you wish. I guess even without an 
assert it would segfault when it tries to iterate intel_active_engines2.

> 
>>> +
>>> +	ctx_engine = (struct i915_context_param_engines *) buff;
>>> +
>>> +	ctx_param.ctx_id = ctx_id;
>>> +	ctx_param.param = I915_CONTEXT_PARAM_ENGINES;
>>> +
>>> +	ctx_engine->extensions = 0;
>>> +	for (i = 0, e2 = intel_active_engines2; e2->name; i++, e2++) {
>>
>> Here I think is the place where we check that the total number of engines
>> does not exceed the engine map execbuf index.
>>
>> 	igt_require(i <= I915_EXEC_RING_MASK);
>>
>> ?
> 
> I can add that, but it would be redundant as the list would have
> never been created otherwise... anyway, better be safe than sorry :)

Yes I know, I wrote that because I was suggesting to remove the 64 
engine limit from the query and just have it in the engine map.

But as said if you already discussed that point then leave it.

> BTW, given my natural confusion between 'require' and 'assert',
> you meant 'assert', right?

I meant require. But I don't know either, it's so hard to choose 
sometimes. :)

>>> +		ctx_engine->class_instance[i].engine_class = e2->class;
>>> +		ctx_engine->class_instance[i].engine_instance = e2->instance;
>>> +	}
>>> +
>>> +	ctx_param.size = offsetof(typeof(*ctx_engine), class_instance[i + 1]);
>>> +	ctx_param.value = to_user_pointer(ctx_engine);
>>> +
>>> +	gem_context_set_param(fd, &ctx_param);
>>> +}
>>> +
>>> +/*
>>> + * Initializes the list of engines.
>>> + *
>>> + * Returns:
>>> + *
>>> + *  - 0 in case of success and the get/set_param ioctls are implemented
>>> + *  - -ENODEV in case of success but I915_CONTEXT_PARAM_ENGINES is not
>>> + *    implemented in DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM ioctl.
>>> + */
>>> +static int init_engine_list(int fd)
>>> +{
>>> +	const char *class_names[] = { "rcs", "bcs", "vcs", "vecs" };
>>> +	struct drm_i915_query_engine_info *query_engine;
>>> +	unsigned char query_buffer[SIZEOF_QUERY] = { };
>>> +	struct drm_i915_gem_context_param ctx_param = {
>>> +		.param = I915_CONTEXT_PARAM_ENGINES,
>>> +	};
>>> +	int i;
>>> +
>>> +	/* the list is already initialized */
>>> +	if (intel_active_engines2)
>>> +		return gem_has_engine_topology() ? 0 : -ENODEV;
>>> +
>>> +	/*
>>> +	 * We check first whether the I915_CONTEXT_PARAM_ENGINES parameter is
>>> +	 * supported by the running kernel. If not, __gem_context_get_param()
>>> +	 * will return -EINVAL which, at this point, is not necessarily a
>>> +	 * failure but it means that we need to fall beck to polling the engines
>>> +	 * directly from intel_execution_engines2[].
>>> +	 *
>>> +	 * We will return -ENODEV with the meaning of missing interface
>>> +	 */
>>> +	if (__gem_context_get_param(fd, &ctx_param)) {
>>> +		intel_active_engines2 = intel_execution_engines2;
>>> +		return -ENODEV;
>>> +	}
>>> +
>>> +	query_engine = (struct drm_i915_query_engine_info *) query_buffer;
>>> +	query_engines(fd, query_engine);
>>
>> Do a two stage query here - first ask for required buffer size, then
>> allocate it and query:
>>
>> 	size = query_engines(fd, NULL, 0);
>> 	query_engine = malloc(size);
>> 	query_engines(fd, query_engine, size);
> 
> As above :) this is how I did it at the beginning and with Chris
> we agreed that 64 is big enough, and then we had some review
> rounds on agreeing on buffer size, name, calculation and so
> on.
> 
> Shall I move back? Honestly I like the double call, as well.

Leave it at least for now then.

>>> +
>>> +	igt_assert(query_engine->num_engines < I915_EXEC_RING_MASK + 1);
>>
>> Remove this since we don't need to limit the size of the array during the
>> query. It is only the engine map that has the limitation.
> 
> This came after one of the 10 rounds of review as well :)
> It's indeed a bit redundant, It's mainly for the malloc,
> to avoid crazy allocation in case something goes wrong.
> 
>>> +
>>> +	intel_active_engines2 = malloc((query_engine->num_engines + 1) *
>>> +				       sizeof(*intel_active_engines2));
>>> +	igt_assert(intel_active_engines2);
>>> +
>>> +	for (i = 0; i < query_engine->num_engines; i++) {
>>> +		char *name;
>>> +		int class = query_engine->engines[i].engine_class;
>>> +		int instance = query_engine->engines[i].engine_instance;
>>
>> Could use __u16 to match uapi.
> 
> Sure!
> 
>>> +
>>> +		intel_active_engines2[i].class = class;
>>> +		intel_active_engines2[i].instance = instance;
>>> +
>>> +		/* if we don't recognise the class, then we mark it as "unk" */
>>> +		if (class >= ARRAY_SIZE(class_names) || !class_names[class])
>>
>> Second condition seems to be not needed at the moment.
> 
> Yes, of course, it must be a leftover.
> 
>>> +struct intel_execution_engine2 *get_active_engines(int fd)
>>
>> Unexport this one?
> 
> I thought someone might need it, I will do it static and rework
> it with the bool gem_has_engine_topology() as they would become
> very similar.
> 
>>> +{
>>> +	if (init_engine_list(fd)) {
>>> +		igt_info("using pre-allocated engine list\n");
>>> +		return NULL;
>>> +	}
>>> +
>>> +	return intel_active_engines2;
>>> +}
>>> +
>>> +struct intel_execution_engine2 *gem_set_context_get_engines(int fd,
>>> +							    uint32_t ctx_id)
>>
>> I find the name of this function really confusing (set get what?). Can I
>> suggest __gem_prepare_context_engines or something like that?
> 
> The name means "set context and get engines", as it's a "get_"
> kind of function. But as it came out, I have a very limited
> imagination for names choice. I will call it
> __gem_prepare_context_engines(), then.
> 
>>> +{
>>> +	struct intel_execution_engine2 *active_engines = get_active_engines(fd);
>>> +
>>> +	if (!active_engines)
>>> +		return intel_execution_engines2;
>>
>> So without engine discovery the function will not configure the engine map.
>> How will the code inside for_each_engine2 be able to work then?
> 
> It's this part of the for_each_engine2 that would make it work:
> 
>   for_if (gem_has_engine_topology() || \
>           gem_has_engine(fd, e2__->class, e2__->instance))
> 
> We had quite some discussions about backward compatibility and
> the whole thing is designed to be backward compatible, otherwise,
> I would have removed quite some code from the above.

Yes, I comment on that in the other reply.

>> I guess it's okay since we don't expect to see a kernel with ctx engine map
>> support and no engine discovery but it feels a bit unnatural.
>>
>> But I think it effectively means you should have igt_require_gem_engine_list
>> in here since it is otherwise not usable from the for_each_engine2 iterator.
>>
>>> +
>>> +	set_ctx_param_engines(fd, ctx_id);
>>
>> You need to handle the use case where the context already has a map
>> configured instead of overriding it. Should be easy.
> 
> Yes, this is relevant to your comment above, about the
> igt_require(<new_api>). This part is checked in
> 'get_active_engines(fd)', that returns NULL if we do not have the
> new uapi and therefore it returns the old list of engines.
> 
> adding the igt_require() (asset?) would be redundant.
> Am I missing any use case?

AFAIR Chris wanted it to support the use case where he configures the 
engine map and passes the context to for_each_engine2. Maybe he changed 
his mind?

It would be tricky to do since then there is no intel_active_engine 
array to walk.. Could only define the iterator that the pointer to 
engine is sometimes not valid (must be checked) and added index used to 
submit. Not sure, depends if Chris still wants this feature.

>>> +#ifndef GEM_QUERY_H
>>> +#define GEM_QUERY_H
>>
>> GEM_ENGINE_TOPOLOGY_H
> 
> Yes :) This library was affected by an extensive name changing,
> due to my lack of imagination :)
> 
>>> -const struct intel_execution_engine2 intel_execution_engines2[] = {
>>> +struct intel_execution_engine2 intel_execution_engines2[] = {
>>
>> This one can't stay const?
> 
> Yes, I hate this bit as well! I removed here the const, because I
> wanted active_engines2 to point to execution_engine2.
> 
> active_engines2 cannot be const, so that I cannot make it point
> to this one, therefore I have to remove the const from here.
> 
> But, indeed, because now I am using the "get_engine...()" and
> because I am going to rework the 'bool has_engine_topology()'
> function, approach, I might not need anymore to refer to this
> one.

Hm yes, the const hell.. see what's easiest then.

> What will happen, though, is that we would then need, at some
> point, to patch all the tests that refer to
> intel_execution_engines2.

I think keep the big changes to minimum for this series at this stage 
and we just try to make it work good enough for the media scalability 
requirement.

Regards,

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

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

* Re: [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well
  2019-03-07 13:54     ` Andi Shyti
@ 2019-03-07 14:27       ` Tvrtko Ursulin
  2019-03-07 15:46         ` Andi Shyti
  0 siblings, 1 reply; 30+ messages in thread
From: Tvrtko Ursulin @ 2019-03-07 14:27 UTC (permalink / raw)
  To: Andi Shyti; +Cc: IGT dev, Andi Shyti


On 07/03/2019 13:54, Andi Shyti wrote:
> Hi Tvrtko,
> 
>>> With the new engine query method engines are reachable through
>>> an index and context they are combined with.
>>>
>>> The 'gem_has_ring()' becomes 'gem_context_has_engine()' that
>>> requires the index that the engine is mapped within the driver.
>>>
>>> The previous 'gem_has_ring()' function becomes a wrapper to the new
>>> 'gem_context_has_engine()'.
>>>
>>> Signed-off-by: Andi Shyti <andi.shyti@intel.com>
>>> ---
>>>    lib/ioctl_wrappers.c | 4 +++-
>>>    lib/ioctl_wrappers.h | 4 +++-
>>>    2 files changed, 6 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
>>> index 39920f8707d2..a2597e282704 100644
>>> --- a/lib/ioctl_wrappers.c
>>> +++ b/lib/ioctl_wrappers.c
>>> @@ -1252,7 +1252,7 @@ void igt_require_gem(int fd)
>>>    	igt_require_f(err == 0, "Unresponsive i915/GEM device\n");
>>>    }
>>> -bool gem_has_ring(int fd, unsigned ring)
>>> +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx)
>>>    {
>>>    	struct drm_i915_gem_execbuffer2 execbuf;
>>>    	struct drm_i915_gem_exec_object2 exec;
>>> @@ -1268,6 +1268,8 @@ bool gem_has_ring(int fd, unsigned ring)
>>>    	execbuf.buffers_ptr = to_user_pointer(&exec);
>>>    	execbuf.buffer_count = 1;
>>>    	execbuf.flags = ring;
>>> +	execbuf.rsvd1 = ctx;
>>> +
>>>    	return __gem_execbuf(fd, &execbuf) == -ENOENT;
>>>    }
>>> diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
>>> index f0be26080da6..446e973b7449 100644
>>> --- a/lib/ioctl_wrappers.h
>>> +++ b/lib/ioctl_wrappers.h
>>> @@ -142,11 +142,13 @@ bool gem_has_exec_fence(int fd);
>>>    /* check functions which auto-skip tests by calling igt_skip() */
>>>    void gem_require_caching(int fd);
>>> -bool gem_has_ring(int fd, unsigned ring);
>>> +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx);
>>>    void gem_require_ring(int fd, unsigned ring);
>>>    bool gem_has_mocs_registers(int fd);
>>>    void gem_require_mocs_registers(int fd);
>>> +#define gem_has_ring(fd, ring) gem_context_has_engine(fd, ring, 0)
>>> +
>>>    /* prime */
>>>    struct local_dma_buf_sync {
>>>    	uint64_t flags;
>>>
>>
>> I don't understand why this. All current callers of gem_has_ring pass in eb
>> flags and not an index so how it can work?
> 
> This is because of patch 3/6 this makes the for_each_engine2()
> able to work with new and old api.

How does it do that? Maybe I am extra slow today..

How is the for_each_engine2 without a helper to get engine flags, or the 
index variable, supposed to be used if one wants to submit a batch to 
all engines:

for_each_engine2(...)
	eb(engine=??)

Both in legacy and engine discovery mode.

Regards,

Tvrtko

> Have I messed up the patch order?
> 
> Andi
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library
  2019-03-07 14:16       ` Tvrtko Ursulin
@ 2019-03-07 14:59         ` Chris Wilson
  2019-03-07 16:25           ` Tvrtko Ursulin
  0 siblings, 1 reply; 30+ messages in thread
From: Chris Wilson @ 2019-03-07 14:59 UTC (permalink / raw)
  To: Andi Shyti, Tvrtko Ursulin; +Cc: IGT dev, Andi Shyti

Quoting Tvrtko Ursulin (2019-03-07 14:16:13)
> 
> On 07/03/2019 13:42, Andi Shyti wrote:
> > Hi Tvrtko,
> > 
> >>> +#include "drmtest.h"
> >>> +#include "igt_gt.h"
> >>> +#include "ioctl_wrappers.h"
> >>> +
> >>> +#include "i915/gem_engine_topology.h"
> >>> +
> >>> +#define SIZEOF_CTX_PARAM   offsetof(struct i915_context_param_engines, \
> >>> +                                   class_instance[I915_EXEC_RING_MASK + 1])
> >>> +#define SIZEOF_QUERY               offsetof(struct drm_i915_query_engine_info, \
> >>> +                                   engines[I915_EXEC_RING_MASK + 1])
> >>
> >> There is no relationship between I915_EXEC_RING_MASK and the number of
> >> engines we can query. I'll suggest how I think it should work a bit later.
> > 
> > I915_EXEC_RING_MASK is the upper limit checked in the driver,
> > that's why I used that one. I could have hardcoded it to 64, but
> > I wanted to keep it consistent to the driver.
> 
> I'll argue with Chris to remove this limit from the engine map (come eb3 
> might not be relevant any more) - nevertheless the query does not have 
> this limit so I think it would be best to decouple the code from the start.

At the moment it fits in a u64 and I don't have to worry about flexible
bitmaps. It's a bridge to cross later, we've plenty of space in the enum
api to version a new interface.
> 
> >>> +
> >>> +static struct intel_execution_engine2 *intel_active_engines2;
> >>> +
> >>> +int __gem_query(int fd, struct drm_i915_query *q)
> >>> +{
> >>> +   int err = 0;
> >>> +
> >>> +   if (igt_ioctl(fd, DRM_IOCTL_I915_QUERY, q))
> >>> +           err = -errno;
> >>> +
> >>> +   errno = 0;
> >>> +   return err;
> >>> +}
> >>> +
> >>> +void gem_query(int fd, struct drm_i915_query *q)
> >>> +{
> >>> +   igt_assert_eq(__gem_query(fd, q), 0);
> >>> +}
> >>
> >> I would keep these two static if there are no external callers for now.
> > 
> > Yes, I can make them static, I thought someone might need them in
> > the future.
> 
> Could be but it will be easy to export them at that point. I wanted to 
> keep the patch smallest possible for now so I can focus on reviewing the 
> important bits.
> 
> > 
> >>> +
> >>> +static void query_engines(int fd,
> >>> +                     struct drm_i915_query_engine_info *query_engines)
> >>> +{
> >>> +   struct drm_i915_query_item item = { };
> >>> +   struct drm_i915_query query = { };
> >>> +
> >>> +   item.query_id = DRM_I915_QUERY_ENGINE_INFO;
> >>> +   query.items_ptr = to_user_pointer(&item);
> >>> +   query.num_items = 1;
> >>> +   item.length = SIZEOF_QUERY;
> >>
> >> I think making this function take buffer size and return the queried size
> >> would be simplest.
> > 
> > I haven't really understood, do you mean doing something like:
> > 
> > static int query_engines(...., int size)
> > {
> >     [...]
> >     return size;
> > }
> > 
> > or calling the gem_query twice, first time for getting the size
> > and second time for allocating the necessary resources.
> > 
> > Because in the first case, we have the size in query_engines, is
> > that right?
> > 
> > While if you mean the second case, this is how I did it at the
> > very beginning, but then with Chris we agreed that 64
> > (I915_EXEC_RING_MASK) is "big enough". If you are strong with it,
> > I can revert it back.
> 
> Hm.. what happened to the old Chris!? :)) I am not objecting that 
> strongly. Especially if you already changed it once then just leave it. 
> It can be changed later if someone gets the desire to tidy..

If I recall, my position is that you can have a fixed stack and then
fallback to a heap. But for these interfaces where we have to return a
heap pointer, we might as well use heaps and be flexible.

> 
> >>> +
> >>> +   item.data_ptr = to_user_pointer(query_engines);
> >>> +
> >>> +   gem_query(fd, &query);
> >>> +}
> >>> +
> >>> +bool gem_has_engine_topology(void)
> >>> +{
> >>> +   return intel_active_engines2 != intel_execution_engines2;
> >>
> >> A problem for the exported API if init_engine_list hasn't been called yet?
> >> Maybe:
> >>
> >>      if (!intel_active_engines2)
> >>              init_engine_list(fd);
> >>
> >>      return intel_active_engines2 != intel_execution_engines2;
> >>
> >> ?
> > 
> > Yes, it's indeed prone to be misused, I would need to make a more
> > generic way, because the two lines
> > 
> >     if (!intel_active_engines2)
> >            init_engine_list(fd);
> > 
> > are called so many times that I'm having an overdose of them :)
> 
> Yes the call chains and responsibilities do feel a bit unobvious.

I really don't want init_engine_list(fd) at all :) Ideally the query
interface is cheap enough that it doesn't matter (other than debug noise
in strace) and if we can't make it that cheap, it is cached in sensible
scopes.

That may be an igt_device class (i915_device subclass).
> 
> > 
> >>> +}
> >>> +
> >>> +static void set_ctx_param_engines(int fd, uint32_t ctx_id)
> >>> +{
> >>> +   struct i915_context_param_engines *ctx_engine;
> >>> +   struct drm_i915_gem_context_param ctx_param;
> >>> +   const struct intel_execution_engine2 *e2;
> >>> +   uint8_t buff[SIZEOF_CTX_PARAM] = { };
> >>> +   int i;
> >>> +
> >>> +   if (!gem_has_engine_topology())
> >>> +           return;
> >>
> >> AFAICS this can be assert here.
> > 
> > I think this check is redundant as it's never going to happen.
> > This function is 'static' and the calling function checks that
> > already. I will remove it.
> 
> Better to have it as assert but as you wish. I guess even without an 
> assert it would segfault when it tries to iterate intel_active_engines2.
> 
> > 
> >>> +
> >>> +   ctx_engine = (struct i915_context_param_engines *) buff;
> >>> +
> >>> +   ctx_param.ctx_id = ctx_id;
> >>> +   ctx_param.param = I915_CONTEXT_PARAM_ENGINES;
> >>> +
> >>> +   ctx_engine->extensions = 0;
> >>> +   for (i = 0, e2 = intel_active_engines2; e2->name; i++, e2++) {
> >>
> >> Here I think is the place where we check that the total number of engines
> >> does not exceed the engine map execbuf index.
> >>
> >>      igt_require(i <= I915_EXEC_RING_MASK);
> >>
> >> ?
> > 
> > I can add that, but it would be redundant as the list would have
> > never been created otherwise... anyway, better be safe than sorry :)
> 
> Yes I know, I wrote that because I was suggesting to remove the 64 
> engine limit from the query and just have it in the engine map.
> 
> But as said if you already discussed that point then leave it.
> 
> > BTW, given my natural confusion between 'require' and 'assert',
> > you meant 'assert', right?
> 
> I meant require. But I don't know either, it's so hard to choose 
> sometimes. :)
> 
> >>> +           ctx_engine->class_instance[i].engine_class = e2->class;
> >>> +           ctx_engine->class_instance[i].engine_instance = e2->instance;
> >>> +   }
> >>> +
> >>> +   ctx_param.size = offsetof(typeof(*ctx_engine), class_instance[i + 1]);
> >>> +   ctx_param.value = to_user_pointer(ctx_engine);
> >>> +
> >>> +   gem_context_set_param(fd, &ctx_param);
> >>> +}
> >>> +
> >>> +/*
> >>> + * Initializes the list of engines.
> >>> + *
> >>> + * Returns:
> >>> + *
> >>> + *  - 0 in case of success and the get/set_param ioctls are implemented
> >>> + *  - -ENODEV in case of success but I915_CONTEXT_PARAM_ENGINES is not
> >>> + *    implemented in DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM ioctl.
> >>> + */
> >>> +static int init_engine_list(int fd)
> >>> +{
> >>> +   const char *class_names[] = { "rcs", "bcs", "vcs", "vecs" };
> >>> +   struct drm_i915_query_engine_info *query_engine;
> >>> +   unsigned char query_buffer[SIZEOF_QUERY] = { };
> >>> +   struct drm_i915_gem_context_param ctx_param = {
> >>> +           .param = I915_CONTEXT_PARAM_ENGINES,
> >>> +   };
> >>> +   int i;
> >>> +
> >>> +   /* the list is already initialized */
> >>> +   if (intel_active_engines2)
> >>> +           return gem_has_engine_topology() ? 0 : -ENODEV;
> >>> +
> >>> +   /*
> >>> +    * We check first whether the I915_CONTEXT_PARAM_ENGINES parameter is
> >>> +    * supported by the running kernel. If not, __gem_context_get_param()
> >>> +    * will return -EINVAL which, at this point, is not necessarily a
> >>> +    * failure but it means that we need to fall beck to polling the engines
> >>> +    * directly from intel_execution_engines2[].
> >>> +    *
> >>> +    * We will return -ENODEV with the meaning of missing interface
> >>> +    */
> >>> +   if (__gem_context_get_param(fd, &ctx_param)) {
> >>> +           intel_active_engines2 = intel_execution_engines2;
> >>> +           return -ENODEV;
> >>> +   }
> >>> +
> >>> +   query_engine = (struct drm_i915_query_engine_info *) query_buffer;
> >>> +   query_engines(fd, query_engine);
> >>
> >> Do a two stage query here - first ask for required buffer size, then
> >> allocate it and query:
> >>
> >>      size = query_engines(fd, NULL, 0);
> >>      query_engine = malloc(size);
> >>      query_engines(fd, query_engine, size);
> > 
> > As above :) this is how I did it at the beginning and with Chris
> > we agreed that 64 is big enough, and then we had some review
> > rounds on agreeing on buffer size, name, calculation and so
> > on.
> > 
> > Shall I move back? Honestly I like the double call, as well.
> 
> Leave it at least for now then.
> 
> >>> +
> >>> +   igt_assert(query_engine->num_engines < I915_EXEC_RING_MASK + 1);
> >>
> >> Remove this since we don't need to limit the size of the array during the
> >> query. It is only the engine map that has the limitation.
> > 
> > This came after one of the 10 rounds of review as well :)
> > It's indeed a bit redundant, It's mainly for the malloc,
> > to avoid crazy allocation in case something goes wrong.
> > 
> >>> +
> >>> +   intel_active_engines2 = malloc((query_engine->num_engines + 1) *
> >>> +                                  sizeof(*intel_active_engines2));
> >>> +   igt_assert(intel_active_engines2);
> >>> +
> >>> +   for (i = 0; i < query_engine->num_engines; i++) {
> >>> +           char *name;
> >>> +           int class = query_engine->engines[i].engine_class;
> >>> +           int instance = query_engine->engines[i].engine_instance;
> >>
> >> Could use __u16 to match uapi.
> > 
> > Sure!
> > 
> >>> +
> >>> +           intel_active_engines2[i].class = class;
> >>> +           intel_active_engines2[i].instance = instance;
> >>> +
> >>> +           /* if we don't recognise the class, then we mark it as "unk" */
> >>> +           if (class >= ARRAY_SIZE(class_names) || !class_names[class])
> >>
> >> Second condition seems to be not needed at the moment.
> > 
> > Yes, of course, it must be a leftover.
> > 
> >>> +struct intel_execution_engine2 *get_active_engines(int fd)
> >>
> >> Unexport this one?
> > 
> > I thought someone might need it, I will do it static and rework
> > it with the bool gem_has_engine_topology() as they would become
> > very similar.
> > 
> >>> +{
> >>> +   if (init_engine_list(fd)) {
> >>> +           igt_info("using pre-allocated engine list\n");
> >>> +           return NULL;
> >>> +   }
> >>> +
> >>> +   return intel_active_engines2;
> >>> +}
> >>> +
> >>> +struct intel_execution_engine2 *gem_set_context_get_engines(int fd,
> >>> +                                                       uint32_t ctx_id)
> >>
> >> I find the name of this function really confusing (set get what?). Can I
> >> suggest __gem_prepare_context_engines or something like that?
> > 
> > The name means "set context and get engines", as it's a "get_"
> > kind of function. But as it came out, I have a very limited
> > imagination for names choice. I will call it
> > __gem_prepare_context_engines(), then.
> > 
> >>> +{
> >>> +   struct intel_execution_engine2 *active_engines = get_active_engines(fd);
> >>> +
> >>> +   if (!active_engines)
> >>> +           return intel_execution_engines2;
> >>
> >> So without engine discovery the function will not configure the engine map.
> >> How will the code inside for_each_engine2 be able to work then?
> > 
> > It's this part of the for_each_engine2 that would make it work:
> > 
> >   for_if (gem_has_engine_topology() || \
> >           gem_has_engine(fd, e2__->class, e2__->instance))
> > 
> > We had quite some discussions about backward compatibility and
> > the whole thing is designed to be backward compatible, otherwise,
> > I would have removed quite some code from the above.
> 
> Yes, I comment on that in the other reply.
> 
> >> I guess it's okay since we don't expect to see a kernel with ctx engine map
> >> support and no engine discovery but it feels a bit unnatural.
> >>
> >> But I think it effectively means you should have igt_require_gem_engine_list
> >> in here since it is otherwise not usable from the for_each_engine2 iterator.
> >>
> >>> +
> >>> +   set_ctx_param_engines(fd, ctx_id);
> >>
> >> You need to handle the use case where the context already has a map
> >> configured instead of overriding it. Should be easy.
> > 
> > Yes, this is relevant to your comment above, about the
> > igt_require(<new_api>). This part is checked in
> > 'get_active_engines(fd)', that returns NULL if we do not have the
> > new uapi and therefore it returns the old list of engines.
> > 
> > adding the igt_require() (asset?) would be redundant.
> > Am I missing any use case?
> 
> AFAIR Chris wanted it to support the use case where he configures the 
> engine map and passes the context to for_each_engine2. Maybe he changed 
> his mind?

I want to change engine maps on the fly, have multiple contexts with
different engines, and have multiple devices, and have it all work.
 
> It would be tricky to do since then there is no intel_active_engine 
> array to walk.. Could only define the iterator that the pointer to 
> engine is sometimes not valid (must be checked) and added index used to 
> submit. Not sure, depends if Chris still wants this feature.

Just construct the engine array in the iterator. DO NOT USE A STATIC
MAP! :)
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well
  2019-03-07 14:27       ` Tvrtko Ursulin
@ 2019-03-07 15:46         ` Andi Shyti
  2019-03-07 15:57           ` Andi Shyti
  2019-03-07 16:28           ` Tvrtko Ursulin
  0 siblings, 2 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-07 15:46 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: IGT dev, Andi Shyti

Hi Tvrtko,

yes, this patchset has grown and changed many times over the
review iterations and unfortunately, it's not very obvius.

> > > > With the new engine query method engines are reachable through
> > > > an index and context they are combined with.
> > > > 
> > > > The 'gem_has_ring()' becomes 'gem_context_has_engine()' that
> > > > requires the index that the engine is mapped within the driver.
> > > > 
> > > > The previous 'gem_has_ring()' function becomes a wrapper to the new
> > > > 'gem_context_has_engine()'.
> > > > 
> > > > Signed-off-by: Andi Shyti <andi.shyti@intel.com>
> > > > ---
> > > >    lib/ioctl_wrappers.c | 4 +++-
> > > >    lib/ioctl_wrappers.h | 4 +++-
> > > >    2 files changed, 6 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
> > > > index 39920f8707d2..a2597e282704 100644
> > > > --- a/lib/ioctl_wrappers.c
> > > > +++ b/lib/ioctl_wrappers.c
> > > > @@ -1252,7 +1252,7 @@ void igt_require_gem(int fd)
> > > >    	igt_require_f(err == 0, "Unresponsive i915/GEM device\n");
> > > >    }
> > > > -bool gem_has_ring(int fd, unsigned ring)
> > > > +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx)
> > > >    {
> > > >    	struct drm_i915_gem_execbuffer2 execbuf;
> > > >    	struct drm_i915_gem_exec_object2 exec;
> > > > @@ -1268,6 +1268,8 @@ bool gem_has_ring(int fd, unsigned ring)
> > > >    	execbuf.buffers_ptr = to_user_pointer(&exec);
> > > >    	execbuf.buffer_count = 1;
> > > >    	execbuf.flags = ring;
> > > > +	execbuf.rsvd1 = ctx;
> > > > +
> > > >    	return __gem_execbuf(fd, &execbuf) == -ENOENT;
> > > >    }
> > > > diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
> > > > index f0be26080da6..446e973b7449 100644
> > > > --- a/lib/ioctl_wrappers.h
> > > > +++ b/lib/ioctl_wrappers.h
> > > > @@ -142,11 +142,13 @@ bool gem_has_exec_fence(int fd);
> > > >    /* check functions which auto-skip tests by calling igt_skip() */
> > > >    void gem_require_caching(int fd);
> > > > -bool gem_has_ring(int fd, unsigned ring);
> > > > +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx);
> > > >    void gem_require_ring(int fd, unsigned ring);
> > > >    bool gem_has_mocs_registers(int fd);
> > > >    void gem_require_mocs_registers(int fd);
> > > > +#define gem_has_ring(fd, ring) gem_context_has_engine(fd, ring, 0)
> > > > +
> > > >    /* prime */
> > > >    struct local_dma_buf_sync {
> > > >    	uint64_t flags;
> > > > 
> > > 
> > > I don't understand why this. All current callers of gem_has_ring pass in eb
> > > flags and not an index so how it can work?
> > 
> > This is because of patch 3/6 this makes the for_each_engine2()
> > able to work with new and old api.
> 
> How does it do that? Maybe I am extra slow today..

We assume we have the old api (i.e. we use the current
intel_execution_engines2[] array):

#define for_each_engine2(fd, ctx) \
            ...
                   |---- the for_if() inverts the logic ----------|
                   V                                              V
                 for_if (gem_has_engine_topology() || \    <--- false
                         gem_has_engine(fd, e2__->class, e2__->instance)) <--- true

gem_has_engine() is the bit that will be called, which translates
class/instance to eb flag and calls gem_has_ring(fd, flags), which now is

#define gem_has_ring(fd, ring) gem_context_has_engine(fd, ring, 0) (*)

gem_context_has_engine() would work exactly as before and assign
ring to execbuf.flags and '0' to execbuf.rsvd1, nothing changes,
although the logic is a bit twisted (we still have discussion on
names with Chris :) ).

At the same time the "gem_set_context_get_engines()" (which means
set context and get engines) has returned
intel_execution_engines2[] and we iterate through the
preallocated engines.

It works exactly like for_each_engine(...), but using the new
"struct intel_execution_engine2" instead of the old "struct
intel_execution_engine".

If we have the new uapi, then we don't care, because
gem_has_engine_topology is true and we move forward:

#define for_each_engine2(fd, ctx) \
            ...
                 for_if (gem_has_engine_topology() || \    <--- true
                         gem_has_engine(fd, e2__->class, e2__->instance)) <--- does not matter

"gem_set_context_get_engines()" has returned the
"intel_active_engines2[]" array that we created by querying the
driver.

On the other hand, if you see the subtest "exec-ctx" (patch 6/6),
we call exactly the same function without goint through the
definition(*) and gem_context_has_engine(...) would work by
using the new api:

   gem_context_has_engine(fd, ++index_map, ctx_id));

index_map is assigned to execbuf.flags, while ctx_id is assigned
to execbuf.rsvd1.

This definition reduces quite some code, because I can use
gem_context_has_engine(...) for both indexed engines and not.

I don't know if I made myself clear, but if you want we can also
take this offline.

Andi

> How is the for_each_engine2 without a helper to get engine flags, or the
> index variable, supposed to be used if one wants to submit a batch to all
> engines:
> 
> for_each_engine2(...)
> 	eb(engine=??)
> 
> Both in legacy and engine discovery mode.
> 
> Regards,
> 
> Tvrtko
> 
> > Have I messed up the patch order?
> > 
> > Andi
> > 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well
  2019-03-07 15:46         ` Andi Shyti
@ 2019-03-07 15:57           ` Andi Shyti
  2019-03-07 16:28           ` Tvrtko Ursulin
  1 sibling, 0 replies; 30+ messages in thread
From: Andi Shyti @ 2019-03-07 15:57 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: IGT dev, Andi Shyti

Hi again :)

> #define gem_has_ring(fd, ring) gem_context_has_engine(fd, ring, 0) (*)

Another advantage of this define is that before we didn't have a
"gem_has_ring" by class/instance, now, with just a define, we do
and we are also back-compatible.

Andi

PS I will still move this define to 'lib/i915/gem_engine_topology.h'.
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library
  2019-03-07 14:59         ` Chris Wilson
@ 2019-03-07 16:25           ` Tvrtko Ursulin
  0 siblings, 0 replies; 30+ messages in thread
From: Tvrtko Ursulin @ 2019-03-07 16:25 UTC (permalink / raw)
  To: Chris Wilson, Andi Shyti; +Cc: IGT dev, Andi Shyti


On 07/03/2019 14:59, Chris Wilson wrote:
> Quoting Tvrtko Ursulin (2019-03-07 14:16:13)
>>
>> On 07/03/2019 13:42, Andi Shyti wrote:
>>> Hi Tvrtko,
>>>
>>>>> +#include "drmtest.h"
>>>>> +#include "igt_gt.h"
>>>>> +#include "ioctl_wrappers.h"
>>>>> +
>>>>> +#include "i915/gem_engine_topology.h"
>>>>> +
>>>>> +#define SIZEOF_CTX_PARAM   offsetof(struct i915_context_param_engines, \
>>>>> +                                   class_instance[I915_EXEC_RING_MASK + 1])
>>>>> +#define SIZEOF_QUERY               offsetof(struct drm_i915_query_engine_info, \
>>>>> +                                   engines[I915_EXEC_RING_MASK + 1])
>>>>
>>>> There is no relationship between I915_EXEC_RING_MASK and the number of
>>>> engines we can query. I'll suggest how I think it should work a bit later.
>>>
>>> I915_EXEC_RING_MASK is the upper limit checked in the driver,
>>> that's why I used that one. I could have hardcoded it to 64, but
>>> I wanted to keep it consistent to the driver.
>>
>> I'll argue with Chris to remove this limit from the engine map (come eb3
>> might not be relevant any more) - nevertheless the query does not have
>> this limit so I think it would be best to decouple the code from the start.
> 
> At the moment it fits in a u64 and I don't have to worry about flexible
> bitmaps. It's a bridge to cross later, we've plenty of space in the enum
> api to version a new interface.

Load balancing mask? Or engine->mask? Is the latter relevant when not 
load balancing?

>>
>>>>> +
>>>>> +static struct intel_execution_engine2 *intel_active_engines2;
>>>>> +
>>>>> +int __gem_query(int fd, struct drm_i915_query *q)
>>>>> +{
>>>>> +   int err = 0;
>>>>> +
>>>>> +   if (igt_ioctl(fd, DRM_IOCTL_I915_QUERY, q))
>>>>> +           err = -errno;
>>>>> +
>>>>> +   errno = 0;
>>>>> +   return err;
>>>>> +}
>>>>> +
>>>>> +void gem_query(int fd, struct drm_i915_query *q)
>>>>> +{
>>>>> +   igt_assert_eq(__gem_query(fd, q), 0);
>>>>> +}
>>>>
>>>> I would keep these two static if there are no external callers for now.
>>>
>>> Yes, I can make them static, I thought someone might need them in
>>> the future.
>>
>> Could be but it will be easy to export them at that point. I wanted to
>> keep the patch smallest possible for now so I can focus on reviewing the
>> important bits.
>>
>>>
>>>>> +
>>>>> +static void query_engines(int fd,
>>>>> +                     struct drm_i915_query_engine_info *query_engines)
>>>>> +{
>>>>> +   struct drm_i915_query_item item = { };
>>>>> +   struct drm_i915_query query = { };
>>>>> +
>>>>> +   item.query_id = DRM_I915_QUERY_ENGINE_INFO;
>>>>> +   query.items_ptr = to_user_pointer(&item);
>>>>> +   query.num_items = 1;
>>>>> +   item.length = SIZEOF_QUERY;
>>>>
>>>> I think making this function take buffer size and return the queried size
>>>> would be simplest.
>>>
>>> I haven't really understood, do you mean doing something like:
>>>
>>> static int query_engines(...., int size)
>>> {
>>>      [...]
>>>      return size;
>>> }
>>>
>>> or calling the gem_query twice, first time for getting the size
>>> and second time for allocating the necessary resources.
>>>
>>> Because in the first case, we have the size in query_engines, is
>>> that right?
>>>
>>> While if you mean the second case, this is how I did it at the
>>> very beginning, but then with Chris we agreed that 64
>>> (I915_EXEC_RING_MASK) is "big enough". If you are strong with it,
>>> I can revert it back.
>>
>> Hm.. what happened to the old Chris!? :)) I am not objecting that
>> strongly. Especially if you already changed it once then just leave it.
>> It can be changed later if someone gets the desire to tidy..
> 
> If I recall, my position is that you can have a fixed stack and then
> fallback to a heap. But for these interfaces where we have to return a
> heap pointer, we might as well use heaps and be flexible.
> 
>>
>>>>> +
>>>>> +   item.data_ptr = to_user_pointer(query_engines);
>>>>> +
>>>>> +   gem_query(fd, &query);
>>>>> +}
>>>>> +
>>>>> +bool gem_has_engine_topology(void)
>>>>> +{
>>>>> +   return intel_active_engines2 != intel_execution_engines2;
>>>>
>>>> A problem for the exported API if init_engine_list hasn't been called yet?
>>>> Maybe:
>>>>
>>>>       if (!intel_active_engines2)
>>>>               init_engine_list(fd);
>>>>
>>>>       return intel_active_engines2 != intel_execution_engines2;
>>>>
>>>> ?
>>>
>>> Yes, it's indeed prone to be misused, I would need to make a more
>>> generic way, because the two lines
>>>
>>>      if (!intel_active_engines2)
>>>             init_engine_list(fd);
>>>
>>> are called so many times that I'm having an overdose of them :)
>>
>> Yes the call chains and responsibilities do feel a bit unobvious.
> 
> I really don't want init_engine_list(fd) at all :) Ideally the query
> interface is cheap enough that it doesn't matter (other than debug noise
> in strace) and if we can't make it that cheap, it is cached in sensible
> scopes.

Maybe it would indeed be more future proof to enumerate every time 
before iterating, but we also don't necessarily have to do that right 
now. For instance I think the problem of test enumeration will likely 
come back to trouble us as long as we are not allowed to enumerate 
dynamically.

> That may be an igt_device class (i915_device subclass).

For something that needs to be delivered next week we have to be 
pragmatical and keep the wish list in check. :)

>>
>>>
>>>>> +}
>>>>> +
>>>>> +static void set_ctx_param_engines(int fd, uint32_t ctx_id)
>>>>> +{
>>>>> +   struct i915_context_param_engines *ctx_engine;
>>>>> +   struct drm_i915_gem_context_param ctx_param;
>>>>> +   const struct intel_execution_engine2 *e2;
>>>>> +   uint8_t buff[SIZEOF_CTX_PARAM] = { };
>>>>> +   int i;
>>>>> +
>>>>> +   if (!gem_has_engine_topology())
>>>>> +           return;
>>>>
>>>> AFAICS this can be assert here.
>>>
>>> I think this check is redundant as it's never going to happen.
>>> This function is 'static' and the calling function checks that
>>> already. I will remove it.
>>
>> Better to have it as assert but as you wish. I guess even without an
>> assert it would segfault when it tries to iterate intel_active_engines2.
>>
>>>
>>>>> +
>>>>> +   ctx_engine = (struct i915_context_param_engines *) buff;
>>>>> +
>>>>> +   ctx_param.ctx_id = ctx_id;
>>>>> +   ctx_param.param = I915_CONTEXT_PARAM_ENGINES;
>>>>> +
>>>>> +   ctx_engine->extensions = 0;
>>>>> +   for (i = 0, e2 = intel_active_engines2; e2->name; i++, e2++) {
>>>>
>>>> Here I think is the place where we check that the total number of engines
>>>> does not exceed the engine map execbuf index.
>>>>
>>>>       igt_require(i <= I915_EXEC_RING_MASK);
>>>>
>>>> ?
>>>
>>> I can add that, but it would be redundant as the list would have
>>> never been created otherwise... anyway, better be safe than sorry :)
>>
>> Yes I know, I wrote that because I was suggesting to remove the 64
>> engine limit from the query and just have it in the engine map.
>>
>> But as said if you already discussed that point then leave it.
>>
>>> BTW, given my natural confusion between 'require' and 'assert',
>>> you meant 'assert', right?
>>
>> I meant require. But I don't know either, it's so hard to choose
>> sometimes. :)
>>
>>>>> +           ctx_engine->class_instance[i].engine_class = e2->class;
>>>>> +           ctx_engine->class_instance[i].engine_instance = e2->instance;
>>>>> +   }
>>>>> +
>>>>> +   ctx_param.size = offsetof(typeof(*ctx_engine), class_instance[i + 1]);
>>>>> +   ctx_param.value = to_user_pointer(ctx_engine);
>>>>> +
>>>>> +   gem_context_set_param(fd, &ctx_param);
>>>>> +}
>>>>> +
>>>>> +/*
>>>>> + * Initializes the list of engines.
>>>>> + *
>>>>> + * Returns:
>>>>> + *
>>>>> + *  - 0 in case of success and the get/set_param ioctls are implemented
>>>>> + *  - -ENODEV in case of success but I915_CONTEXT_PARAM_ENGINES is not
>>>>> + *    implemented in DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM ioctl.
>>>>> + */
>>>>> +static int init_engine_list(int fd)
>>>>> +{
>>>>> +   const char *class_names[] = { "rcs", "bcs", "vcs", "vecs" };
>>>>> +   struct drm_i915_query_engine_info *query_engine;
>>>>> +   unsigned char query_buffer[SIZEOF_QUERY] = { };
>>>>> +   struct drm_i915_gem_context_param ctx_param = {
>>>>> +           .param = I915_CONTEXT_PARAM_ENGINES,
>>>>> +   };
>>>>> +   int i;
>>>>> +
>>>>> +   /* the list is already initialized */
>>>>> +   if (intel_active_engines2)
>>>>> +           return gem_has_engine_topology() ? 0 : -ENODEV;
>>>>> +
>>>>> +   /*
>>>>> +    * We check first whether the I915_CONTEXT_PARAM_ENGINES parameter is
>>>>> +    * supported by the running kernel. If not, __gem_context_get_param()
>>>>> +    * will return -EINVAL which, at this point, is not necessarily a
>>>>> +    * failure but it means that we need to fall beck to polling the engines
>>>>> +    * directly from intel_execution_engines2[].
>>>>> +    *
>>>>> +    * We will return -ENODEV with the meaning of missing interface
>>>>> +    */
>>>>> +   if (__gem_context_get_param(fd, &ctx_param)) {
>>>>> +           intel_active_engines2 = intel_execution_engines2;
>>>>> +           return -ENODEV;
>>>>> +   }
>>>>> +
>>>>> +   query_engine = (struct drm_i915_query_engine_info *) query_buffer;
>>>>> +   query_engines(fd, query_engine);
>>>>
>>>> Do a two stage query here - first ask for required buffer size, then
>>>> allocate it and query:
>>>>
>>>>       size = query_engines(fd, NULL, 0);
>>>>       query_engine = malloc(size);
>>>>       query_engines(fd, query_engine, size);
>>>
>>> As above :) this is how I did it at the beginning and with Chris
>>> we agreed that 64 is big enough, and then we had some review
>>> rounds on agreeing on buffer size, name, calculation and so
>>> on.
>>>
>>> Shall I move back? Honestly I like the double call, as well.
>>
>> Leave it at least for now then.
>>
>>>>> +
>>>>> +   igt_assert(query_engine->num_engines < I915_EXEC_RING_MASK + 1);
>>>>
>>>> Remove this since we don't need to limit the size of the array during the
>>>> query. It is only the engine map that has the limitation.
>>>
>>> This came after one of the 10 rounds of review as well :)
>>> It's indeed a bit redundant, It's mainly for the malloc,
>>> to avoid crazy allocation in case something goes wrong.
>>>
>>>>> +
>>>>> +   intel_active_engines2 = malloc((query_engine->num_engines + 1) *
>>>>> +                                  sizeof(*intel_active_engines2));
>>>>> +   igt_assert(intel_active_engines2);
>>>>> +
>>>>> +   for (i = 0; i < query_engine->num_engines; i++) {
>>>>> +           char *name;
>>>>> +           int class = query_engine->engines[i].engine_class;
>>>>> +           int instance = query_engine->engines[i].engine_instance;
>>>>
>>>> Could use __u16 to match uapi.
>>>
>>> Sure!
>>>
>>>>> +
>>>>> +           intel_active_engines2[i].class = class;
>>>>> +           intel_active_engines2[i].instance = instance;
>>>>> +
>>>>> +           /* if we don't recognise the class, then we mark it as "unk" */
>>>>> +           if (class >= ARRAY_SIZE(class_names) || !class_names[class])
>>>>
>>>> Second condition seems to be not needed at the moment.
>>>
>>> Yes, of course, it must be a leftover.
>>>
>>>>> +struct intel_execution_engine2 *get_active_engines(int fd)
>>>>
>>>> Unexport this one?
>>>
>>> I thought someone might need it, I will do it static and rework
>>> it with the bool gem_has_engine_topology() as they would become
>>> very similar.
>>>
>>>>> +{
>>>>> +   if (init_engine_list(fd)) {
>>>>> +           igt_info("using pre-allocated engine list\n");
>>>>> +           return NULL;
>>>>> +   }
>>>>> +
>>>>> +   return intel_active_engines2;
>>>>> +}
>>>>> +
>>>>> +struct intel_execution_engine2 *gem_set_context_get_engines(int fd,
>>>>> +                                                       uint32_t ctx_id)
>>>>
>>>> I find the name of this function really confusing (set get what?). Can I
>>>> suggest __gem_prepare_context_engines or something like that?
>>>
>>> The name means "set context and get engines", as it's a "get_"
>>> kind of function. But as it came out, I have a very limited
>>> imagination for names choice. I will call it
>>> __gem_prepare_context_engines(), then.
>>>
>>>>> +{
>>>>> +   struct intel_execution_engine2 *active_engines = get_active_engines(fd);
>>>>> +
>>>>> +   if (!active_engines)
>>>>> +           return intel_execution_engines2;
>>>>
>>>> So without engine discovery the function will not configure the engine map.
>>>> How will the code inside for_each_engine2 be able to work then?
>>>
>>> It's this part of the for_each_engine2 that would make it work:
>>>
>>>    for_if (gem_has_engine_topology() || \
>>>            gem_has_engine(fd, e2__->class, e2__->instance))
>>>
>>> We had quite some discussions about backward compatibility and
>>> the whole thing is designed to be backward compatible, otherwise,
>>> I would have removed quite some code from the above.
>>
>> Yes, I comment on that in the other reply.
>>
>>>> I guess it's okay since we don't expect to see a kernel with ctx engine map
>>>> support and no engine discovery but it feels a bit unnatural.
>>>>
>>>> But I think it effectively means you should have igt_require_gem_engine_list
>>>> in here since it is otherwise not usable from the for_each_engine2 iterator.
>>>>
>>>>> +
>>>>> +   set_ctx_param_engines(fd, ctx_id);
>>>>
>>>> You need to handle the use case where the context already has a map
>>>> configured instead of overriding it. Should be easy.
>>>
>>> Yes, this is relevant to your comment above, about the
>>> igt_require(<new_api>). This part is checked in
>>> 'get_active_engines(fd)', that returns NULL if we do not have the
>>> new uapi and therefore it returns the old list of engines.
>>>
>>> adding the igt_require() (asset?) would be redundant.
>>> Am I missing any use case?
>>
>> AFAIR Chris wanted it to support the use case where he configures the
>> engine map and passes the context to for_each_engine2. Maybe he changed
>> his mind?
> 
> I want to change engine maps on the fly, have multiple contexts with
> different engines, and have multiple devices, and have it all work.
>   
>> It would be tricky to do since then there is no intel_active_engine
>> array to walk.. Could only define the iterator that the pointer to
>> engine is sometimes not valid (must be checked) and added index used to
>> submit. Not sure, depends if Chris still wants this feature.
> 
> Just construct the engine array in the iterator. DO NOT USE A STATIC
> MAP! :)

Multiple devices I think we really need to punt for later.

In place engine discovery has some value to try if Andi wants to try.

Regards,

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

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

* Re: [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well
  2019-03-07 15:46         ` Andi Shyti
  2019-03-07 15:57           ` Andi Shyti
@ 2019-03-07 16:28           ` Tvrtko Ursulin
  2019-03-07 17:17             ` Andi Shyti
  1 sibling, 1 reply; 30+ messages in thread
From: Tvrtko Ursulin @ 2019-03-07 16:28 UTC (permalink / raw)
  To: Andi Shyti; +Cc: IGT dev, Andi Shyti


On 07/03/2019 15:46, Andi Shyti wrote:
> Hi Tvrtko,
> 
> yes, this patchset has grown and changed many times over the
> review iterations and unfortunately, it's not very obvius.
> 
>>>>> With the new engine query method engines are reachable through
>>>>> an index and context they are combined with.
>>>>>
>>>>> The 'gem_has_ring()' becomes 'gem_context_has_engine()' that
>>>>> requires the index that the engine is mapped within the driver.
>>>>>
>>>>> The previous 'gem_has_ring()' function becomes a wrapper to the new
>>>>> 'gem_context_has_engine()'.
>>>>>
>>>>> Signed-off-by: Andi Shyti <andi.shyti@intel.com>
>>>>> ---
>>>>>     lib/ioctl_wrappers.c | 4 +++-
>>>>>     lib/ioctl_wrappers.h | 4 +++-
>>>>>     2 files changed, 6 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
>>>>> index 39920f8707d2..a2597e282704 100644
>>>>> --- a/lib/ioctl_wrappers.c
>>>>> +++ b/lib/ioctl_wrappers.c
>>>>> @@ -1252,7 +1252,7 @@ void igt_require_gem(int fd)
>>>>>     	igt_require_f(err == 0, "Unresponsive i915/GEM device\n");
>>>>>     }
>>>>> -bool gem_has_ring(int fd, unsigned ring)
>>>>> +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx)
>>>>>     {
>>>>>     	struct drm_i915_gem_execbuffer2 execbuf;
>>>>>     	struct drm_i915_gem_exec_object2 exec;
>>>>> @@ -1268,6 +1268,8 @@ bool gem_has_ring(int fd, unsigned ring)
>>>>>     	execbuf.buffers_ptr = to_user_pointer(&exec);
>>>>>     	execbuf.buffer_count = 1;
>>>>>     	execbuf.flags = ring;
>>>>> +	execbuf.rsvd1 = ctx;
>>>>> +
>>>>>     	return __gem_execbuf(fd, &execbuf) == -ENOENT;
>>>>>     }
>>>>> diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
>>>>> index f0be26080da6..446e973b7449 100644
>>>>> --- a/lib/ioctl_wrappers.h
>>>>> +++ b/lib/ioctl_wrappers.h
>>>>> @@ -142,11 +142,13 @@ bool gem_has_exec_fence(int fd);
>>>>>     /* check functions which auto-skip tests by calling igt_skip() */
>>>>>     void gem_require_caching(int fd);
>>>>> -bool gem_has_ring(int fd, unsigned ring);
>>>>> +bool gem_context_has_engine(int fd, unsigned ring, unsigned ctx);
>>>>>     void gem_require_ring(int fd, unsigned ring);
>>>>>     bool gem_has_mocs_registers(int fd);
>>>>>     void gem_require_mocs_registers(int fd);
>>>>> +#define gem_has_ring(fd, ring) gem_context_has_engine(fd, ring, 0)
>>>>> +
>>>>>     /* prime */
>>>>>     struct local_dma_buf_sync {
>>>>>     	uint64_t flags;
>>>>>
>>>>
>>>> I don't understand why this. All current callers of gem_has_ring pass in eb
>>>> flags and not an index so how it can work?
>>>
>>> This is because of patch 3/6 this makes the for_each_engine2()
>>> able to work with new and old api.
>>
>> How does it do that? Maybe I am extra slow today..
> 
> We assume we have the old api (i.e. we use the current
> intel_execution_engines2[] array):
> 
> #define for_each_engine2(fd, ctx) \
>              ...
>                     |---- the for_if() inverts the logic ----------|
>                     V                                              V
>                   for_if (gem_has_engine_topology() || \    <--- false
>                           gem_has_engine(fd, e2__->class, e2__->instance)) <--- true
> 
> gem_has_engine() is the bit that will be called, which translates
> class/instance to eb flag and calls gem_has_ring(fd, flags), which now is
> 
> #define gem_has_ring(fd, ring) gem_context_has_engine(fd, ring, 0) (*)
> 
> gem_context_has_engine() would work exactly as before and assign
> ring to execbuf.flags and '0' to execbuf.rsvd1, nothing changes,
> although the logic is a bit twisted (we still have discussion on
> names with Chris :) ).
> 
> At the same time the "gem_set_context_get_engines()" (which means
> set context and get engines) has returned
> intel_execution_engines2[] and we iterate through the
> preallocated engines.
> 
> It works exactly like for_each_engine(...), but using the new
> "struct intel_execution_engine2" instead of the old "struct
> intel_execution_engine".
> 
> If we have the new uapi, then we don't care, because
> gem_has_engine_topology is true and we move forward:
> 
> #define for_each_engine2(fd, ctx) \
>              ...
>                   for_if (gem_has_engine_topology() || \    <--- true
>                           gem_has_engine(fd, e2__->class, e2__->instance)) <--- does not matter
> 
> "gem_set_context_get_engines()" has returned the
> "intel_active_engines2[]" array that we created by querying the
> driver.
> 
> On the other hand, if you see the subtest "exec-ctx" (patch 6/6),
> we call exactly the same function without goint through the
> definition(*) and gem_context_has_engine(...) would work by
> using the new api:
> 
>     gem_context_has_engine(fd, ++index_map, ctx_id));
> 
> index_map is assigned to execbuf.flags, while ctx_id is assigned
> to execbuf.rsvd1.
> 
> This definition reduces quite some code, because I can use
> gem_context_has_engine(...) for both indexed engines and not.
> 
> I don't know if I made myself clear, but if you want we can also
> take this offline.

I understand the loop itself works, but I wanted to find out how do I 
write a test which uses it and actually submits work.

for_each_engine2(fd, ctx) {
	...
	eb.flags = ???;
	eb.rsvd1 = ctx;

	gem_execbuf(fd, &eb);
}

What do I replace ??? with so the test works on old and new kernels?

Regards,

Tvrtko

>> How is the for_each_engine2 without a helper to get engine flags, or the
>> index variable, supposed to be used if one wants to submit a batch to all
>> engines:
>>
>> for_each_engine2(...)
>> 	eb(engine=??)
>>
>> Both in legacy and engine discovery mode.
>>
>> Regards,
>>
>> Tvrtko
>>
>>> Have I messed up the patch order?
>>>
>>> Andi
>>>
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well
  2019-03-07 16:28           ` Tvrtko Ursulin
@ 2019-03-07 17:17             ` Andi Shyti
  2019-03-08  6:59               ` Tvrtko Ursulin
  0 siblings, 1 reply; 30+ messages in thread
From: Andi Shyti @ 2019-03-07 17:17 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: IGT dev, Andi Shyti

> I understand the loop itself works, but I wanted to find out how do I write
> a test which uses it and actually submits work.
> 
> for_each_engine2(fd, ctx) {
> 	...
> 	eb.flags = ???;
> 	eb.rsvd1 = ctx;
> 
> 	gem_execbuf(fd, &eb);
> }
> 
> What do I replace ??? with so the test works on old and new kernels?

I guess it would be:

  index_map = 0;
  for_each_engine2(fd, ctx) {
      ...
      eb.flags = ++index_map;
      eb.rsvd1 = ctx;

      gem_execbuf(fd, &eb);
  }

for_each_engine2 is just responsible for iterating through
engines. (*)

while for the current api it would be:

  for_each_engine2(fd, 0) {
      eb.flags = gem_class_instance_to_eb_flags(fd, e2__->class, e2__->instance));
      eb.rsvd1 = 0;
  }

There definitely are better way for doing the
for_each_engine(...) but I think this is the most consistent to
the way things are done now.

In my opinion, next step would be, indeed, to get rid of all
legacy and have a single for_each_engine(...) that works with
everything.

But for this, at my current understanding, we need some
re-architecturing of igt (and possibly using dynamic lists of
engines as Chris pointed out).

Once this patch gets in, I can start looking at the next steps,
but in one go, we would get everything in only at "[PATCH v1174]" :)

Andi

(*) Some extra code would be required to increment index_map
into the for_each_engine2(), Chris was suggesting, indeed, an
iter structure (or we can use some other 'C' tricks that would
make the code quite unreadable).
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well
  2019-03-07 17:17             ` Andi Shyti
@ 2019-03-08  6:59               ` Tvrtko Ursulin
  0 siblings, 0 replies; 30+ messages in thread
From: Tvrtko Ursulin @ 2019-03-08  6:59 UTC (permalink / raw)
  To: Andi Shyti; +Cc: IGT dev, Andi Shyti


On 07/03/2019 17:17, Andi Shyti wrote:
>> I understand the loop itself works, but I wanted to find out how do I write
>> a test which uses it and actually submits work.
>>
>> for_each_engine2(fd, ctx) {
>> 	...
>> 	eb.flags = ???;
>> 	eb.rsvd1 = ctx;
>>
>> 	gem_execbuf(fd, &eb);
>> }
>>
>> What do I replace ??? with so the test works on old and new kernels?
> 
> I guess it would be:
> 
>    index_map = 0;
>    for_each_engine2(fd, ctx) {
>        ...
>        eb.flags = ++index_map;
>        eb.rsvd1 = ctx;
> 
>        gem_execbuf(fd, &eb);
>    }
> 
> for_each_engine2 is just responsible for iterating through
> engines. (*)
> 
> while for the current api it would be:
> 
>    for_each_engine2(fd, 0) {
>        eb.flags = gem_class_instance_to_eb_flags(fd, e2__->class, e2__->instance));
>        eb.rsvd1 = 0;
>    }

So as I was pointing out it is not possible to write a test which works 
with same code on both old and new kernels? Which makes me ask - what is 
the point of making the iterator backward compatible?

IMHO we either drop the backward compatible goal or make some additions 
to enable writing truly agnostic tests. Maybe along the lines of:

for_each_engine2(fd, ctx, i) {
	...
	gem_set_execbuf_engine(&eb, fd, ctx, e2, i);
	...

    	gem_execbuf(fd, &eb);
}

void gem_set_execbuf_engine(...)
{
	if (gem_has_discovered_engines() /* simple pointer check, no ioctl */) {
		eb->rsvd1 = ctx;
		eb->flags |= i;
	} else {
		eb->flags |= gem_class_instance_to_eb_flags(...);
	}
}

A bit longish parameter list for the helper but I don't have better 
ideas at the moment.

Regards,

Tvrtko

> There definitely are better way for doing the
> for_each_engine(...) but I think this is the most consistent to
> the way things are done now.
> 
> In my opinion, next step would be, indeed, to get rid of all
> legacy and have a single for_each_engine(...) that works with
> everything.
> 
> But for this, at my current understanding, we need some
> re-architecturing of igt (and possibly using dynamic lists of
> engines as Chris pointed out).
> 
> Once this patch gets in, I can start looking at the next steps,
> but in one go, we would get everything in only at "[PATCH v1174]" :)
> 
> Andi
> 
> (*) Some extra code would be required to increment index_map
> into the for_each_engine2(), Chris was suggesting, indeed, an
> iter structure (or we can use some other 'C' tricks that would
> make the code quite unreadable).
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

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

* Re: [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines
  2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines Andi Shyti
  2019-03-05 13:36   ` Chris Wilson
  2019-03-07 12:07   ` Tvrtko Ursulin
@ 2019-03-08  7:09   ` Tvrtko Ursulin
  2 siblings, 0 replies; 30+ messages in thread
From: Tvrtko Ursulin @ 2019-03-08  7:09 UTC (permalink / raw)
  To: Andi Shyti, IGT dev; +Cc: Andi Shyti


On 05/03/2019 13:16, Andi Shyti wrote:
> 'for_each_engine2()' defines a loop through the gpu engines.
> 
> It can work with both active and pre-defined engines.
> 
> In case we are looping through active engines (i.e. the running
> kernel has the query and get/setparam ioctls), the
> intel_active_engines2 points to an array that contains only the
> list engines dynamically allocated after having interrogated the
> driver.
> 
> While, if we are looping through pre-defined engines,
> intel_active_engines2 points to the 'intel_execution_engines2'
> array and works exactly as for_each_engine() but using the
> new 'struct intel_execution_engine2' data type.
> 
> Signed-off-by: Andi Shyti <andi.shyti@intel.com>
> ---
>   lib/igt_gt.h | 8 ++++++++
>   1 file changed, 8 insertions(+)
> 
> diff --git a/lib/igt_gt.h b/lib/igt_gt.h
> index f4bd6c22a81a..f8bdaa62899f 100644
> --- a/lib/igt_gt.h
> +++ b/lib/igt_gt.h
> @@ -30,6 +30,8 @@
>   
>   #include "i915_drm.h"
>   
> +#include "i915/gem_engine_topology.h"
> +
>   void igt_require_hang_ring(int fd, int ring);
>   
>   typedef struct igt_hang {
> @@ -86,6 +88,12 @@ extern const struct intel_execution_engine {
>   	     e__++) \
>   		for_if (gem_ring_has_physical_engine(fd__, flags__ = e__->exec_id | e__->flags))
>   
> +#define for_each_engine2(fd, ctx) \
> +		for (struct intel_execution_engine2 *e2__ = \
> +		     gem_set_context_get_engines(fd, ctx); e2__->name; e2__++) \
> +			for_if (gem_has_engine_topology() || \
> +				gem_has_engine(fd, e2__->class, e2__->instance))
> +
>   bool gem_ring_is_physical_engine(int fd, unsigned int ring);
>   bool gem_ring_has_physical_engine(int fd, unsigned int ring);
>   
> 

Btw maybe you can just replace existing for_each_engine_class_instance 
with new code. Only one test uses it at the moment so it should be 
manageable.

(The double underscore version you leave to always work off the static 
list for test enumeration.)

Regards,

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

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

end of thread, other threads:[~2019-03-08  7:09 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-05 13:16 [igt-dev] [RFC PATCH v10 0/6] new engine discovery interface Andi Shyti
2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 1/6] include/drm-uapi: import i915_drm.h header file Andi Shyti
2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 2/6] lib/i915: add gem_engine_topology library Andi Shyti
2019-03-05 13:24   ` Chris Wilson
2019-03-07 13:00     ` Andi Shyti
2019-03-07 12:05   ` Tvrtko Ursulin
2019-03-07 13:42     ` Andi Shyti
2019-03-07 14:16       ` Tvrtko Ursulin
2019-03-07 14:59         ` Chris Wilson
2019-03-07 16:25           ` Tvrtko Ursulin
2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 3/6] lib/igt_gt: use for_each_engine2 to loop through engines Andi Shyti
2019-03-05 13:36   ` Chris Wilson
2019-03-07 12:07   ` Tvrtko Ursulin
2019-03-07 12:27     ` Tvrtko Ursulin
2019-03-07 13:52       ` Andi Shyti
2019-03-08  7:09   ` Tvrtko Ursulin
2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 4/6] lib: ioctl_wrappers: reach engines by index as well Andi Shyti
2019-03-05 13:27   ` Chris Wilson
2019-03-07 12:10   ` Tvrtko Ursulin
2019-03-07 13:54     ` Andi Shyti
2019-03-07 14:27       ` Tvrtko Ursulin
2019-03-07 15:46         ` Andi Shyti
2019-03-07 15:57           ` Andi Shyti
2019-03-07 16:28           ` Tvrtko Ursulin
2019-03-07 17:17             ` Andi Shyti
2019-03-08  6:59               ` Tvrtko Ursulin
2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 5/6] lib: move gem_context_has_engine from ioctl_wrappers to gem_context Andi Shyti
2019-03-05 13:16 ` [igt-dev] [RFC PATCH v10 6/6] tests: gem_exec_basic: add "exec-ctx" buffer execution demo test Andi Shyti
2019-03-05 14:13 ` [igt-dev] ✓ Fi.CI.BAT: success for new engine discovery interface Patchwork
2019-03-05 15:22 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork

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.