[igt-dev] [PATCH v15 4/5] lib/i915: add gem_engine_topology library and for_each loop definition
Tvrtko Ursulin
tvrtko.ursulin at linux.intel.com
Fri Mar 22 09:58:37 UTC 2019
On 21/03/2019 16:05, 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 access point is the 'intel_init_engine_list()'
> function that, everytime is called, generates the list of active
> engines and returns them in a 'struct intel_engine_data'. The
> structure contains only the engines that are actively present in
> the GPU.
>
> The function can work in both the cases that the query and
> getparam ioctls are implemented or not by the running kernel. In
> case they are implemented, a query is made to the driver to fetch
> the list of active engines. In case they are not implemented, the
> list is taken from the 'intel_execution_engines2' array and
> stored only after checking their presence.
>
> The gem_engine_topology library provides some iteration helpers:
>
> - intel_get_current_engine(): provides the current engine in the
> iteration.
>
> - intel_get_current_physical_engine(): provides the current
> physical engine, if the current engine is a virtual engine,
> it moves forward until it finds a physical engine.
>
> - intel_next_engine() it just increments the counter so that it
> points to the next engine.
>
> Extend the 'for_each_engine_class_instance' so that it can loop
> using the new 'intel_init_engine_list()' and rename it to
> 'for_each_context_engine'.
>
> Move '__for_each_engine_class_instance' to gem_engine_topology.h
> and rename it to '__for_each_static_engine'.
>
> Update accordingly tests/perf_pmu.c to use correctly the new
> for_each lopps.
>
> Signed-off-by: Andi Shyti <andi.shyti at intel.com>
> ---
> lib/Makefile.sources | 2 +
> lib/i915/gem_engine_topology.c | 222 +++++++++++++++++++++++++++++++++
> lib/i915/gem_engine_topology.h | 63 ++++++++++
> lib/igt.h | 1 +
> lib/igt_gt.h | 8 +-
> lib/meson.build | 1 +
> tests/perf_pmu.c | 12 +-
> 7 files changed, 296 insertions(+), 13 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..1144c49a1993
> --- /dev/null
> +++ b/lib/i915/gem_engine_topology.c
> @@ -0,0 +1,222 @@
> +/*
> + * 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 "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 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;
> +}
> +
> +static 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,
> + int length)
> +{
> + 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 = length;
> +
> + item.data_ptr = to_user_pointer(query_engines);
> +
> + gem_query(fd, &query);
> +}
> +
> +static void ctx_map_engines(int fd, struct intel_engine_data *ed,
> + struct drm_i915_gem_context_param *ctx_param)
> +{
> + struct i915_context_param_engines *ctx_engine =
> + (struct i915_context_param_engines*) ctx_param->value;
> + int i = 0;
> +
> + for (typeof(ctx_engine->class_instance[0]) *p =
> + &ctx_engine->class_instance[0];
> + i < ed->nengines; i++, p++) {
> + p->engine_class = ed->engines[i].class;
> + p->engine_instance = ed->engines[i].instance;
> + }
> +
> + ctx_param->size = offsetof(typeof(*ctx_engine), class_instance[i]);
> +
> + gem_context_set_param(fd, ctx_param);
> +}
> +
> +static void init_engine(struct intel_execution_engine2 *e2, const char *name,
> + uint16_t class, uint16_t instance, uint64_t flags)
> +{
> + static const char *unknown_name = "unknown",
> + *virtual_name = "virtual";
> +
> + e2->class = class;
> + e2->instance = instance;
> + e2->flags = flags;
> +
> + if (class < 0 && instance < 0) {
> + e2->name = virtual_name;
> + } else {
> + const struct intel_execution_engine2 *__e2;
> +
> + __for_each_static_engine(__e2)
> + if (__e2->class == class && __e2->instance == instance)
> + break;
> +
> + e2->name = __e2->name ? __e2->name : unknown_name;
> + }
> +}
> +
> +static void query_engine_list(int fd, struct intel_engine_data *ed)
> +{
> + uint8_t query_buffer[SIZEOF_QUERY] = { };
> + struct drm_i915_query_engine_info *query_engine =
> + (struct drm_i915_query_engine_info *) query_buffer;
> + int i;
> +
> + query_engines(fd, query_engine, SIZEOF_QUERY);
> +
> + for (i = 0; i < query_engine->num_engines; i++)
> + init_engine(&ed->engines[i], NULL,
> + query_engine->engines[i].engine_class,
> + query_engine->engines[i].engine_instance, i);
> +
> + ed->nengines = query_engine->num_engines;
> +}
> +
> +struct intel_engine_data intel_init_engine_list(int fd, uint32_t ctx_id)
> +{
> + struct intel_engine_data engine_data = { };
> + uint8_t buff[SIZEOF_CTX_PARAM] = { };
> +
> + struct i915_context_param_engines *engines =
> + (struct i915_context_param_engines *) buff;
> +
> + struct drm_i915_gem_context_param param = {
> + .param = I915_CONTEXT_PARAM_ENGINES,
> + .ctx_id = ctx_id,
> + .size = SIZEOF_CTX_PARAM,
> + .value = to_user_pointer(engines),
> + };
> +
> + int i, ret;
> + unsigned int nengines;
> +
> + ret = __gem_context_get_param(fd, ¶m);
> +
> + nengines = param.size > sizeof(struct i915_context_param_engines) ?
> + (param.size - sizeof(struct i915_context_param_engines)) /
> + sizeof(engines->class_instance[0]) :
> + 0;
> +
> + if (nengines > I915_EXEC_RING_MASK + 1) {
> + engine_data.error = ret ? ret : -EINVAL;
> + return engine_data;
> + }
> +
> + if (__gem_context_get_param(fd, ¶m)) {
Why are you calling get_param twice btw?
Regards,
Tvrtko
> + /* if kernel does not support engine/context mapping */
> + const struct intel_execution_engine2 *e2;
> +
> + igt_debug("using pre-allocated engine list\n");
> +
> + __for_each_static_engine(e2) {
> + struct intel_execution_engine2 *__e2;
> +
> + __e2 = &engine_data.engines[engine_data.nengines];
> + __e2->flags = gem_class_instance_to_eb_flags(fd,
> + e2->class, e2->instance);
> +
> + if (!gem_has_ring(fd, __e2->flags))
> + continue;
> +
> + __e2->name = e2->name;
> + __e2->instance = e2->instance;
> + __e2->class = e2->class;
> + engine_data.nengines++;
> + }
> +
> + } else if (!param.size) {
> + /* else if context doesn't have mapped engines */
> + query_engine_list(fd, &engine_data);
> + ctx_map_engines(fd, &engine_data, ¶m);
> +
> + } else {
> + /* context has a list of mapped engines */
> +
> + for (i = 0; i < nengines; i++)
> + init_engine(&engine_data.engines[i], NULL,
> + engines->class_instance[i].engine_class,
> + engines->class_instance[i].engine_instance,
> + i);
> +
> + engine_data.nengines = i;
> + }
> +
> + return engine_data;
> +}
> +
> +struct intel_execution_engine2
> + *intel_get_current_engine(struct intel_engine_data *ed)
> +{
> + return (ed->n < ed->nengines) && !ed->error ?
> + &ed->engines[ed->n] :
> + NULL;
> +}
> +
> +void intel_next_engine(struct intel_engine_data *ed)
> +{
> + ed->n++;
> +}
> +
> +struct intel_execution_engine2
> + *intel_get_current_physical_engine(struct intel_engine_data *ed)
> +{
> + struct intel_execution_engine2 *e;
> +
> + for (e = intel_get_current_engine(ed);
> + e && !IS_PHYSICAL_ENGINE(e);
> + intel_next_engine(ed))
> + ;
> +
> + return e;
> +}
> diff --git a/lib/i915/gem_engine_topology.h b/lib/i915/gem_engine_topology.h
> new file mode 100644
> index 000000000000..f662a4601ecd
> --- /dev/null
> +++ b/lib/i915/gem_engine_topology.h
> @@ -0,0 +1,63 @@
> +/*
> + * 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_ENGINE_TOPOLOGY_H
> +#define GEM_ENGINE_TOPOLOGY_H
> +
> +#include "igt_gt.h"
> +#include "i915_drm.h"
> +
> +struct intel_engine_data {
> + uint32_t nengines;
> + uint32_t n;
> + int error;
> + struct intel_execution_engine2 engines[I915_EXEC_RING_MASK + 1];
> +};
> +
> +struct intel_engine_data intel_init_engine_list(int fd, uint32_t ctx_id);
> +
> +/* iteration functions */
> +struct intel_execution_engine2
> + *intel_get_current_engine(struct intel_engine_data *ed);
> +struct intel_execution_engine2
> + *intel_get_current_physical_engine(struct intel_engine_data *ed);
> +void intel_next_engine(struct intel_engine_data *ed);
> +
> +#define IS_PHYSICAL_ENGINE(e2) ((e2->class >= 0) && (e2->instance >= 0))
> +
> +/* needs to replace "__for_each_engine_class_instance" when conflicts are fixed */
> +#define __for_each_static_engine(e__) \
> + for ((e__) = intel_execution_engines2; (e__)->name; (e__)++)
> +
> +#define for_each_context_engine(fd__, ctx__, e__) \
> + for (struct intel_engine_data i__ = intel_init_engine_list(fd__, ctx__); \
> + ((e__) = intel_get_current_engine(&i__)); \
> + intel_next_engine(&i__))
> +
> +/* needs to replace "for_each_physical_engine" when conflicts are fixed */
> +#define __for_each_physical_engine__(fd__, e__) \
> + for (struct intel_engine_data i__ = intel_init_engine_list(fd__, 0); \
> + ((e__) = intel_get_current_physical_engine(&i__)); \
> + intel_next_engine(&i__))
> +
> +#endif /* GEM_ENGINE_TOPOLOGY_H */
> diff --git a/lib/igt.h b/lib/igt.h
> index 6654a659c062..03f19ca2dfb6 100644
> --- a/lib/igt.h
> +++ b/lib/igt.h
> @@ -53,5 +53,6 @@
> #include "media_spin.h"
> #include "rendercopy.h"
> #include "i915/gem_mman.h"
> +#include "i915/gem_engine_topology.h"
>
> #endif /* IGT_H */
> diff --git a/lib/igt_gt.h b/lib/igt_gt.h
> index 475c0b3c3cc6..2a7032d4b262 100644
> --- a/lib/igt_gt.h
> +++ b/lib/igt_gt.h
> @@ -95,6 +95,7 @@ extern const struct intel_execution_engine2 {
> const char *name;
> int class;
> int instance;
> + uint64_t flags;
> } intel_execution_engines2[];
>
> unsigned int
> @@ -114,11 +115,4 @@ void gem_require_engine(int gem_fd,
> igt_require(gem_has_engine(gem_fd, class, instance));
> }
>
> -#define __for_each_engine_class_instance(e__) \
> - for ((e__) = intel_execution_engines2; (e__)->name; (e__)++)
> -
> -#define for_each_engine_class_instance(fd__, e__) \
> - for ((e__) = intel_execution_engines2; (e__)->name; (e__)++) \
> - for_if (gem_has_engine((fd__), (e__)->class, (e__)->instance))
> -
> #endif /* IGT_GT_H */
> 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',
> diff --git a/tests/perf_pmu.c b/tests/perf_pmu.c
> index 4f552bc2ae28..0e10bcfd1693 100644
> --- a/tests/perf_pmu.c
> +++ b/tests/perf_pmu.c
> @@ -434,7 +434,7 @@ busy_check_all(int gem_fd, const struct intel_execution_engine2 *e,
>
> i = 0;
> fd[0] = -1;
> - for_each_engine_class_instance(gem_fd, e_) {
> + for_each_context_engine(gem_fd, 0, e_) {
> if (e == e_)
> busy_idx = i;
>
> @@ -497,7 +497,7 @@ most_busy_check_all(int gem_fd, const struct intel_execution_engine2 *e,
> unsigned int idle_idx, i;
>
> i = 0;
> - for_each_engine_class_instance(gem_fd, e_) {
> + for_each_context_engine(gem_fd, 0, e_) {
> if (e == e_)
> idle_idx = i;
> else if (spin)
> @@ -554,7 +554,7 @@ all_busy_check_all(int gem_fd, const unsigned int num_engines,
> unsigned int i;
>
> i = 0;
> - for_each_engine_class_instance(gem_fd, e) {
> + for_each_context_engine(gem_fd, 0, e) {
> if (spin)
> __submit_spin_batch(gem_fd, spin, e, 64);
> else
> @@ -1683,7 +1683,7 @@ igt_main
> igt_require_gem(fd);
> igt_require(i915_type_id() > 0);
>
> - for_each_engine_class_instance(fd, e)
> + for_each_context_engine(fd, 0, e)
> num_engines++;
> }
>
> @@ -1693,7 +1693,7 @@ igt_main
> igt_subtest("invalid-init")
> invalid_init();
>
> - __for_each_engine_class_instance(e) {
> + __for_each_static_engine(e) {
> const unsigned int pct[] = { 2, 50, 98 };
>
> /**
> @@ -1897,7 +1897,7 @@ igt_main
> gem_quiescent_gpu(fd);
> }
>
> - __for_each_engine_class_instance(e) {
> + __for_each_static_engine(e) {
> igt_subtest_group {
> igt_fixture {
> gem_require_engine(render_fd,
>
More information about the igt-dev
mailing list