* [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
@ 2018-03-07 22:49 ` Chris Wilson
0 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-07 22:49 UTC (permalink / raw)
To: intel-gfx; +Cc: igt-dev
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
tests/Makefile.am | 2 +-
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 193 insertions(+), 1 deletion(-)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index edd689a4..f42641f6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
@@ -128,7 +129,6 @@ prime_self_import_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
prime_self_import_LDADD = $(LDADD) -lpthread
gem_userptr_blits_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_userptr_blits_LDADD = $(LDADD) -lpthread
-perf_pmu_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_wait_LDADD = $(LDADD) -lrt
kms_flip_LDADD = $(LDADD) -lrt -lpthread
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 05cdc1ef..06e729ef 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -59,6 +59,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_shared \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..a01ce01b
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 8
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ gem_context_set_param(fd, ¶m);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int delay)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(delay);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ gem_quiescent_gpu(fd);
+ measured = measure_frequency(pmu, 10000);
+ igt_info("Initial (idle) freq: %.1fMHz\n",measured);
+ igt_require(measured >= min - 50 && measured <= min + 50);
+
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ set_freq(fd, ctx, freq, freq);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+ }
+ gem_quiescent_gpu(fd);
+
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+
+ gem_quiescent_gpu(fd);
+ measured = measure_frequency(pmu, 10000);
+ igt_info("Final (idle) freq: %.1fMHz\n", measured);
+ igt_assert(measured >= min - 50 && measured <= min + 50);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+ }
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ if (e->exec_id == 0)
+ continue;
+
+ igt_subtest_f("%s%s", e->exec_id == 0 ? "basic-" : "", e->name) {
+ igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
+ single(fd, e);
+ }
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 58729231..f1271274 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -35,6 +35,7 @@ test_progs = [
'gem_ctx_bad_exec',
'gem_ctx_create',
'gem_ctx_exec',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [igt-dev] [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
@ 2018-03-07 22:49 ` Chris Wilson
0 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-07 22:49 UTC (permalink / raw)
To: intel-gfx; +Cc: igt-dev
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
tests/Makefile.am | 2 +-
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 193 insertions(+), 1 deletion(-)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index edd689a4..f42641f6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
@@ -128,7 +129,6 @@ prime_self_import_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
prime_self_import_LDADD = $(LDADD) -lpthread
gem_userptr_blits_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_userptr_blits_LDADD = $(LDADD) -lpthread
-perf_pmu_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_wait_LDADD = $(LDADD) -lrt
kms_flip_LDADD = $(LDADD) -lrt -lpthread
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 05cdc1ef..06e729ef 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -59,6 +59,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_shared \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..a01ce01b
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 8
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ gem_context_set_param(fd, ¶m);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int delay)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(delay);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ gem_quiescent_gpu(fd);
+ measured = measure_frequency(pmu, 10000);
+ igt_info("Initial (idle) freq: %.1fMHz\n",measured);
+ igt_require(measured >= min - 50 && measured <= min + 50);
+
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ set_freq(fd, ctx, freq, freq);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+ }
+ gem_quiescent_gpu(fd);
+
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+
+ gem_quiescent_gpu(fd);
+ measured = measure_frequency(pmu, 10000);
+ igt_info("Final (idle) freq: %.1fMHz\n", measured);
+ igt_assert(measured >= min - 50 && measured <= min + 50);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+ }
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ if (e->exec_id == 0)
+ continue;
+
+ igt_subtest_f("%s%s", e->exec_id == 0 ? "basic-" : "", e->name) {
+ igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
+ single(fd, e);
+ }
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 58729231..f1271274 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -35,6 +35,7 @@ test_progs = [
'gem_ctx_bad_exec',
'gem_ctx_create',
'gem_ctx_exec',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [igt-dev] ✗ Fi.CI.BAT: failure for igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-07 22:49 ` [igt-dev] " Chris Wilson
(?)
@ 2018-03-07 23:00 ` Patchwork
-1 siblings, 0 replies; 36+ messages in thread
From: Patchwork @ 2018-03-07 23:00 UTC (permalink / raw)
To: Chris Wilson; +Cc: igt-dev
== Series Details ==
Series: igt: Add gem_ctx_freq to exercise requesting freq on a ctx
URL : https://patchwork.freedesktop.org/series/39564/
State : failure
== Summary ==
Applying: igt: Add gem_ctx_freq to exercise requesting freq on a ctx
Patch failed at 0001 igt: Add gem_ctx_freq to exercise requesting freq on a ctx
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-07 22:49 ` [igt-dev] " Chris Wilson
@ 2018-03-08 0:13 ` Chris Wilson
-1 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-08 0:13 UTC (permalink / raw)
To: intel-gfx; +Cc: igt-dev
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
tests/Makefile.am | 1 +
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 338 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 341 insertions(+)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index dbc7be72..389f7fc7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4a81ac4a..3d079c42 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -58,6 +58,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_switch \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..e68d9dd9
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 8
+
+static int __set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ return __gem_context_set_param(fd, ¶m);
+}
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ igt_assert_eq(__set_freq(fd, ctx, min, max), 0);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int delay)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(delay);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ gem_quiescent_gpu(fd);
+ measured = measure_frequency(pmu, 10000);
+ igt_info("Initial (idle) freq: %.1fMHz\n",measured);
+ igt_require(measured >= min - 50 && measured <= min + 50);
+
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ set_freq(fd, ctx, freq, freq);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+ }
+ gem_quiescent_gpu(fd);
+
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+
+ gem_quiescent_gpu(fd);
+ measured = measure_frequency(pmu, 10000);
+ igt_info("Final (idle) freq: %.1fMHz\n", measured);
+ igt_assert(measured >= min - 50 && measured <= min + 50);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+}
+
+static void sandwich(int fd)
+{
+ uint32_t ctx = gem_context_create(fd);
+ unsigned int engine;
+ uint32_t min, max;
+ igt_spin_t *spin;
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ spin = igt_spin_batch_new(fd, ctx, 0, 0);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+ for_each_physical_engine(fd, engine) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = ctx,
+ };
+ double measured;
+
+ min += 50;
+ if (min > max)
+ break;
+
+ set_freq(fd, ctx, min, min);
+ gem_execbuf(fd, &eb);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("Measured %.1fMHz, expected %dMhz\n", measured, min);
+ igt_assert(measured > min - 100 && measured < min + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ gem_context_destroy(fd, ctx);
+ close(pmu);
+}
+
+static void invalid_param(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ igt_assert_eq(__set_freq(fd, 0, min - 50, max), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, min, max + 50), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, min + 50, min), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, max, max - 50), -EINVAL);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void idempotent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ set_freq(fd, 0, min, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void independent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+ uint32_t ctx[2];
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ ctx[0] = gem_context_create(fd);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ ctx[1] = gem_context_create(fd);
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx[1], max, max);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[1]);
+
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[0]);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+ }
+
+ igt_subtest("invalid")
+ invalid_param(fd);
+
+ igt_subtest("idempotent")
+ idempotent(fd);
+
+ igt_subtest("independent")
+ independent(fd);
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ if (e->exec_id == 0)
+ continue;
+
+ igt_subtest(e->name) {
+ igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
+ single(fd, e);
+ }
+ }
+
+ igt_subtest("sandwich")
+ sandwich(fd);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 58729231..f1271274 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -35,6 +35,7 @@ test_progs = [
'gem_ctx_bad_exec',
'gem_ctx_create',
'gem_ctx_exec',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [igt-dev] [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
@ 2018-03-08 0:13 ` Chris Wilson
0 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-08 0:13 UTC (permalink / raw)
To: intel-gfx; +Cc: igt-dev
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
tests/Makefile.am | 1 +
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 338 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 341 insertions(+)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index dbc7be72..389f7fc7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4a81ac4a..3d079c42 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -58,6 +58,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_switch \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..e68d9dd9
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 8
+
+static int __set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ return __gem_context_set_param(fd, ¶m);
+}
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ igt_assert_eq(__set_freq(fd, ctx, min, max), 0);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int delay)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(delay);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ gem_quiescent_gpu(fd);
+ measured = measure_frequency(pmu, 10000);
+ igt_info("Initial (idle) freq: %.1fMHz\n",measured);
+ igt_require(measured >= min - 50 && measured <= min + 50);
+
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ set_freq(fd, ctx, freq, freq);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+ }
+ gem_quiescent_gpu(fd);
+
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+
+ gem_quiescent_gpu(fd);
+ measured = measure_frequency(pmu, 10000);
+ igt_info("Final (idle) freq: %.1fMHz\n", measured);
+ igt_assert(measured >= min - 50 && measured <= min + 50);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+}
+
+static void sandwich(int fd)
+{
+ uint32_t ctx = gem_context_create(fd);
+ unsigned int engine;
+ uint32_t min, max;
+ igt_spin_t *spin;
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ spin = igt_spin_batch_new(fd, ctx, 0, 0);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+ for_each_physical_engine(fd, engine) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = ctx,
+ };
+ double measured;
+
+ min += 50;
+ if (min > max)
+ break;
+
+ set_freq(fd, ctx, min, min);
+ gem_execbuf(fd, &eb);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("Measured %.1fMHz, expected %dMhz\n", measured, min);
+ igt_assert(measured > min - 100 && measured < min + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ gem_context_destroy(fd, ctx);
+ close(pmu);
+}
+
+static void invalid_param(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ igt_assert_eq(__set_freq(fd, 0, min - 50, max), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, min, max + 50), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, min + 50, min), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, max, max - 50), -EINVAL);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void idempotent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ set_freq(fd, 0, min, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void independent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+ uint32_t ctx[2];
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ ctx[0] = gem_context_create(fd);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ ctx[1] = gem_context_create(fd);
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx[1], max, max);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[1]);
+
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[0]);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+ }
+
+ igt_subtest("invalid")
+ invalid_param(fd);
+
+ igt_subtest("idempotent")
+ idempotent(fd);
+
+ igt_subtest("independent")
+ independent(fd);
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ if (e->exec_id == 0)
+ continue;
+
+ igt_subtest(e->name) {
+ igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
+ single(fd, e);
+ }
+ }
+
+ igt_subtest("sandwich")
+ sandwich(fd);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 58729231..f1271274 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -35,6 +35,7 @@ test_progs = [
'gem_ctx_bad_exec',
'gem_ctx_create',
'gem_ctx_exec',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [igt-dev] ✓ Fi.CI.BAT: success for igt: Add gem_ctx_freq to exercise requesting freq on a ctx (rev2)
2018-03-07 22:49 ` [igt-dev] " Chris Wilson
` (2 preceding siblings ...)
(?)
@ 2018-03-08 0:42 ` Patchwork
-1 siblings, 0 replies; 36+ messages in thread
From: Patchwork @ 2018-03-08 0:42 UTC (permalink / raw)
To: Chris Wilson; +Cc: igt-dev
== Series Details ==
Series: igt: Add gem_ctx_freq to exercise requesting freq on a ctx (rev2)
URL : https://patchwork.freedesktop.org/series/39564/
State : success
== Summary ==
IGT patchset tested on top of latest successful build
b4689dce36d0fbd9aec70d5a4b077c43a6b9c254 igt: Remove gen7_forcewake_mt
with latest DRM-Tip kernel build CI_DRM_3892
fc93d196b8e4 drm-tip: 2018y-03m-07d-23h-55m-21s UTC integration manifest
Testlist changes:
+igt@gem_ctx_freq@blt
+igt@gem_ctx_freq@bsd
+igt@gem_ctx_freq@bsd1
+igt@gem_ctx_freq@bsd2
+igt@gem_ctx_freq@idempotent
+igt@gem_ctx_freq@independent
+igt@gem_ctx_freq@invalid
+igt@gem_ctx_freq@render
+igt@gem_ctx_freq@sandwich
+igt@gem_ctx_freq@vebox
---- Known issues:
Test kms_pipe_crc_basic:
Subgroup suspend-read-crc-pipe-b:
pass -> INCOMPLETE (fi-snb-2520m) fdo#103713
fdo#103713 https://bugs.freedesktop.org/show_bug.cgi?id=103713
fi-bdw-5557u total:288 pass:267 dwarn:0 dfail:0 fail:0 skip:21 time:425s
fi-bdw-gvtdvm total:288 pass:264 dwarn:0 dfail:0 fail:0 skip:24 time:431s
fi-blb-e6850 total:288 pass:223 dwarn:1 dfail:0 fail:0 skip:64 time:377s
fi-bsw-n3050 total:288 pass:242 dwarn:0 dfail:0 fail:0 skip:46 time:514s
fi-bwr-2160 total:288 pass:183 dwarn:0 dfail:0 fail:0 skip:105 time:284s
fi-bxt-dsi total:288 pass:258 dwarn:0 dfail:0 fail:0 skip:30 time:490s
fi-bxt-j4205 total:288 pass:259 dwarn:0 dfail:0 fail:0 skip:29 time:495s
fi-byt-j1900 total:288 pass:253 dwarn:0 dfail:0 fail:0 skip:35 time:484s
fi-byt-n2820 total:288 pass:249 dwarn:0 dfail:0 fail:0 skip:39 time:471s
fi-cfl-8700k total:288 pass:260 dwarn:0 dfail:0 fail:0 skip:28 time:406s
fi-cfl-s2 total:288 pass:262 dwarn:0 dfail:0 fail:0 skip:26 time:582s
fi-cfl-u total:288 pass:262 dwarn:0 dfail:0 fail:0 skip:26 time:510s
fi-elk-e7500 total:288 pass:229 dwarn:0 dfail:0 fail:0 skip:59 time:418s
fi-gdg-551 total:288 pass:179 dwarn:0 dfail:0 fail:1 skip:108 time:290s
fi-glk-1 total:288 pass:260 dwarn:0 dfail:0 fail:0 skip:28 time:518s
fi-hsw-4770 total:288 pass:261 dwarn:0 dfail:0 fail:0 skip:27 time:397s
fi-ilk-650 total:288 pass:228 dwarn:0 dfail:0 fail:0 skip:60 time:413s
fi-ivb-3520m total:288 pass:259 dwarn:0 dfail:0 fail:0 skip:29 time:459s
fi-ivb-3770 total:288 pass:255 dwarn:0 dfail:0 fail:0 skip:33 time:421s
fi-kbl-7500u total:288 pass:263 dwarn:1 dfail:0 fail:0 skip:24 time:468s
fi-kbl-7567u total:288 pass:268 dwarn:0 dfail:0 fail:0 skip:20 time:468s
fi-kbl-r total:288 pass:261 dwarn:0 dfail:0 fail:0 skip:27 time:510s
fi-pnv-d510 total:288 pass:222 dwarn:1 dfail:0 fail:0 skip:65 time:595s
fi-skl-6260u total:288 pass:268 dwarn:0 dfail:0 fail:0 skip:20 time:434s
fi-skl-6600u total:288 pass:261 dwarn:0 dfail:0 fail:0 skip:27 time:523s
fi-skl-6700hq total:288 pass:262 dwarn:0 dfail:0 fail:0 skip:26 time:535s
fi-skl-6700k2 total:288 pass:264 dwarn:0 dfail:0 fail:0 skip:24 time:503s
fi-skl-6770hq total:288 pass:268 dwarn:0 dfail:0 fail:0 skip:20 time:490s
fi-skl-guc total:288 pass:260 dwarn:0 dfail:0 fail:0 skip:28 time:421s
fi-skl-gvtdvm total:288 pass:265 dwarn:0 dfail:0 fail:0 skip:23 time:429s
fi-snb-2520m total:245 pass:211 dwarn:0 dfail:0 fail:0 skip:33
fi-snb-2600 total:288 pass:248 dwarn:0 dfail:0 fail:0 skip:40 time:399s
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_1079/issues.html
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-07 22:49 ` [igt-dev] " Chris Wilson
@ 2018-03-08 0:55 ` Antonio Argenziano
-1 siblings, 0 replies; 36+ messages in thread
From: Antonio Argenziano @ 2018-03-08 0:55 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: igt-dev
On 07/03/18 14:49, Chris Wilson wrote:
> Exercise some new API that allows applications to request that
> individual contexts are executed within a desired frequency range.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
> tests/Makefile.am | 2 +-
> tests/Makefile.sources | 1 +
> tests/gem_ctx_freq.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++
> tests/meson.build | 1 +
> 4 files changed, 193 insertions(+), 1 deletion(-)
> create mode 100644 tests/gem_ctx_freq.c
>
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index edd689a4..f42641f6 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> drm_import_export_LDADD = $(LDADD) -lpthread
> gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> gem_close_race_LDADD = $(LDADD) -lpthread
> +gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
> gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> gem_ctx_thrash_LDADD = $(LDADD) -lpthread
> gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> @@ -128,7 +129,6 @@ prime_self_import_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> prime_self_import_LDADD = $(LDADD) -lpthread
> gem_userptr_blits_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> gem_userptr_blits_LDADD = $(LDADD) -lpthread
> -perf_pmu_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
>
> gem_wait_LDADD = $(LDADD) -lrt
> kms_flip_LDADD = $(LDADD) -lrt -lpthread
> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
> index 05cdc1ef..06e729ef 100644
> --- a/tests/Makefile.sources
> +++ b/tests/Makefile.sources
> @@ -59,6 +59,7 @@ TESTS_progs = \
> gem_ctx_bad_exec \
> gem_ctx_create \
> gem_ctx_exec \
> + gem_ctx_freq \
> gem_ctx_isolation \
> gem_ctx_param \
> gem_ctx_shared \
> diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
> new file mode 100644
> index 00000000..a01ce01b
> --- /dev/null
> +++ b/tests/gem_ctx_freq.c
> @@ -0,0 +1,190 @@
> +/*
> + * Copyright © 2018 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 <unistd.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <errno.h>
> +#include <sys/stat.h>
> +#include <sys/ioctl.h>
> +#include <sys/time.h>
> +#include <time.h>
> +
> +#include "igt.h"
> +#include "igt_perf.h"
> +
> +#define LOCAL_CONTEXT_PARAM_FREQUENCY 8
> +
> +static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
> +{
> + struct drm_i915_gem_context_param param = {
> + .ctx_id = ctx,
> + .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
> + .value = (uint64_t)max << 32 | min,
> + };
> +
> + gem_context_set_param(fd, ¶m);
> +}
> +
> +static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
> +{
> + struct drm_i915_gem_context_param param = {
> + .ctx_id = ctx,
> + .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
> + };
> +
> + gem_context_get_param(fd, ¶m);
> +
> + *min = param.value & 0xffffffff;
> + *max = param.value >> 32;
> +}
> +
> +static double measure_frequency(int pmu, int delay)
> +{
> + uint64_t data[2];
> + uint64_t d_t, d_v;
> +
> + igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
> + d_v = -data[0];
> + d_t = -data[1];
> +
> + usleep(delay);
> +
> + igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
> + d_v += data[0];
> + d_t += data[1];
> +
> + return d_v * 1e9 / d_t;
> +}
> +
> +static void single(int fd, const struct intel_execution_engine *e)
> +{
> + const unsigned int engine = e->exec_id | e->flags;
> + uint32_t ctx = gem_context_create(fd);
> + uint32_t min, max;
> + double measured;
> + igt_spin_t *spin;
> + int pmu;
> +
> + get_freq(fd, ctx, &min, &max);
> + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
> +
> + gem_quiescent_gpu(fd);
> + measured = measure_frequency(pmu, 10000);
> + igt_info("Initial (idle) freq: %.1fMHz\n",measured);
> + igt_require(measured >= min - 50 && measured <= min + 50);
> +
> + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
> + set_freq(fd, ctx, freq, freq);
> +
> + gem_quiescent_gpu(fd);
> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> + usleep(10000);
> +
> + measured = measure_frequency(pmu, 50000);
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> +
> + igt_spin_batch_free(fd, spin);
> + igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
> + e->name, measured, freq);
> + igt_assert(measured > freq - 100 && measured < freq + 100);
> + }
> + gem_quiescent_gpu(fd);
Check frequency has gone back to ~min.
> +
I would suggest to split here into two sub-tests.
> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
> + igt_spin_t *kick;
> +
> + set_freq(fd, ctx, freq, freq);
> +
> + /*
> + * When requesting a new frequency on the currently
> + * executing context, it does not take effect until the
> + * next context switch. In this case, we trigger a lite
> + * restore.
Is this enforced by the ABI? If so, we should check that after
set_freq() nothing changed.
> + */
> + kick = __igt_spin_batch_new(fd, ctx, engine, 0);
> + igt_spin_batch_free(fd, spin);
> + spin = kick;
> +
> + usleep(10000);
> +
> + measured = measure_frequency(pmu, 50000);
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> +
> + igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
> + e->name, measured, freq);
> + igt_assert(measured > freq - 100 && measured < freq + 100);
> + }
> + igt_spin_batch_free(fd, spin);
> +
> + gem_quiescent_gpu(fd);
> + measured = measure_frequency(pmu, 10000);
> + igt_info("Final (idle) freq: %.1fMHz\n", measured);
> + igt_assert(measured >= min - 50 && measured <= min + 50);
> +
> + close(pmu);
> + gem_context_destroy(fd, ctx);
> +}
> +
> +static bool has_ctx_freq(int fd)
> +{
> + struct drm_i915_gem_context_param param = {
> + .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
> + };
> +
> + return __gem_context_get_param(fd, ¶m) == 0;
> +}
> +
> +igt_main
> +{
> + const struct intel_execution_engine *e;
> + int fd = -1;
> +
> + igt_fixture {
> + fd = drm_open_driver(DRIVER_INTEL);
> + igt_require_gem(fd);
> +
> + igt_require(has_ctx_freq(fd));
> + }
> +
> + igt_skip_on_simulation();
> +
> + for (e = intel_execution_engines; e->name; e++) {
> + if (e->exec_id == 0)
> + continue;
> +
> + igt_subtest_f("%s%s", e->exec_id == 0 ? "basic-" : "", e->name) {
I believe this is a typo, exec_id would never be 0 at this check. Maybe
it should have been ("basic-%s", e->name).
Thanks,
Antonio
> + igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
> + single(fd, e);
> + }
> + }
> +}
> diff --git a/tests/meson.build b/tests/meson.build
> index 58729231..f1271274 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -35,6 +35,7 @@ test_progs = [
> 'gem_ctx_bad_exec',
> 'gem_ctx_create',
> 'gem_ctx_exec',
> + 'gem_ctx_freq',
> 'gem_ctx_param',
> 'gem_ctx_switch',
> 'gem_ctx_thrash',
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [Intel-gfx] [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
@ 2018-03-08 0:55 ` Antonio Argenziano
0 siblings, 0 replies; 36+ messages in thread
From: Antonio Argenziano @ 2018-03-08 0:55 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: igt-dev
On 07/03/18 14:49, Chris Wilson wrote:
> Exercise some new API that allows applications to request that
> individual contexts are executed within a desired frequency range.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
> tests/Makefile.am | 2 +-
> tests/Makefile.sources | 1 +
> tests/gem_ctx_freq.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++
> tests/meson.build | 1 +
> 4 files changed, 193 insertions(+), 1 deletion(-)
> create mode 100644 tests/gem_ctx_freq.c
>
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index edd689a4..f42641f6 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> drm_import_export_LDADD = $(LDADD) -lpthread
> gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> gem_close_race_LDADD = $(LDADD) -lpthread
> +gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
> gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> gem_ctx_thrash_LDADD = $(LDADD) -lpthread
> gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> @@ -128,7 +129,6 @@ prime_self_import_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> prime_self_import_LDADD = $(LDADD) -lpthread
> gem_userptr_blits_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
> gem_userptr_blits_LDADD = $(LDADD) -lpthread
> -perf_pmu_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
>
> gem_wait_LDADD = $(LDADD) -lrt
> kms_flip_LDADD = $(LDADD) -lrt -lpthread
> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
> index 05cdc1ef..06e729ef 100644
> --- a/tests/Makefile.sources
> +++ b/tests/Makefile.sources
> @@ -59,6 +59,7 @@ TESTS_progs = \
> gem_ctx_bad_exec \
> gem_ctx_create \
> gem_ctx_exec \
> + gem_ctx_freq \
> gem_ctx_isolation \
> gem_ctx_param \
> gem_ctx_shared \
> diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
> new file mode 100644
> index 00000000..a01ce01b
> --- /dev/null
> +++ b/tests/gem_ctx_freq.c
> @@ -0,0 +1,190 @@
> +/*
> + * Copyright © 2018 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 <unistd.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <errno.h>
> +#include <sys/stat.h>
> +#include <sys/ioctl.h>
> +#include <sys/time.h>
> +#include <time.h>
> +
> +#include "igt.h"
> +#include "igt_perf.h"
> +
> +#define LOCAL_CONTEXT_PARAM_FREQUENCY 8
> +
> +static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
> +{
> + struct drm_i915_gem_context_param param = {
> + .ctx_id = ctx,
> + .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
> + .value = (uint64_t)max << 32 | min,
> + };
> +
> + gem_context_set_param(fd, ¶m);
> +}
> +
> +static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
> +{
> + struct drm_i915_gem_context_param param = {
> + .ctx_id = ctx,
> + .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
> + };
> +
> + gem_context_get_param(fd, ¶m);
> +
> + *min = param.value & 0xffffffff;
> + *max = param.value >> 32;
> +}
> +
> +static double measure_frequency(int pmu, int delay)
> +{
> + uint64_t data[2];
> + uint64_t d_t, d_v;
> +
> + igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
> + d_v = -data[0];
> + d_t = -data[1];
> +
> + usleep(delay);
> +
> + igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
> + d_v += data[0];
> + d_t += data[1];
> +
> + return d_v * 1e9 / d_t;
> +}
> +
> +static void single(int fd, const struct intel_execution_engine *e)
> +{
> + const unsigned int engine = e->exec_id | e->flags;
> + uint32_t ctx = gem_context_create(fd);
> + uint32_t min, max;
> + double measured;
> + igt_spin_t *spin;
> + int pmu;
> +
> + get_freq(fd, ctx, &min, &max);
> + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
> +
> + gem_quiescent_gpu(fd);
> + measured = measure_frequency(pmu, 10000);
> + igt_info("Initial (idle) freq: %.1fMHz\n",measured);
> + igt_require(measured >= min - 50 && measured <= min + 50);
> +
> + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
> + set_freq(fd, ctx, freq, freq);
> +
> + gem_quiescent_gpu(fd);
> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> + usleep(10000);
> +
> + measured = measure_frequency(pmu, 50000);
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> +
> + igt_spin_batch_free(fd, spin);
> + igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
> + e->name, measured, freq);
> + igt_assert(measured > freq - 100 && measured < freq + 100);
> + }
> + gem_quiescent_gpu(fd);
Check frequency has gone back to ~min.
> +
I would suggest to split here into two sub-tests.
> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
> + igt_spin_t *kick;
> +
> + set_freq(fd, ctx, freq, freq);
> +
> + /*
> + * When requesting a new frequency on the currently
> + * executing context, it does not take effect until the
> + * next context switch. In this case, we trigger a lite
> + * restore.
Is this enforced by the ABI? If so, we should check that after
set_freq() nothing changed.
> + */
> + kick = __igt_spin_batch_new(fd, ctx, engine, 0);
> + igt_spin_batch_free(fd, spin);
> + spin = kick;
> +
> + usleep(10000);
> +
> + measured = measure_frequency(pmu, 50000);
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> +
> + igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
> + e->name, measured, freq);
> + igt_assert(measured > freq - 100 && measured < freq + 100);
> + }
> + igt_spin_batch_free(fd, spin);
> +
> + gem_quiescent_gpu(fd);
> + measured = measure_frequency(pmu, 10000);
> + igt_info("Final (idle) freq: %.1fMHz\n", measured);
> + igt_assert(measured >= min - 50 && measured <= min + 50);
> +
> + close(pmu);
> + gem_context_destroy(fd, ctx);
> +}
> +
> +static bool has_ctx_freq(int fd)
> +{
> + struct drm_i915_gem_context_param param = {
> + .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
> + };
> +
> + return __gem_context_get_param(fd, ¶m) == 0;
> +}
> +
> +igt_main
> +{
> + const struct intel_execution_engine *e;
> + int fd = -1;
> +
> + igt_fixture {
> + fd = drm_open_driver(DRIVER_INTEL);
> + igt_require_gem(fd);
> +
> + igt_require(has_ctx_freq(fd));
> + }
> +
> + igt_skip_on_simulation();
> +
> + for (e = intel_execution_engines; e->name; e++) {
> + if (e->exec_id == 0)
> + continue;
> +
> + igt_subtest_f("%s%s", e->exec_id == 0 ? "basic-" : "", e->name) {
I believe this is a typo, exec_id would never be 0 at this check. Maybe
it should have been ("basic-%s", e->name).
Thanks,
Antonio
> + igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
> + single(fd, e);
> + }
> + }
> +}
> diff --git a/tests/meson.build b/tests/meson.build
> index 58729231..f1271274 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -35,6 +35,7 @@ test_progs = [
> 'gem_ctx_bad_exec',
> 'gem_ctx_create',
> 'gem_ctx_exec',
> + 'gem_ctx_freq',
> 'gem_ctx_param',
> 'gem_ctx_switch',
> 'gem_ctx_thrash',
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-08 0:55 ` [Intel-gfx] " Antonio Argenziano
@ 2018-03-08 1:18 ` Chris Wilson
-1 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-08 1:18 UTC (permalink / raw)
To: Antonio Argenziano, intel-gfx; +Cc: igt-dev
Quoting Antonio Argenziano (2018-03-08 00:55:47)
>
>
> On 07/03/18 14:49, Chris Wilson wrote:
> > +static void single(int fd, const struct intel_execution_engine *e)
> > +{
> > + const unsigned int engine = e->exec_id | e->flags;
> > + uint32_t ctx = gem_context_create(fd);
> > + uint32_t min, max;
> > + double measured;
> > + igt_spin_t *spin;
> > + int pmu;
> > +
> > + get_freq(fd, ctx, &min, &max);
> > + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
> > +
> > + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> > + igt_require(pmu >= 0);
> > +
> > + gem_quiescent_gpu(fd);
> > + measured = measure_frequency(pmu, 10000);
> > + igt_info("Initial (idle) freq: %.1fMHz\n",measured);
> > + igt_require(measured >= min - 50 && measured <= min + 50);
> > +
> > + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
> > + set_freq(fd, ctx, freq, freq);
> > +
> > + gem_quiescent_gpu(fd);
> > + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> > + usleep(10000);
> > +
> > + measured = measure_frequency(pmu, 50000);
> > + igt_debugfs_dump(fd, "i915_rps_boost_info");
> > +
> > + igt_spin_batch_free(fd, spin);
> > + igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
> > + e->name, measured, freq);
> > + igt_assert(measured > freq - 100 && measured < freq + 100);
> > + }
> > + gem_quiescent_gpu(fd);
>
> Check frequency has gone back to ~min.
It's not that interesting a test (covered already by pmu) as we
essentially lie anyway over idle.
> I would suggest to split here into two sub-tests.
>
> > + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> > + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
> > + igt_spin_t *kick;
> > +
> > + set_freq(fd, ctx, freq, freq);
> > +
> > + /*
> > + * When requesting a new frequency on the currently
> > + * executing context, it does not take effect until the
> > + * next context switch. In this case, we trigger a lite
> > + * restore.
>
> Is this enforced by the ABI?
Enforced? No. The comment is precisely because it's not checked on
calling whether the context is currently on the HW and trying hard to be
sure that no one expects us to do that check. i.e. that set_freq()
doesn't change frequency itself, but doesn't rule it out either as it
may appear to have that effect due to many external factors.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [igt-dev] [Intel-gfx] [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
@ 2018-03-08 1:18 ` Chris Wilson
0 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-08 1:18 UTC (permalink / raw)
To: Antonio Argenziano, intel-gfx; +Cc: igt-dev
Quoting Antonio Argenziano (2018-03-08 00:55:47)
>
>
> On 07/03/18 14:49, Chris Wilson wrote:
> > +static void single(int fd, const struct intel_execution_engine *e)
> > +{
> > + const unsigned int engine = e->exec_id | e->flags;
> > + uint32_t ctx = gem_context_create(fd);
> > + uint32_t min, max;
> > + double measured;
> > + igt_spin_t *spin;
> > + int pmu;
> > +
> > + get_freq(fd, ctx, &min, &max);
> > + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
> > +
> > + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> > + igt_require(pmu >= 0);
> > +
> > + gem_quiescent_gpu(fd);
> > + measured = measure_frequency(pmu, 10000);
> > + igt_info("Initial (idle) freq: %.1fMHz\n",measured);
> > + igt_require(measured >= min - 50 && measured <= min + 50);
> > +
> > + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
> > + set_freq(fd, ctx, freq, freq);
> > +
> > + gem_quiescent_gpu(fd);
> > + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> > + usleep(10000);
> > +
> > + measured = measure_frequency(pmu, 50000);
> > + igt_debugfs_dump(fd, "i915_rps_boost_info");
> > +
> > + igt_spin_batch_free(fd, spin);
> > + igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
> > + e->name, measured, freq);
> > + igt_assert(measured > freq - 100 && measured < freq + 100);
> > + }
> > + gem_quiescent_gpu(fd);
>
> Check frequency has gone back to ~min.
It's not that interesting a test (covered already by pmu) as we
essentially lie anyway over idle.
> I would suggest to split here into two sub-tests.
>
> > + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> > + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
> > + igt_spin_t *kick;
> > +
> > + set_freq(fd, ctx, freq, freq);
> > +
> > + /*
> > + * When requesting a new frequency on the currently
> > + * executing context, it does not take effect until the
> > + * next context switch. In this case, we trigger a lite
> > + * restore.
>
> Is this enforced by the ABI?
Enforced? No. The comment is precisely because it's not checked on
calling whether the context is currently on the HW and trying hard to be
sure that no one expects us to do that check. i.e. that set_freq()
doesn't change frequency itself, but doesn't rule it out either as it
may appear to have that effect due to many external factors.
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
^ permalink raw reply [flat|nested] 36+ messages in thread
* [igt-dev] ✗ Fi.CI.IGT: failure for igt: Add gem_ctx_freq to exercise requesting freq on a ctx (rev2)
2018-03-07 22:49 ` [igt-dev] " Chris Wilson
` (4 preceding siblings ...)
(?)
@ 2018-03-08 1:49 ` Patchwork
-1 siblings, 0 replies; 36+ messages in thread
From: Patchwork @ 2018-03-08 1:49 UTC (permalink / raw)
To: Chris Wilson; +Cc: igt-dev
== Series Details ==
Series: igt: Add gem_ctx_freq to exercise requesting freq on a ctx (rev2)
URL : https://patchwork.freedesktop.org/series/39564/
State : failure
== Summary ==
---- Possible new issues:
Test gem_exec_capture:
Subgroup capture-vebox:
pass -> FAIL (shard-apl)
---- Known issues:
Test gem_softpin:
Subgroup noreloc-s3:
skip -> PASS (shard-snb) fdo#103375
Test kms_chv_cursor_fail:
Subgroup pipe-b-128x128-bottom-edge:
pass -> DMESG-WARN (shard-snb) fdo#105185 +2
Test kms_flip:
Subgroup 2x-flip-vs-expired-vblank:
pass -> FAIL (shard-hsw) fdo#102887 +1
Subgroup 2x-plain-flip-ts-check:
fail -> PASS (shard-hsw) fdo#100368 +1
Test kms_frontbuffer_tracking:
Subgroup fbc-suspend:
fail -> PASS (shard-apl) fdo#101623
Test kms_rotation_crc:
Subgroup primary-rotation-180:
fail -> PASS (shard-snb) fdo#103925
fdo#103375 https://bugs.freedesktop.org/show_bug.cgi?id=103375
fdo#105185 https://bugs.freedesktop.org/show_bug.cgi?id=105185
fdo#102887 https://bugs.freedesktop.org/show_bug.cgi?id=102887
fdo#100368 https://bugs.freedesktop.org/show_bug.cgi?id=100368
fdo#101623 https://bugs.freedesktop.org/show_bug.cgi?id=101623
fdo#103925 https://bugs.freedesktop.org/show_bug.cgi?id=103925
shard-apl total:3471 pass:1820 dwarn:1 dfail:0 fail:8 skip:1640 time:12015s
shard-hsw total:3477 pass:1770 dwarn:1 dfail:0 fail:4 skip:1701 time:11919s
shard-snb total:3477 pass:1364 dwarn:2 dfail:0 fail:1 skip:2110 time:7170s
Blacklisted hosts:
shard-kbl total:3471 pass:1941 dwarn:7 dfail:0 fail:8 skip:1514 time:9363s
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_1079/shards.html
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-07 22:49 ` [igt-dev] " Chris Wilson
` (5 preceding siblings ...)
(?)
@ 2018-03-08 1:59 ` Chris Wilson
-1 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-08 1:59 UTC (permalink / raw)
To: intel-gfx
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
A few more test ideas.
---
tests/Makefile.am | 1 +
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 512 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 515 insertions(+)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index dbc7be72..389f7fc7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4a81ac4a..3d079c42 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -58,6 +58,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_switch \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..bd60837d
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,512 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 8
+
+static int __set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ return __gem_context_set_param(fd, ¶m);
+}
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ igt_assert_eq(__set_freq(fd, ctx, min, max), 0);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int delay)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(delay);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ gem_quiescent_gpu(fd);
+ measured = measure_frequency(pmu, 10000);
+ igt_info("Initial (idle) freq: %.1fMHz\n",measured);
+ igt_require(measured >= min - 50 && measured <= min + 50);
+
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ uint32_t cur, discard;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ gem_quiescent_gpu(fd);
+
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ uint32_t cur, discard;
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+
+ gem_quiescent_gpu(fd);
+ measured = measure_frequency(pmu, 10000);
+ igt_info("Final (idle) freq: %.1fMHz\n", measured);
+ igt_assert(measured >= min - 50 && measured <= min + 50);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+}
+
+static void inflight(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx, min, max, freq, discard;
+ double measured;
+ igt_spin_t *plug, *spin;
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ plug = igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+ for (int n = 0; n < 16; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = plug->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = gem_context_create(fd),
+ };
+ set_freq(fd, eb.rsvd1, min, min);
+ gem_execbuf(fd, &eb);
+ gem_context_destroy(fd, eb.rsvd1);
+ }
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(plug): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, min);
+ igt_assert(measured > min - 100 && measured < min + 100);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+
+ /* spin is now queued but not executing */
+ freq = (max + min) / 2;
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &freq, &discard);
+ gem_context_destroy(fd, ctx);
+ igt_spin_batch_end(plug);
+
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, plug->handle));
+ igt_spin_batch_free(fd, plug);
+
+ /* Now spin will execute */
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+
+ igt_spin_batch_free(fd, spin);
+ close(pmu);
+ gem_quiescent_gpu(fd);
+}
+
+static void sandwich(int fd)
+{
+ uint32_t ctx = gem_context_create(fd);
+ unsigned int engine;
+ uint32_t min, max;
+ igt_spin_t *spin;
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ spin = igt_spin_batch_new(fd, ctx, 0, 0);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+ for_each_physical_engine(fd, engine) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = ctx,
+ };
+ uint32_t cur, discard;
+ double measured;
+
+ min += 50;
+ if (min > max)
+ break;
+
+ set_freq(fd, ctx, min, min);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_execbuf(fd, &eb);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, 50000);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("Measured %.1fMHz, expected %dMhz\n", measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ gem_context_destroy(fd, ctx);
+ close(pmu);
+}
+
+static void smoketest(int fd, int timeout)
+{
+ unsigned int engines[16];
+ unsigned int nengine;
+ unsigned int engine;
+ igt_spin_t *spin[16] = {};
+ uint32_t min[16], max[16];
+ int n, pmu;
+
+ get_freq(fd, 0, &min[0], &max[0]);
+
+ nengine = 0;
+ for_each_physical_engine(fd, engine) {
+ if (nengine == ARRAY_SIZE(engines))
+ break;
+
+ min[nengine] = min[0];
+ max[nengine] = max[0];
+ engines[nengine] = engine;
+ nengine++;
+ }
+ igt_require(nengine);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ igt_until_timeout(timeout) {
+ uint32_t ctx, c_min, c_max;
+ igt_spin_t *kick;
+ double measured;
+
+ n = rand() % nengine;
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &c_min, &c_max);
+ c_min = rand() % (c_max - c_min) + c_min;
+ c_max = rand() % (c_max - c_min) + c_min;
+ set_freq(fd, ctx, c_min, c_max);
+ get_freq(fd, ctx, &c_min, &c_max);
+
+ igt_debug("Replacing (%d, %d) on engine %x with (%d, %d)\n",
+ min[n], max[n], n, c_min, c_max);
+
+ kick = __igt_spin_batch_new(fd, ctx, engines[n], 0);
+ igt_spin_batch_free(fd, spin[n]);
+ spin[n] = kick;
+
+ gem_context_destroy(fd, ctx);
+
+ min[n] = c_min;
+ max[n] = c_max;
+
+ for (n = 0; n < nengine; n++) {
+ igt_debug("[%d]: [%d, %d]\n", n, min[n], max[n]);
+ if (min[n] < c_min)
+ c_min = min[n];
+ if (max[n] > c_max)
+ c_max = max[n];
+ }
+ igt_assert(c_max >= c_min);
+
+ usleep(50000);
+ measured = measure_frequency(pmu, 50000);
+
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("Measured %.1fMHz, expected [%d, %d]Mhz\n",
+ measured, c_min, c_max);
+ igt_assert(measured > c_min - 100 && measured < c_max + 100);
+
+ /* Kick every engine to avoid hangcheck (bad rng) */
+ for (n = 0; n < nengine; n++) {
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, min[n], max[n]);
+
+ kick = __igt_spin_batch_new(fd, ctx, engines[n], 0);
+ igt_spin_batch_free(fd, spin[n]);
+ spin[n] = kick;
+
+ gem_context_destroy(fd, ctx);
+ }
+ }
+
+ for (n = 0; n < nengine; n++)
+ igt_spin_batch_free(fd, spin[n]);
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+}
+
+static void invalid_param(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ igt_assert_eq(__set_freq(fd, 0, min - 50, max), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, min, max + 50), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, min + 50, min), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, max, max - 50), -EINVAL);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void idempotent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ set_freq(fd, 0, min, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void independent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+ uint32_t ctx[2];
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ ctx[0] = gem_context_create(fd);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ ctx[1] = gem_context_create(fd);
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx[1], max, max);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[1]);
+
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[0]);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+ }
+
+ igt_subtest("invalid")
+ invalid_param(fd);
+
+ igt_subtest("idempotent")
+ idempotent(fd);
+
+ igt_subtest("independent")
+ independent(fd);
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ if (e->exec_id == 0)
+ continue;
+
+ igt_subtest_group {
+ igt_fixture {
+ igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
+ }
+
+ igt_subtest(e->name)
+ single(fd, e);
+ igt_subtest_f("%s-inflight", e->name)
+ inflight(fd, e);
+ }
+ }
+
+ igt_subtest("sandwich")
+ sandwich(fd);
+
+ igt_subtest("smoketest")
+ smoketest(fd, 20);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 58729231..f1271274 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -35,6 +35,7 @@ test_progs = [
'gem_ctx_bad_exec',
'gem_ctx_create',
'gem_ctx_exec',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 36+ messages in thread
* ✓ Fi.CI.BAT: success for igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-07 22:49 ` [igt-dev] " Chris Wilson
` (6 preceding siblings ...)
(?)
@ 2018-03-08 2:26 ` Patchwork
-1 siblings, 0 replies; 36+ messages in thread
From: Patchwork @ 2018-03-08 2:26 UTC (permalink / raw)
To: Chris Wilson; +Cc: intel-gfx
== Series Details ==
Series: igt: Add gem_ctx_freq to exercise requesting freq on a ctx
URL : https://patchwork.freedesktop.org/series/39571/
State : success
== Summary ==
IGT patchset tested on top of latest successful build
b4689dce36d0fbd9aec70d5a4b077c43a6b9c254 igt: Remove gen7_forcewake_mt
with latest DRM-Tip kernel build CI_DRM_3892
fc93d196b8e4 drm-tip: 2018y-03m-07d-23h-55m-21s UTC integration manifest
Testlist changes:
+igt@gem_ctx_freq@blt
+igt@gem_ctx_freq@blt-inflight
+igt@gem_ctx_freq@bsd
+igt@gem_ctx_freq@bsd1
+igt@gem_ctx_freq@bsd1-inflight
+igt@gem_ctx_freq@bsd2
+igt@gem_ctx_freq@bsd2-inflight
+igt@gem_ctx_freq@bsd-inflight
+igt@gem_ctx_freq@idempotent
+igt@gem_ctx_freq@independent
+igt@gem_ctx_freq@invalid
+igt@gem_ctx_freq@render
+igt@gem_ctx_freq@render-inflight
+igt@gem_ctx_freq@sandwich
+igt@gem_ctx_freq@smoketest
+igt@gem_ctx_freq@vebox
+igt@gem_ctx_freq@vebox-inflight
---- Known issues:
Test gem_mmap_gtt:
Subgroup basic-small-bo-tiledx:
fail -> PASS (fi-gdg-551) fdo#102575
Test prime_vgem:
Subgroup basic-fence-flip:
pass -> FAIL (fi-byt-j1900) fdo#104008
fdo#102575 https://bugs.freedesktop.org/show_bug.cgi?id=102575
fdo#104008 https://bugs.freedesktop.org/show_bug.cgi?id=104008
fi-bdw-5557u total:288 pass:267 dwarn:0 dfail:0 fail:0 skip:21 time:426s
fi-bdw-gvtdvm total:288 pass:264 dwarn:0 dfail:0 fail:0 skip:24 time:428s
fi-blb-e6850 total:288 pass:223 dwarn:1 dfail:0 fail:0 skip:64 time:379s
fi-bsw-n3050 total:288 pass:242 dwarn:0 dfail:0 fail:0 skip:46 time:504s
fi-bwr-2160 total:288 pass:183 dwarn:0 dfail:0 fail:0 skip:105 time:280s
fi-bxt-dsi total:288 pass:258 dwarn:0 dfail:0 fail:0 skip:30 time:488s
fi-bxt-j4205 total:288 pass:259 dwarn:0 dfail:0 fail:0 skip:29 time:492s
fi-byt-j1900 total:288 pass:252 dwarn:0 dfail:0 fail:1 skip:35 time:485s
fi-byt-n2820 total:288 pass:249 dwarn:0 dfail:0 fail:0 skip:39 time:474s
fi-cfl-8700k total:288 pass:260 dwarn:0 dfail:0 fail:0 skip:28 time:410s
fi-cfl-s2 total:288 pass:262 dwarn:0 dfail:0 fail:0 skip:26 time:575s
fi-cfl-u total:288 pass:262 dwarn:0 dfail:0 fail:0 skip:26 time:509s
fi-elk-e7500 total:288 pass:229 dwarn:0 dfail:0 fail:0 skip:59 time:416s
fi-gdg-551 total:288 pass:180 dwarn:0 dfail:0 fail:0 skip:108 time:290s
fi-glk-1 total:288 pass:260 dwarn:0 dfail:0 fail:0 skip:28 time:528s
fi-hsw-4770 total:288 pass:261 dwarn:0 dfail:0 fail:0 skip:27 time:398s
fi-ilk-650 total:288 pass:228 dwarn:0 dfail:0 fail:0 skip:60 time:412s
fi-ivb-3520m total:288 pass:259 dwarn:0 dfail:0 fail:0 skip:29 time:456s
fi-ivb-3770 total:288 pass:255 dwarn:0 dfail:0 fail:0 skip:33 time:421s
fi-kbl-7500u total:288 pass:263 dwarn:1 dfail:0 fail:0 skip:24 time:472s
fi-kbl-7567u total:288 pass:268 dwarn:0 dfail:0 fail:0 skip:20 time:460s
fi-kbl-r total:288 pass:261 dwarn:0 dfail:0 fail:0 skip:27 time:505s
fi-pnv-d510 total:288 pass:222 dwarn:1 dfail:0 fail:0 skip:65 time:585s
fi-skl-6260u total:288 pass:268 dwarn:0 dfail:0 fail:0 skip:20 time:432s
fi-skl-6600u total:288 pass:261 dwarn:0 dfail:0 fail:0 skip:27 time:522s
fi-skl-6700hq total:288 pass:262 dwarn:0 dfail:0 fail:0 skip:26 time:538s
fi-skl-6700k2 total:288 pass:264 dwarn:0 dfail:0 fail:0 skip:24 time:501s
fi-skl-6770hq total:288 pass:268 dwarn:0 dfail:0 fail:0 skip:20 time:493s
fi-skl-guc total:288 pass:260 dwarn:0 dfail:0 fail:0 skip:28 time:420s
fi-skl-gvtdvm total:288 pass:265 dwarn:0 dfail:0 fail:0 skip:23 time:428s
fi-snb-2520m total:288 pass:248 dwarn:0 dfail:0 fail:0 skip:40 time:530s
fi-snb-2600 total:288 pass:248 dwarn:0 dfail:0 fail:0 skip:40 time:392s
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_1080/issues.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* ✓ Fi.CI.IGT: success for igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-07 22:49 ` [igt-dev] " Chris Wilson
` (7 preceding siblings ...)
(?)
@ 2018-03-08 3:12 ` Patchwork
-1 siblings, 0 replies; 36+ messages in thread
From: Patchwork @ 2018-03-08 3:12 UTC (permalink / raw)
To: Chris Wilson; +Cc: intel-gfx
== Series Details ==
Series: igt: Add gem_ctx_freq to exercise requesting freq on a ctx
URL : https://patchwork.freedesktop.org/series/39571/
State : success
== Summary ==
---- Known issues:
Test gem_softpin:
Subgroup noreloc-s3:
skip -> PASS (shard-snb) fdo#103375
Test kms_chv_cursor_fail:
Subgroup pipe-b-128x128-right-edge:
pass -> DMESG-WARN (shard-snb) fdo#105185 +2
Test kms_flip:
Subgroup 2x-plain-flip-fb-recreate:
fail -> PASS (shard-hsw) fdo#100368 +1
Test kms_frontbuffer_tracking:
Subgroup fbc-modesetfrombusy:
pass -> FAIL (shard-apl) fdo#103167
Subgroup fbc-suspend:
fail -> PASS (shard-apl) fdo#101623
Test kms_rotation_crc:
Subgroup primary-rotation-180:
fail -> PASS (shard-snb) fdo#103925
Test kms_sysfs_edid_timing:
warn -> PASS (shard-apl) fdo#100047
Test pm_lpsp:
Subgroup screens-disabled:
fail -> PASS (shard-hsw) fdo#104941
fdo#103375 https://bugs.freedesktop.org/show_bug.cgi?id=103375
fdo#105185 https://bugs.freedesktop.org/show_bug.cgi?id=105185
fdo#100368 https://bugs.freedesktop.org/show_bug.cgi?id=100368
fdo#103167 https://bugs.freedesktop.org/show_bug.cgi?id=103167
fdo#101623 https://bugs.freedesktop.org/show_bug.cgi?id=101623
fdo#103925 https://bugs.freedesktop.org/show_bug.cgi?id=103925
fdo#100047 https://bugs.freedesktop.org/show_bug.cgi?id=100047
fdo#104941 https://bugs.freedesktop.org/show_bug.cgi?id=104941
shard-apl total:3448 pass:1806 dwarn:1 dfail:0 fail:8 skip:1632 time:12072s
shard-hsw total:3484 pass:1772 dwarn:1 dfail:0 fail:2 skip:1708 time:11921s
shard-snb total:3484 pass:1364 dwarn:2 dfail:0 fail:1 skip:2117 time:7142s
Blacklisted hosts:
shard-kbl total:3328 pass:1791 dwarn:7 dfail:1 fail:7 skip:1519 time:8399s
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_1080/shards.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH igt v2] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-07 22:49 ` [igt-dev] " Chris Wilson
` (8 preceding siblings ...)
(?)
@ 2018-03-08 9:02 ` Chris Wilson
-1 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-08 9:02 UTC (permalink / raw)
To: intel-gfx
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
v2: Split single/continuous set_freq subtests
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
tests/Makefile.am | 1 +
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 604 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 607 insertions(+)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index dbc7be72..389f7fc7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4a81ac4a..3d079c42 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -58,6 +58,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_switch \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..f7e79ac3
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,604 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 8
+
+#define SAMPLE_PERIOD (USEC_PER_SEC / 10)
+
+static int __set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ return __gem_context_set_param(fd, ¶m);
+}
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ igt_assert_eq(__set_freq(fd, ctx, min, max), 0);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int period_us)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(period_us);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ uint32_t cur, discard;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+}
+
+static void continuous(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ uint32_t cur, discard;
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+}
+
+static void inflight(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx, min, max, freq, discard;
+ double measured;
+ igt_spin_t *plug, *work[2];
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ gem_quiescent_gpu(fd);
+ plug = igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+ for (int n = 0; n < 16; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = plug->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = gem_context_create(fd),
+ };
+ set_freq(fd, eb.rsvd1, min, min);
+ gem_execbuf(fd, &eb);
+ gem_context_destroy(fd, eb.rsvd1);
+ }
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(plug): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, min);
+ igt_assert(measured > min - 100 && measured < min + 100);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[0] = __igt_spin_batch_new(fd, ctx, engine, 0);
+
+ /* work is now queued but not executing */
+ freq = (max + min) / 2;
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &freq, &discard);
+ gem_context_destroy(fd, ctx);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[1] = __igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+
+ igt_spin_batch_end(plug);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, plug->handle));
+ igt_spin_batch_free(fd, plug);
+
+ /* Now work will execute */
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work0): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+
+ igt_spin_batch_end(work[0]);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, work[0]->handle));
+ igt_spin_batch_free(fd, work[0]);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work1): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, max);
+ igt_assert(measured > max - 100 && measured < max + 100);
+
+ igt_spin_batch_free(fd, work[1]);
+ close(pmu);
+ gem_quiescent_gpu(fd);
+}
+
+static void sandwich(int fd)
+{
+ uint32_t ctx = gem_context_create(fd);
+ unsigned int engine;
+ uint32_t min, max;
+ igt_spin_t *spin;
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ spin = igt_spin_batch_new(fd, ctx, 0, 0);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+ for_each_physical_engine(fd, engine) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = ctx,
+ };
+ uint32_t cur, discard;
+ double measured;
+
+ min += 50;
+ if (min > max)
+ break;
+
+ set_freq(fd, ctx, min, min);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_execbuf(fd, &eb);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("Measured %.1fMHz, expected %dMhz\n", measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ gem_context_destroy(fd, ctx);
+ close(pmu);
+}
+
+static void pwm(int fd, unsigned int *engines, unsigned int nengine, int link)
+{
+ uint32_t ctx[nengine];
+
+ fcntl(link, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ for (unsigned int n = 0; n < nengine; n++)
+ ctx[n] = gem_context_create(fd);
+
+ do {
+ igt_spin_t *spin;
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+
+ while (read(link, &req, sizeof(req)) > 0) {
+ if ((req.engine | req.min | req.max) == 0)
+ goto out;
+
+ igt_assert(req.engine < nengine);
+ set_freq(fd, ctx[req.engine], req.min, req.max);
+ }
+
+ /* Create a 20% load using busy spinners */
+ spin = __igt_spin_batch_new(fd, ctx[0], engines[0], 0);
+ for (unsigned int n = 1; n < nengine; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engines[n],
+ .rsvd1 = ctx[n],
+ };
+ gem_execbuf(fd, &eb);
+ }
+ usleep(100);
+ igt_spin_batch_end(spin);
+
+ do
+ usleep(10);
+ while (gem_bo_busy(fd, spin->handle));
+ igt_spin_batch_free(fd, spin);
+ usleep(400);
+ } while (1);
+
+out:
+ for (unsigned int n = 0; n < nengine; n++)
+ gem_context_destroy(fd, ctx[n]);
+}
+
+static void smoketest(int fd, int timeout)
+{
+ unsigned int engines[16];
+ unsigned int nengine;
+ unsigned int engine;
+ uint32_t min[16], max[16];
+ int pmu, link[2];
+
+ get_freq(fd, 0, &min[0], &max[0]);
+
+ nengine = 0;
+ for_each_physical_engine(fd, engine) {
+ if (nengine == ARRAY_SIZE(engines) - 1)
+ break;
+
+ min[nengine] = min[0];
+ max[nengine] = max[0];
+ engines[nengine] = engine;
+ nengine++;
+ }
+ igt_require(nengine);
+
+ igt_assert(pipe(link) == 0);
+ igt_fork(child, 1)
+ pwm(fd, engines, nengine, link[0]);
+ close(link[0]);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ igt_until_timeout(timeout) {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+ double measured;
+ uint32_t ctx;
+
+ req.engine = rand() % nengine;
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &req.min, &req.max);
+ req.min = rand() % (req.max - req.min) + req.min;
+ req.max = rand() % (req.max - req.min) + req.min;
+ set_freq(fd, ctx, req.min, req.max);
+ get_freq(fd, ctx, &req.min, &req.max);
+
+ igt_debug("Replacing (%d, %d) on engine %x with (%d, %d)\n",
+ min[req.engine], max[req.engine], req.engine,
+ req.min, req.max);
+ igt_assert(write(link[1], &req, sizeof(req)) == sizeof(req));
+ gem_context_destroy(fd, ctx);
+
+ min[req.engine] = req.min;
+ max[req.engine] = req.max;
+
+ for (unsigned int n = 0; n < nengine; n++) {
+ igt_debug("[%d]: [%d, %d]\n", n, min[n], max[n]);
+ if (min[n] < req.min)
+ req.min = min[n];
+ if (max[n] > req.max)
+ req.max = max[n];
+ }
+ igt_assert(req.max >= req.min);
+
+ usleep(50000);
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+
+ if (measured <= req.min - 100 || measured >= req.max + 100)
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("Measured %.1fMHz, expected [%d, %d]Mhz\n",
+ measured, req.min, req.max);
+ igt_assert(measured > req.min - 100 &&
+ measured < req.max + 100);
+ }
+
+ do {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req = {};
+
+ write(link[1], &req, sizeof(req));
+ close(link[1]);
+ } while (0);
+ igt_waitchildren();
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+}
+
+static void invalid_param(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ igt_assert_eq(__set_freq(fd, 0, min - 50, max), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, min, max + 50), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, min + 50, min), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, max, max - 50), -EINVAL);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void idempotent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ set_freq(fd, 0, min, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void independent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+ uint32_t ctx[2];
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ ctx[0] = gem_context_create(fd);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ ctx[1] = gem_context_create(fd);
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx[1], max, max);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[1]);
+
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[0]);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+ }
+
+ igt_subtest("invalid")
+ invalid_param(fd);
+
+ igt_subtest("idempotent")
+ idempotent(fd);
+
+ igt_subtest("independent")
+ independent(fd);
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ if (e->exec_id == 0)
+ continue;
+
+ igt_subtest_group {
+ igt_fixture {
+ igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
+ }
+
+ igt_subtest_f("%s-single", e->name)
+ single(fd, e);
+ igt_subtest_f("%s-continuous", e->name)
+ continuous(fd, e);
+ igt_subtest_f("%s-inflight", e->name)
+ inflight(fd, e);
+ }
+ }
+
+ igt_subtest("sandwich")
+ sandwich(fd);
+
+ igt_subtest("smoketest")
+ smoketest(fd, 20);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 58729231..f1271274 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -35,6 +35,7 @@ test_progs = [
'gem_ctx_bad_exec',
'gem_ctx_create',
'gem_ctx_exec',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-08 1:18 ` [igt-dev] [Intel-gfx] " Chris Wilson
@ 2018-03-08 17:33 ` Antonio Argenziano
-1 siblings, 0 replies; 36+ messages in thread
From: Antonio Argenziano @ 2018-03-08 17:33 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: igt-dev
On 07/03/18 17:18, Chris Wilson wrote:
> Quoting Antonio Argenziano (2018-03-08 00:55:47)
>>
>>
>> On 07/03/18 14:49, Chris Wilson wrote:
>>> +static void single(int fd, const struct intel_execution_engine *e)
>>> +{
>>> + const unsigned int engine = e->exec_id | e->flags;
>>> + uint32_t ctx = gem_context_create(fd);
>>> + uint32_t min, max;
>>> + double measured;
>>> + igt_spin_t *spin;
>>> + int pmu;
>>> +
>>> + get_freq(fd, ctx, &min, &max);
>>> + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
>>> +
>>> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
>>> + igt_require(pmu >= 0);
>>> +
>>> + gem_quiescent_gpu(fd);
>>> + measured = measure_frequency(pmu, 10000);
>>> + igt_info("Initial (idle) freq: %.1fMHz\n",measured);
>>> + igt_require(measured >= min - 50 && measured <= min + 50);
>>> +
>>> + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
>>> + set_freq(fd, ctx, freq, freq);
>>> +
>>> + gem_quiescent_gpu(fd);
>>> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
>>> + usleep(10000);
>>> +
>>> + measured = measure_frequency(pmu, 50000);
>>> + igt_debugfs_dump(fd, "i915_rps_boost_info");
>>> +
>>> + igt_spin_batch_free(fd, spin);
>>> + igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
>>> + e->name, measured, freq);
>>> + igt_assert(measured > freq - 100 && measured < freq + 100);
>>> + }
>>> + gem_quiescent_gpu(fd);
>>
>> Check frequency has gone back to ~min.
>
> It's not that interesting a test (covered already by pmu) as we
> essentially lie anyway over idle.
Agreed.
>
>> I would suggest to split here into two sub-tests.
>>
>>> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
>>> + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
>>> + igt_spin_t *kick;
>>> +
>>> + set_freq(fd, ctx, freq, freq);
>>> +
>>> + /*
>>> + * When requesting a new frequency on the currently
>>> + * executing context, it does not take effect until the
>>> + * next context switch. In this case, we trigger a lite
>>> + * restore.
>>
>> Is this enforced by the ABI?
>
> Enforced? No. The comment is precisely because it's not checked on
> calling whether the context is currently on the HW and trying hard to be
> sure that no one expects us to do that check. i.e. that set_freq()
> doesn't change frequency itself, but doesn't rule it out either as it
> may appear to have that effect due to many external factors.
That is what I thought :).
I see that you had a new version with more tests, I'll have a look at that.
Thanks,
Antonio
> -Chris
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [igt-dev] [Intel-gfx] [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
@ 2018-03-08 17:33 ` Antonio Argenziano
0 siblings, 0 replies; 36+ messages in thread
From: Antonio Argenziano @ 2018-03-08 17:33 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: igt-dev
On 07/03/18 17:18, Chris Wilson wrote:
> Quoting Antonio Argenziano (2018-03-08 00:55:47)
>>
>>
>> On 07/03/18 14:49, Chris Wilson wrote:
>>> +static void single(int fd, const struct intel_execution_engine *e)
>>> +{
>>> + const unsigned int engine = e->exec_id | e->flags;
>>> + uint32_t ctx = gem_context_create(fd);
>>> + uint32_t min, max;
>>> + double measured;
>>> + igt_spin_t *spin;
>>> + int pmu;
>>> +
>>> + get_freq(fd, ctx, &min, &max);
>>> + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
>>> +
>>> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
>>> + igt_require(pmu >= 0);
>>> +
>>> + gem_quiescent_gpu(fd);
>>> + measured = measure_frequency(pmu, 10000);
>>> + igt_info("Initial (idle) freq: %.1fMHz\n",measured);
>>> + igt_require(measured >= min - 50 && measured <= min + 50);
>>> +
>>> + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
>>> + set_freq(fd, ctx, freq, freq);
>>> +
>>> + gem_quiescent_gpu(fd);
>>> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
>>> + usleep(10000);
>>> +
>>> + measured = measure_frequency(pmu, 50000);
>>> + igt_debugfs_dump(fd, "i915_rps_boost_info");
>>> +
>>> + igt_spin_batch_free(fd, spin);
>>> + igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
>>> + e->name, measured, freq);
>>> + igt_assert(measured > freq - 100 && measured < freq + 100);
>>> + }
>>> + gem_quiescent_gpu(fd);
>>
>> Check frequency has gone back to ~min.
>
> It's not that interesting a test (covered already by pmu) as we
> essentially lie anyway over idle.
Agreed.
>
>> I would suggest to split here into two sub-tests.
>>
>>> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
>>> + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
>>> + igt_spin_t *kick;
>>> +
>>> + set_freq(fd, ctx, freq, freq);
>>> +
>>> + /*
>>> + * When requesting a new frequency on the currently
>>> + * executing context, it does not take effect until the
>>> + * next context switch. In this case, we trigger a lite
>>> + * restore.
>>
>> Is this enforced by the ABI?
>
> Enforced? No. The comment is precisely because it's not checked on
> calling whether the context is currently on the HW and trying hard to be
> sure that no one expects us to do that check. i.e. that set_freq()
> doesn't change frequency itself, but doesn't rule it out either as it
> may appear to have that effect due to many external factors.
That is what I thought :).
I see that you had a new version with more tests, I'll have a look at that.
Thanks,
Antonio
> -Chris
>
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-08 17:33 ` [igt-dev] [Intel-gfx] " Antonio Argenziano
@ 2018-03-08 17:39 ` Chris Wilson
-1 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-08 17:39 UTC (permalink / raw)
To: Antonio Argenziano, intel-gfx; +Cc: igt-dev
Quoting Antonio Argenziano (2018-03-08 17:33:11)
>
>
> On 07/03/18 17:18, Chris Wilson wrote:
> > Quoting Antonio Argenziano (2018-03-08 00:55:47)
> >>
> >>
> >> On 07/03/18 14:49, Chris Wilson wrote:
> >>> + gem_quiescent_gpu(fd);
> >>
> >> Check frequency has gone back to ~min.
> >
> > It's not that interesting a test (covered already by pmu) as we
> > essentially lie anyway over idle.
>
> Agreed.
I should mention somewhere the reason for all the gem_quiescent_gpu()
spam here is because I want to make sure that no stray waitboosts affect
the measurements.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [igt-dev] [Intel-gfx] [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
@ 2018-03-08 17:39 ` Chris Wilson
0 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-08 17:39 UTC (permalink / raw)
To: Antonio Argenziano, intel-gfx; +Cc: igt-dev
Quoting Antonio Argenziano (2018-03-08 17:33:11)
>
>
> On 07/03/18 17:18, Chris Wilson wrote:
> > Quoting Antonio Argenziano (2018-03-08 00:55:47)
> >>
> >>
> >> On 07/03/18 14:49, Chris Wilson wrote:
> >>> + gem_quiescent_gpu(fd);
> >>
> >> Check frequency has gone back to ~min.
> >
> > It's not that interesting a test (covered already by pmu) as we
> > essentially lie anyway over idle.
>
> Agreed.
I should mention somewhere the reason for all the gem_quiescent_gpu()
spam here is because I want to make sure that no stray waitboosts affect
the measurements.
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-14 9:03 ` Chris Wilson
@ 2018-03-14 9:49 ` Sagar Arun Kamble
0 siblings, 0 replies; 36+ messages in thread
From: Sagar Arun Kamble @ 2018-03-14 9:49 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: igt-dev, Praveen Paneri
On 3/14/2018 2:33 PM, Chris Wilson wrote:
> Quoting Sagar Arun Kamble (2018-03-14 08:15:15)
>>
>> On 3/13/2018 7:28 PM, Chris Wilson wrote:
>>> Exercise some new API that allows applications to request that
>>> individual contexts are executed within a desired frequency range.
>>>
>>> v2: Split single/continuous set_freq subtests
>>> v3: Do an up/down ramp for individual freq request, check nothing
>>> changes after each invalid request
>>> v4: Check the frequencies reported by the kernel across the entire
>>> range.
>>> v5: Rewrite sandwich to create a sandwich between multiple concurrent
>>> engines.
>>> v6: Exercise sysfs overrides.
>>> v7: Reset min/max of default context after independent(); don't ask
>>> about failure
>>> v8: Check transition beyond randomly chosen frequencies as well as
>>> up/down ramps.
>>>
>>> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
>>> Cc: Praveen Paneri <praveen.paneri@intel.com>
>>> Cc: Sagar A Kamble <sagar.a.kamble@intel.com>
>>> Cc: Antonio Argenziano <antonio.argenziano@intel.com>
>>> Reviewed-by: Antonio Argenziano <antonio.argenziano@intel.com> #v5
>> There are few stray whitespaces in __pmu_within_tolerance, pmu_assert.
>> Otherwise looks good to me.
>> Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>
>> Can you please clarify few things below:
>>> ---
>> <snip>
>>> +
>>> +static void sysfs_clamp(int fd, const struct intel_execution_engine *e)
>>> +{
>>> +#define N_STEPS 10
>>> + const unsigned int engine = e->exec_id | e->flags;
>>> + uint32_t ctx = gem_context_create(fd);
>>> + uint32_t sys_min, sys_max;
>>> + uint32_t min, max;
>>> + double measured;
>>> + igt_spin_t *spin;
>>> + int pmu;
>>> +
>>> + get_sysfs_freq(&sys_min, &sys_max);
>>> + igt_info("System min freq: %dMHz; max freq: %dMHz\n", sys_min, sys_max);
>>> +
>>> + get_freq(fd, ctx, &min, &max);
>>> + igt_info("Context min freq: %dMHz; max freq: %dMHz\n", min, max);
>>> +
>>> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
>>> + igt_require(pmu >= 0);
>>> +
>>> + for (int outer = 0; outer <= 2*N_STEPS; outer++) {
>>> + int ofrac = outer > N_STEPS ? 2*N_STEPS - outer : outer;
>>> + uint32_t ofreq = min + (max - min) * ofrac / N_STEPS;
>>> + uint32_t cur, discard;
>>> +
>>> + for (int inner = 0; inner <= 2*N_STEPS; inner++) {
>>> + int ifrac = inner > N_STEPS ? 2*N_STEPS - inner : inner;
>>> + uint32_t ifreq = min + (max - min) * ifrac / N_STEPS;
>>> +
>>> + set_freq(fd, ctx, ifreq, ifreq);
>>> +
>>> + gem_quiescent_gpu(fd);
>>> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
>>> + usleep(10000);
>>> +
>>> + set_sysfs_freq(ofreq, ofreq);
>>> + get_sysfs_freq(&cur, &discard);
>> We don't sleep here because we know that we set the frequency in sysfs?
> sysfs is a synchronous interface, yes.
>
>>> +
>>> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
>>> + igt_debugfs_dump(fd, "i915_rps_boost_info");
>>> +
>>> + set_sysfs_freq(sys_min, sys_max);
>>> +
>>> + igt_spin_batch_free(fd, spin);
>>> + igt_info("%s(sysfs): Measured %.1fMHz, context %dMhz, expected %dMhz\n",
>>> + e->name, measured, ifreq, cur);
>>> + pmu_assert(measured, cur);
>>> + }
>>> + }
>>> + gem_quiescent_gpu(fd);
>>> +
>>> + close(pmu);
>>> + gem_context_destroy(fd, ctx);
>>> +
>>> +#undef N_STEPS
>>> +}
>>> +
>> ...
>>> +static void disable_boost(int fd)
>>> +{
>>> + char *value;
>>> +
>>> + value = igt_sysfs_get(fd, "gt_RPn_freq_mhz");
>>> + igt_sysfs_set(fd, "gt_boost_freq_mhz", value);
>> Why is this needed? kernel will not clamp boost freq as well within
>> ctx_freq_min/max?
> Boosting is a separate mechanism than ctx->freq, as it is performed on
> behalf of *another* client.
Right. I meant i915 min|max_freq_context in your upcoming patch.
boost_freq is clamped against max_hw and min_user|soft|context
Understood that setting it to Rpn will make it get clamped in the
expected range :)
Thanks for clarification.
>> Kernel disabling boost seems more effective than setting boost_freq to Rpn.
> This is how we tell the kernel to disable boost, by setting it to a
> value that never applies.
>
> The tests try to avoid triggering boosts, but I felt it was sensible to
> override the mechanism entirely. We still need various random sleeps
> inside the tests in order to give the worker a chance to run, which is a
> nuisance.
> -Chris
--
Thanks,
Sagar
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-14 8:15 ` Sagar Arun Kamble
@ 2018-03-14 9:03 ` Chris Wilson
2018-03-14 9:49 ` Sagar Arun Kamble
0 siblings, 1 reply; 36+ messages in thread
From: Chris Wilson @ 2018-03-14 9:03 UTC (permalink / raw)
To: Sagar Arun Kamble, intel-gfx; +Cc: igt-dev, Praveen Paneri
Quoting Sagar Arun Kamble (2018-03-14 08:15:15)
>
>
> On 3/13/2018 7:28 PM, Chris Wilson wrote:
> > Exercise some new API that allows applications to request that
> > individual contexts are executed within a desired frequency range.
> >
> > v2: Split single/continuous set_freq subtests
> > v3: Do an up/down ramp for individual freq request, check nothing
> > changes after each invalid request
> > v4: Check the frequencies reported by the kernel across the entire
> > range.
> > v5: Rewrite sandwich to create a sandwich between multiple concurrent
> > engines.
> > v6: Exercise sysfs overrides.
> > v7: Reset min/max of default context after independent(); don't ask
> > about failure
> > v8: Check transition beyond randomly chosen frequencies as well as
> > up/down ramps.
> >
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > Cc: Praveen Paneri <praveen.paneri@intel.com>
> > Cc: Sagar A Kamble <sagar.a.kamble@intel.com>
> > Cc: Antonio Argenziano <antonio.argenziano@intel.com>
> > Reviewed-by: Antonio Argenziano <antonio.argenziano@intel.com> #v5
> There are few stray whitespaces in __pmu_within_tolerance, pmu_assert.
> Otherwise looks good to me.
> Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>
> Can you please clarify few things below:
> > ---
> <snip>
> > +
> > +static void sysfs_clamp(int fd, const struct intel_execution_engine *e)
> > +{
> > +#define N_STEPS 10
> > + const unsigned int engine = e->exec_id | e->flags;
> > + uint32_t ctx = gem_context_create(fd);
> > + uint32_t sys_min, sys_max;
> > + uint32_t min, max;
> > + double measured;
> > + igt_spin_t *spin;
> > + int pmu;
> > +
> > + get_sysfs_freq(&sys_min, &sys_max);
> > + igt_info("System min freq: %dMHz; max freq: %dMHz\n", sys_min, sys_max);
> > +
> > + get_freq(fd, ctx, &min, &max);
> > + igt_info("Context min freq: %dMHz; max freq: %dMHz\n", min, max);
> > +
> > + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> > + igt_require(pmu >= 0);
> > +
> > + for (int outer = 0; outer <= 2*N_STEPS; outer++) {
> > + int ofrac = outer > N_STEPS ? 2*N_STEPS - outer : outer;
> > + uint32_t ofreq = min + (max - min) * ofrac / N_STEPS;
> > + uint32_t cur, discard;
> > +
> > + for (int inner = 0; inner <= 2*N_STEPS; inner++) {
> > + int ifrac = inner > N_STEPS ? 2*N_STEPS - inner : inner;
> > + uint32_t ifreq = min + (max - min) * ifrac / N_STEPS;
> > +
> > + set_freq(fd, ctx, ifreq, ifreq);
> > +
> > + gem_quiescent_gpu(fd);
> > + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> > + usleep(10000);
> > +
> > + set_sysfs_freq(ofreq, ofreq);
> > + get_sysfs_freq(&cur, &discard);
> We don't sleep here because we know that we set the frequency in sysfs?
sysfs is a synchronous interface, yes.
> > +
> > + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> > + igt_debugfs_dump(fd, "i915_rps_boost_info");
> > +
> > + set_sysfs_freq(sys_min, sys_max);
> > +
> > + igt_spin_batch_free(fd, spin);
> > + igt_info("%s(sysfs): Measured %.1fMHz, context %dMhz, expected %dMhz\n",
> > + e->name, measured, ifreq, cur);
> > + pmu_assert(measured, cur);
> > + }
> > + }
> > + gem_quiescent_gpu(fd);
> > +
> > + close(pmu);
> > + gem_context_destroy(fd, ctx);
> > +
> > +#undef N_STEPS
> > +}
> > +
> ...
> > +static void disable_boost(int fd)
> > +{
> > + char *value;
> > +
> > + value = igt_sysfs_get(fd, "gt_RPn_freq_mhz");
> > + igt_sysfs_set(fd, "gt_boost_freq_mhz", value);
> Why is this needed? kernel will not clamp boost freq as well within
> ctx_freq_min/max?
Boosting is a separate mechanism than ctx->freq, as it is performed on
behalf of *another* client.
> Kernel disabling boost seems more effective than setting boost_freq to Rpn.
This is how we tell the kernel to disable boost, by setting it to a
value that never applies.
The tests try to avoid triggering boosts, but I felt it was sensible to
override the mechanism entirely. We still need various random sleeps
inside the tests in order to give the worker a chance to run, which is a
nuisance.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-13 13:58 ` Chris Wilson
@ 2018-03-14 8:15 ` Sagar Arun Kamble
2018-03-14 9:03 ` Chris Wilson
0 siblings, 1 reply; 36+ messages in thread
From: Sagar Arun Kamble @ 2018-03-14 8:15 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: igt-dev, Praveen Paneri
On 3/13/2018 7:28 PM, Chris Wilson wrote:
> Exercise some new API that allows applications to request that
> individual contexts are executed within a desired frequency range.
>
> v2: Split single/continuous set_freq subtests
> v3: Do an up/down ramp for individual freq request, check nothing
> changes after each invalid request
> v4: Check the frequencies reported by the kernel across the entire
> range.
> v5: Rewrite sandwich to create a sandwich between multiple concurrent
> engines.
> v6: Exercise sysfs overrides.
> v7: Reset min/max of default context after independent(); don't ask
> about failure
> v8: Check transition beyond randomly chosen frequencies as well as
> up/down ramps.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Praveen Paneri <praveen.paneri@intel.com>
> Cc: Sagar A Kamble <sagar.a.kamble@intel.com>
> Cc: Antonio Argenziano <antonio.argenziano@intel.com>
> Reviewed-by: Antonio Argenziano <antonio.argenziano@intel.com> #v5
There are few stray whitespaces in __pmu_within_tolerance, pmu_assert.
Otherwise looks good to me.
Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Can you please clarify few things below:
> ---
<snip>
> +
> +static void sysfs_clamp(int fd, const struct intel_execution_engine *e)
> +{
> +#define N_STEPS 10
> + const unsigned int engine = e->exec_id | e->flags;
> + uint32_t ctx = gem_context_create(fd);
> + uint32_t sys_min, sys_max;
> + uint32_t min, max;
> + double measured;
> + igt_spin_t *spin;
> + int pmu;
> +
> + get_sysfs_freq(&sys_min, &sys_max);
> + igt_info("System min freq: %dMHz; max freq: %dMHz\n", sys_min, sys_max);
> +
> + get_freq(fd, ctx, &min, &max);
> + igt_info("Context min freq: %dMHz; max freq: %dMHz\n", min, max);
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
> +
> + for (int outer = 0; outer <= 2*N_STEPS; outer++) {
> + int ofrac = outer > N_STEPS ? 2*N_STEPS - outer : outer;
> + uint32_t ofreq = min + (max - min) * ofrac / N_STEPS;
> + uint32_t cur, discard;
> +
> + for (int inner = 0; inner <= 2*N_STEPS; inner++) {
> + int ifrac = inner > N_STEPS ? 2*N_STEPS - inner : inner;
> + uint32_t ifreq = min + (max - min) * ifrac / N_STEPS;
> +
> + set_freq(fd, ctx, ifreq, ifreq);
> +
> + gem_quiescent_gpu(fd);
> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> + usleep(10000);
> +
> + set_sysfs_freq(ofreq, ofreq);
> + get_sysfs_freq(&cur, &discard);
We don't sleep here because we know that we set the frequency in sysfs?
> +
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> +
> + set_sysfs_freq(sys_min, sys_max);
> +
> + igt_spin_batch_free(fd, spin);
> + igt_info("%s(sysfs): Measured %.1fMHz, context %dMhz, expected %dMhz\n",
> + e->name, measured, ifreq, cur);
> + pmu_assert(measured, cur);
> + }
> + }
> + gem_quiescent_gpu(fd);
> +
> + close(pmu);
> + gem_context_destroy(fd, ctx);
> +
> +#undef N_STEPS
> +}
> +
...
> +static void disable_boost(int fd)
> +{
> + char *value;
> +
> + value = igt_sysfs_get(fd, "gt_RPn_freq_mhz");
> + igt_sysfs_set(fd, "gt_boost_freq_mhz", value);
Why is this needed? kernel will not clamp boost freq as well within
ctx_freq_min/max?
Kernel disabling boost seems more effective than setting boost_freq to Rpn.
> + free(value);
> +}
> +
> +igt_main
> +{
> + const struct intel_execution_engine *e;
> + int fd = -1;
> +
> + igt_fixture {
> + fd = drm_open_driver(DRIVER_INTEL);
> + igt_require_gem(fd);
> +
> + igt_require(has_ctx_freq(fd));
> +
> + sysfs = igt_sysfs_open(fd, NULL);
> + igt_assert(sysfs != -1);
> + igt_install_exit_handler(restore_sysfs_freq);
> +
> + disable_boost(sysfs);
> + }
> +
> + igt_subtest("invalid")
> + invalid(fd);
> +
> + igt_subtest("idempotent")
> + idempotent(fd);
> +
> + igt_subtest("range")
> + range(fd);
> +
> + igt_subtest("independent")
> + independent(fd);
> +
> + igt_skip_on_simulation();
> +
> + for (e = intel_execution_engines; e->name; e++) {
> + igt_subtest_group {
> + igt_fixture {
> + gem_require_ring(fd, e->exec_id | e->flags);
> + }
> +
> + igt_subtest_f("%s-single", e->name)
> + single(fd, e);
> + igt_subtest_f("%s-continuous", e->name)
> + continuous(fd, e);
> + igt_subtest_f("%s-inflight", e->name)
> + inflight(fd, e);
> + igt_subtest_f("%s-sysfs", e->name)
> + sysfs_clamp(fd, e);
> + }
> + }
> +
> + igt_subtest("sandwich")
> + sandwich(fd, 20);
> +
> + igt_subtest("smoketest")
> + smoketest(fd, 20);
> +}
> diff --git a/tests/meson.build b/tests/meson.build
> index 1176463c..f07ad25e 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -36,6 +36,7 @@ test_progs = [
> 'gem_ctx_create',
> 'gem_ctx_exec',
> 'gem_ctx_isolation',
> + 'gem_ctx_freq',
> 'gem_ctx_param',
> 'gem_ctx_switch',
> 'gem_ctx_thrash',
--
Thanks,
Sagar
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-08 17:13 [PATCH igt] " Chris Wilson
` (3 preceding siblings ...)
2018-03-13 13:26 ` Chris Wilson
@ 2018-03-13 13:58 ` Chris Wilson
2018-03-14 8:15 ` Sagar Arun Kamble
4 siblings, 1 reply; 36+ messages in thread
From: Chris Wilson @ 2018-03-13 13:58 UTC (permalink / raw)
To: intel-gfx; +Cc: igt-dev, Praveen Paneri
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
v2: Split single/continuous set_freq subtests
v3: Do an up/down ramp for individual freq request, check nothing
changes after each invalid request
v4: Check the frequencies reported by the kernel across the entire
range.
v5: Rewrite sandwich to create a sandwich between multiple concurrent
engines.
v6: Exercise sysfs overrides.
v7: Reset min/max of default context after independent(); don't ask
about failure
v8: Check transition beyond randomly chosen frequencies as well as
up/down ramps.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Praveen Paneri <praveen.paneri@intel.com>
Cc: Sagar A Kamble <sagar.a.kamble@intel.com>
Cc: Antonio Argenziano <antonio.argenziano@intel.com>
Reviewed-by: Antonio Argenziano <antonio.argenziano@intel.com> #v5
---
tests/Makefile.am | 1 +
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 837 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 840 insertions(+)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index dbc7be72..389f7fc7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4e6f5319..a4ca85bc 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -58,6 +58,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_switch \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..83509ea6
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,837 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+#include "igt_sysfs.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 7
+
+#define SAMPLE_PERIOD (USEC_PER_SEC / 10)
+#define PMU_TOLERANCE 100
+
+static int sysfs = -1;
+
+static int __set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ return __gem_context_set_param(fd, ¶m);
+}
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ igt_assert_eq(__set_freq(fd, ctx, min, max), 0);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int period_us)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(period_us);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static bool __pmu_within_tolerance(double actual, double target)
+{
+ return (actual > target - PMU_TOLERANCE &&
+ actual < target + PMU_TOLERANCE);
+}
+
+static void pmu_assert(double actual, double target)
+{
+ igt_assert_f(__pmu_within_tolerance(actual, target),
+ "Measured frequency %.2fMHz, is beyond target %.2f+-%dMhz",
+ actual, target, PMU_TOLERANCE);
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+#define N_STEPS 10
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t frequencies[2*N_STEPS + 1];
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ for (int step = 0; step <= 2*N_STEPS; step++) {
+ int frac = step > N_STEPS ? 2*N_STEPS - step : step;
+ frequencies[step] = min + (max - min) * frac / N_STEPS;
+ }
+
+ for (int pass = 0; pass < 3; pass++) {
+ for (int i = 0; i < ARRAY_SIZE(frequencies); i++) {
+ uint32_t freq = frequencies[i];
+ uint32_t cur, discard;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(%s): Measured %.1fMHz, expected %dMhz\n",
+ e->name, __func__, measured, cur);
+ pmu_assert(measured, cur);
+ }
+
+ igt_permute_array(frequencies,
+ ARRAY_SIZE(frequencies),
+ igt_exchange_int);
+ }
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+
+#undef N_STEPS
+}
+
+static void continuous(int fd, const struct intel_execution_engine *e)
+{
+#define N_STEPS 10
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t frequencies[2*N_STEPS + 1];
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ for (int step = 0; step <= 2*N_STEPS; step++) {
+ int frac = step > N_STEPS ? 2*N_STEPS - step : step;
+ frequencies[step] = min + (max - min) * frac / N_STEPS;
+ }
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (int pass = 0; pass < 3; pass++) {
+ for (int i = 0; i < ARRAY_SIZE(frequencies); i++) {
+ uint32_t freq = frequencies[i];
+ uint32_t cur, discard;
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ pmu_assert(measured, cur);
+ }
+
+ igt_permute_array(frequencies,
+ ARRAY_SIZE(frequencies),
+ igt_exchange_int);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+#undef N_STEPS
+}
+
+static void inflight(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx, min, max, freq, discard;
+ double measured;
+ igt_spin_t *plug, *work[2];
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ gem_quiescent_gpu(fd);
+ plug = igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+ for (int n = 0; n < 16; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = plug->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = gem_context_create(fd),
+ };
+ set_freq(fd, eb.rsvd1, min, min);
+ gem_execbuf(fd, &eb);
+ gem_context_destroy(fd, eb.rsvd1);
+ }
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(plug): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, min);
+ pmu_assert(measured, min);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[0] = __igt_spin_batch_new(fd, ctx, engine, 0);
+
+ /* work is now queued but not executing */
+ freq = (max + min) / 2;
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &freq, &discard);
+ gem_context_destroy(fd, ctx);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[1] = __igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+
+ igt_spin_batch_end(plug);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, plug->handle));
+ igt_spin_batch_free(fd, plug);
+
+ /* Now work will execute */
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work0): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ pmu_assert(measured, freq);
+
+ igt_spin_batch_end(work[0]);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, work[0]->handle));
+ igt_spin_batch_free(fd, work[0]);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work1): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, max);
+ pmu_assert(measured, max);
+
+ igt_spin_batch_free(fd, work[1]);
+ close(pmu);
+ gem_quiescent_gpu(fd);
+}
+
+static void set_sysfs_freq(uint32_t min, uint32_t max)
+{
+ igt_sysfs_printf(sysfs, "gt_min_freq_mhz", "%u", min);
+ igt_sysfs_printf(sysfs, "gt_max_freq_mhz", "%u", max);
+}
+
+static void get_sysfs_freq(uint32_t *min, uint32_t *max)
+{
+ igt_sysfs_scanf(sysfs, "gt_min_freq_mhz", "%u", min);
+ igt_sysfs_scanf(sysfs, "gt_max_freq_mhz", "%u", max);
+}
+
+static void sysfs_clamp(int fd, const struct intel_execution_engine *e)
+{
+#define N_STEPS 10
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t sys_min, sys_max;
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_sysfs_freq(&sys_min, &sys_max);
+ igt_info("System min freq: %dMHz; max freq: %dMHz\n", sys_min, sys_max);
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Context min freq: %dMHz; max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ for (int outer = 0; outer <= 2*N_STEPS; outer++) {
+ int ofrac = outer > N_STEPS ? 2*N_STEPS - outer : outer;
+ uint32_t ofreq = min + (max - min) * ofrac / N_STEPS;
+ uint32_t cur, discard;
+
+ for (int inner = 0; inner <= 2*N_STEPS; inner++) {
+ int ifrac = inner > N_STEPS ? 2*N_STEPS - inner : inner;
+ uint32_t ifreq = min + (max - min) * ifrac / N_STEPS;
+
+ set_freq(fd, ctx, ifreq, ifreq);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ set_sysfs_freq(ofreq, ofreq);
+ get_sysfs_freq(&cur, &discard);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ set_sysfs_freq(sys_min, sys_max);
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(sysfs): Measured %.1fMHz, context %dMhz, expected %dMhz\n",
+ e->name, measured, ifreq, cur);
+ pmu_assert(measured, cur);
+ }
+ }
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+
+#undef N_STEPS
+}
+
+static void sandwich_engine(int fd, unsigned int engine, int timeout)
+{
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ get_freq(fd, ctx, &min, &max);
+
+ igt_until_timeout(timeout) {
+ uint32_t range[2];
+ igt_spin_t *spin;
+ double measured;
+
+ /* make sure we keep an overlap between all engines */
+ range[0] = min + (rand() % (max - min) / 2);
+ range[1] = max - (rand() % (max - min) / 2);
+
+ set_freq(fd, ctx, range[0], range[1]);
+ get_freq(fd, ctx, &range[0], &range[1]);
+
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+
+ usleep(10000);
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_spin_batch_free(fd, spin);
+
+ igt_assert(measured >= range[0] - PMU_TOLERANCE &&
+ measured <= range[1] + PMU_TOLERANCE);
+ }
+
+ gem_context_destroy(fd, ctx);
+ close(pmu);
+}
+
+static void sandwich(int fd, int timeout)
+{
+ unsigned int engine;
+
+ for_each_physical_engine(fd, engine) {
+ igt_fork(child, 1)
+ sandwich_engine(fd, engine, timeout);
+ }
+
+ igt_waitchildren();
+ gem_quiescent_gpu(fd);
+}
+
+static void pwm(int fd, unsigned int *engines, unsigned int nengine, int link)
+{
+ uint32_t ctx[nengine];
+
+ fcntl(link, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ for (unsigned int n = 0; n < nengine; n++)
+ ctx[n] = gem_context_create(fd);
+
+ do {
+ igt_spin_t *spin;
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+
+ while (read(link, &req, sizeof(req)) > 0) {
+ if ((req.engine | req.min | req.max) == 0)
+ goto out;
+
+ igt_assert(req.engine < nengine);
+ set_freq(fd, ctx[req.engine], req.min, req.max);
+ }
+
+ /* Create a 20% load using busy spinners */
+ spin = __igt_spin_batch_new(fd, ctx[0], engines[0], 0);
+ for (unsigned int n = 1; n < nengine; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engines[n],
+ .rsvd1 = ctx[n],
+ };
+ gem_execbuf(fd, &eb);
+ }
+ usleep(100);
+ igt_spin_batch_end(spin);
+
+ do
+ usleep(10);
+ while (gem_bo_busy(fd, spin->handle));
+ igt_spin_batch_free(fd, spin);
+ usleep(400);
+ } while (1);
+
+out:
+ for (unsigned int n = 0; n < nengine; n++)
+ gem_context_destroy(fd, ctx[n]);
+}
+
+static void smoketest(int fd, int timeout)
+{
+ unsigned int engines[16];
+ unsigned int nengine;
+ unsigned int engine;
+ uint32_t min[16], max[16];
+ int pmu, link[2];
+
+ get_freq(fd, 0, &min[0], &max[0]);
+
+ nengine = 0;
+ for_each_physical_engine(fd, engine) {
+ if (nengine == ARRAY_SIZE(engines) - 1)
+ break;
+
+ min[nengine] = min[0];
+ max[nengine] = max[0];
+ engines[nengine] = engine;
+ nengine++;
+ }
+ igt_require(nengine);
+
+ igt_assert(pipe(link) == 0);
+ igt_fork(child, 1)
+ pwm(fd, engines, nengine, link[0]);
+ close(link[0]);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ igt_until_timeout(timeout) {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+ double measured;
+ uint32_t ctx;
+
+ req.engine = rand() % nengine;
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &req.min, &req.max);
+ req.min = rand() % (req.max - req.min) + req.min;
+ req.max = rand() % (req.max - req.min) + req.min;
+ set_freq(fd, ctx, req.min, req.max);
+ get_freq(fd, ctx, &req.min, &req.max);
+
+ igt_debug("Replacing (%d, %d) on engine %x with (%d, %d)\n",
+ min[req.engine], max[req.engine], req.engine,
+ req.min, req.max);
+ igt_assert(write(link[1], &req, sizeof(req)) == sizeof(req));
+ gem_context_destroy(fd, ctx);
+
+ min[req.engine] = req.min;
+ max[req.engine] = req.max;
+
+ for (unsigned int n = 0; n < nengine; n++) {
+ igt_debug("[%d]: [%d, %d]\n", n, min[n], max[n]);
+ if (min[n] < req.min)
+ req.min = min[n];
+ if (max[n] > req.max)
+ req.max = max[n];
+ }
+ igt_assert(req.max >= req.min);
+
+ usleep(50000);
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+
+ if (measured <= req.min - PMU_TOLERANCE ||
+ measured >= req.max + PMU_TOLERANCE)
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("Measured %.1fMHz, expected [%d, %d]Mhz\n",
+ measured, req.min, req.max);
+ igt_assert(measured > req.min - PMU_TOLERANCE &&
+ measured < req.max + PMU_TOLERANCE);
+ }
+
+ do {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req = {};
+
+ write(link[1], &req, sizeof(req));
+ close(link[1]);
+ } while (0);
+ igt_waitchildren();
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+}
+
+static void invalid_context(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ const struct test {
+ uint32_t min, max;
+ } tests[] = {
+ { min - 50, max - 50 },
+ { min - 50, max },
+ { min - 50, max + 50 },
+ { min, max + 50 },
+ { min + 50, max + 50 },
+
+ { min - 50, min - 50 },
+
+ { min - 50, min },
+ { min + 50, min },
+ { min, min - 50 },
+
+ { max + 50, max },
+ { max, max + 50 },
+ { max, max - 50 },
+
+ { max + 50, max + 50 },
+
+ {}
+ };
+
+ for (const struct test *t = tests; t->min | t->max; t++) {
+ uint32_t cur_min, cur_max;
+
+ igt_assert_f(__set_freq(fd, ctx, t->min, t->max) == -EINVAL,
+ "Failed to reject invalid [%d, %d] (valid range [%d, %d]) on context %d\n",
+ t->min, t->max, min, max, ctx);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ }
+}
+
+static void invalid(int fd)
+{
+ uint32_t min, max, ctx;
+
+ get_freq(fd, 0, &min, &max);
+
+ invalid_context(fd, 0, min, max);
+
+ ctx = gem_context_create(fd);
+ invalid_context(fd, ctx, min, max);
+ gem_context_destroy(fd, ctx);
+}
+
+static void idempotent_context(int fd, uint32_t ctx)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, ctx, &min, &max);
+
+ set_freq(fd, ctx, max, max);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx, min, min);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ set_freq(fd, ctx, min, max);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void idempotent(int fd)
+{
+ uint32_t ctx;
+
+ idempotent_context(fd, 0);
+
+ ctx = gem_context_create(fd);
+ idempotent_context(fd, ctx);
+ gem_context_destroy(fd, ctx);
+}
+
+static void range_context(int fd, uint32_t ctx)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, ctx, &min, &max);
+
+ for (uint32_t freq = min; freq <= max; freq++) {
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+
+ igt_assert(cur_min >= min);
+ igt_assert(cur_max <= max);
+ }
+
+ set_freq(fd, ctx, min, max);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void range(int fd)
+{
+ uint32_t ctx;
+
+ range_context(fd, 0);
+
+ ctx = gem_context_create(fd);
+ range_context(fd, ctx);
+ gem_context_destroy(fd, ctx);
+}
+
+static void independent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+ uint32_t ctx[2];
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ ctx[0] = gem_context_create(fd);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ ctx[1] = gem_context_create(fd);
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx[1], max, max);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[1]);
+
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[0]);
+
+ set_freq(fd, 0, min, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+static void restore_sysfs_freq(int sig)
+{
+ char buf[256];
+
+ if (igt_sysfs_read(sysfs, "gt_RPn_freq_mhz", buf, sizeof(buf)) > 0) {
+ igt_sysfs_set(sysfs, "gt_idle_freq_mhz", buf);
+ igt_sysfs_set(sysfs, "gt_min_freq_mhz", buf);
+ }
+
+ if (igt_sysfs_read(sysfs, "gt_RP0_freq_mhz", buf, sizeof(buf)) > 0) {
+ igt_sysfs_set(sysfs, "gt_max_freq_mhz", buf);
+ igt_sysfs_set(sysfs, "gt_boost_freq_mhz", buf);
+ }
+}
+
+static void disable_boost(int fd)
+{
+ char *value;
+
+ value = igt_sysfs_get(fd, "gt_RPn_freq_mhz");
+ igt_sysfs_set(fd, "gt_boost_freq_mhz", value);
+ free(value);
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+
+ sysfs = igt_sysfs_open(fd, NULL);
+ igt_assert(sysfs != -1);
+ igt_install_exit_handler(restore_sysfs_freq);
+
+ disable_boost(sysfs);
+ }
+
+ igt_subtest("invalid")
+ invalid(fd);
+
+ igt_subtest("idempotent")
+ idempotent(fd);
+
+ igt_subtest("range")
+ range(fd);
+
+ igt_subtest("independent")
+ independent(fd);
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ igt_subtest_group {
+ igt_fixture {
+ gem_require_ring(fd, e->exec_id | e->flags);
+ }
+
+ igt_subtest_f("%s-single", e->name)
+ single(fd, e);
+ igt_subtest_f("%s-continuous", e->name)
+ continuous(fd, e);
+ igt_subtest_f("%s-inflight", e->name)
+ inflight(fd, e);
+ igt_subtest_f("%s-sysfs", e->name)
+ sysfs_clamp(fd, e);
+ }
+ }
+
+ igt_subtest("sandwich")
+ sandwich(fd, 20);
+
+ igt_subtest("smoketest")
+ smoketest(fd, 20);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 1176463c..f07ad25e 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -36,6 +36,7 @@ test_progs = [
'gem_ctx_create',
'gem_ctx_exec',
'gem_ctx_isolation',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-08 17:13 [PATCH igt] " Chris Wilson
` (2 preceding siblings ...)
2018-03-09 21:35 ` Chris Wilson
@ 2018-03-13 13:26 ` Chris Wilson
2018-03-13 13:58 ` Chris Wilson
4 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-13 13:26 UTC (permalink / raw)
To: intel-gfx; +Cc: igt-dev, Praveen Paneri
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
v2: Split single/continuous set_freq subtests
v3: Do an up/down ramp for individual freq request, check nothing
changes after each invalid request
v4: Check the frequencies reported by the kernel across the entire
range.
v5: Rewrite sandwich to create a sandwich between multiple concurrent
engines.
v6: Exercise sysfs overrides.
v7: Reset min/max of default context after independent(); don't ask
about failure
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Praveen Paneri <praveen.paneri@intel.com>
Cc: Sagar A Kamble <sagar.a.kamble@intel.com>
Cc: Antonio Argenziano <antonio.argenziano@intel.com>
Reviewed-by: Antonio Argenziano <antonio.argenziano@intel.com> #v5
---
tests/Makefile.am | 1 +
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 800 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 803 insertions(+)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index dbc7be72..389f7fc7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4e6f5319..a4ca85bc 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -58,6 +58,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_switch \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..35825ab8
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,800 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+#include "igt_sysfs.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 7
+
+#define SAMPLE_PERIOD (USEC_PER_SEC / 10)
+
+static int sysfs = -1;
+
+static int __set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ return __gem_context_set_param(fd, ¶m);
+}
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ igt_assert_eq(__set_freq(fd, ctx, min, max), 0);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int period_us)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(period_us);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+#define N_STEPS 10
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ for (int step = 0; step <= 2*N_STEPS; step++) {
+ int frac = step > N_STEPS ? 2*N_STEPS - step : step;
+ uint32_t freq = min + (max - min) * frac / N_STEPS;
+ uint32_t cur, discard;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+
+#undef N_STEPS
+}
+
+static void continuous(int fd, const struct intel_execution_engine *e)
+{
+#define N_STEPS 10
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (int step = 0; step <= 2*N_STEPS; step++) {
+ int frac = step > N_STEPS ? 2*N_STEPS - step : step;
+ uint32_t freq = min + (max - min) * frac / N_STEPS;
+ uint32_t cur, discard;
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+#undef N_STEPS
+}
+
+static void inflight(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx, min, max, freq, discard;
+ double measured;
+ igt_spin_t *plug, *work[2];
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ gem_quiescent_gpu(fd);
+ plug = igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+ for (int n = 0; n < 16; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = plug->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = gem_context_create(fd),
+ };
+ set_freq(fd, eb.rsvd1, min, min);
+ gem_execbuf(fd, &eb);
+ gem_context_destroy(fd, eb.rsvd1);
+ }
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(plug): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, min);
+ igt_assert(measured > min - 100 && measured < min + 100);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[0] = __igt_spin_batch_new(fd, ctx, engine, 0);
+
+ /* work is now queued but not executing */
+ freq = (max + min) / 2;
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &freq, &discard);
+ gem_context_destroy(fd, ctx);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[1] = __igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+
+ igt_spin_batch_end(plug);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, plug->handle));
+ igt_spin_batch_free(fd, plug);
+
+ /* Now work will execute */
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work0): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+
+ igt_spin_batch_end(work[0]);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, work[0]->handle));
+ igt_spin_batch_free(fd, work[0]);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work1): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, max);
+ igt_assert(measured > max - 100 && measured < max + 100);
+
+ igt_spin_batch_free(fd, work[1]);
+ close(pmu);
+ gem_quiescent_gpu(fd);
+}
+
+static void set_sysfs_freq(uint32_t min, uint32_t max)
+{
+ igt_sysfs_printf(sysfs, "gt_min_freq_mhz", "%u", min);
+ igt_sysfs_printf(sysfs, "gt_max_freq_mhz", "%u", max);
+}
+
+static void get_sysfs_freq(uint32_t *min, uint32_t *max)
+{
+ igt_sysfs_scanf(sysfs, "gt_min_freq_mhz", "%u", min);
+ igt_sysfs_scanf(sysfs, "gt_max_freq_mhz", "%u", max);
+}
+
+static void sysfs_clamp(int fd, const struct intel_execution_engine *e)
+{
+#define N_STEPS 10
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t sys_min, sys_max;
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_sysfs_freq(&sys_min, &sys_max);
+ igt_info("System min freq: %dMHz; max freq: %dMHz\n", sys_min, sys_max);
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Context min freq: %dMHz; max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ for (int outer = 0; outer <= 2*N_STEPS; outer++) {
+ int ofrac = outer > N_STEPS ? 2*N_STEPS - outer : outer;
+ uint32_t ofreq = min + (max - min) * ofrac / N_STEPS;
+ uint32_t cur, discard;
+
+ for (int inner = 0; inner <= 2*N_STEPS; inner++) {
+ int ifrac = inner > N_STEPS ? 2*N_STEPS - inner : inner;
+ uint32_t ifreq = min + (max - min) * ifrac / N_STEPS;
+
+ set_freq(fd, ctx, ifreq, ifreq);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ set_sysfs_freq(ofreq, ofreq);
+ get_sysfs_freq(&cur, &discard);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ set_sysfs_freq(sys_min, sys_max);
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(sysfs): Measured %.1fMHz, context %dMhz, expected %dMhz\n",
+ e->name, measured, ifreq, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ }
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+
+#undef N_STEPS
+}
+
+static void sandwich_engine(int fd, unsigned int engine, int timeout)
+{
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ get_freq(fd, ctx, &min, &max);
+
+ igt_until_timeout(timeout) {
+ uint32_t range[2];
+ igt_spin_t *spin;
+ double measured;
+
+ /* make sure we keep an overlap between all engines */
+ range[0] = min + (rand() % (max - min) / 2);
+ range[1] = max - (rand() % (max - min) / 2);
+
+ set_freq(fd, ctx, range[0], range[1]);
+ get_freq(fd, ctx, &range[0], &range[1]);
+
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+
+ usleep(10000);
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_spin_batch_free(fd, spin);
+
+ igt_assert(measured >= range[0] - 100 &&
+ measured <= range[1] + 100);
+ }
+
+ gem_context_destroy(fd, ctx);
+ close(pmu);
+}
+
+static void sandwich(int fd, int timeout)
+{
+ unsigned int engine;
+
+ for_each_physical_engine(fd, engine) {
+ igt_fork(child, 1)
+ sandwich_engine(fd, engine, timeout);
+ }
+
+ igt_waitchildren();
+ gem_quiescent_gpu(fd);
+}
+
+static void pwm(int fd, unsigned int *engines, unsigned int nengine, int link)
+{
+ uint32_t ctx[nengine];
+
+ fcntl(link, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ for (unsigned int n = 0; n < nengine; n++)
+ ctx[n] = gem_context_create(fd);
+
+ do {
+ igt_spin_t *spin;
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+
+ while (read(link, &req, sizeof(req)) > 0) {
+ if ((req.engine | req.min | req.max) == 0)
+ goto out;
+
+ igt_assert(req.engine < nengine);
+ set_freq(fd, ctx[req.engine], req.min, req.max);
+ }
+
+ /* Create a 20% load using busy spinners */
+ spin = __igt_spin_batch_new(fd, ctx[0], engines[0], 0);
+ for (unsigned int n = 1; n < nengine; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engines[n],
+ .rsvd1 = ctx[n],
+ };
+ gem_execbuf(fd, &eb);
+ }
+ usleep(100);
+ igt_spin_batch_end(spin);
+
+ do
+ usleep(10);
+ while (gem_bo_busy(fd, spin->handle));
+ igt_spin_batch_free(fd, spin);
+ usleep(400);
+ } while (1);
+
+out:
+ for (unsigned int n = 0; n < nengine; n++)
+ gem_context_destroy(fd, ctx[n]);
+}
+
+static void smoketest(int fd, int timeout)
+{
+ unsigned int engines[16];
+ unsigned int nengine;
+ unsigned int engine;
+ uint32_t min[16], max[16];
+ int pmu, link[2];
+
+ get_freq(fd, 0, &min[0], &max[0]);
+
+ nengine = 0;
+ for_each_physical_engine(fd, engine) {
+ if (nengine == ARRAY_SIZE(engines) - 1)
+ break;
+
+ min[nengine] = min[0];
+ max[nengine] = max[0];
+ engines[nengine] = engine;
+ nengine++;
+ }
+ igt_require(nengine);
+
+ igt_assert(pipe(link) == 0);
+ igt_fork(child, 1)
+ pwm(fd, engines, nengine, link[0]);
+ close(link[0]);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ igt_until_timeout(timeout) {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+ double measured;
+ uint32_t ctx;
+
+ req.engine = rand() % nengine;
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &req.min, &req.max);
+ req.min = rand() % (req.max - req.min) + req.min;
+ req.max = rand() % (req.max - req.min) + req.min;
+ set_freq(fd, ctx, req.min, req.max);
+ get_freq(fd, ctx, &req.min, &req.max);
+
+ igt_debug("Replacing (%d, %d) on engine %x with (%d, %d)\n",
+ min[req.engine], max[req.engine], req.engine,
+ req.min, req.max);
+ igt_assert(write(link[1], &req, sizeof(req)) == sizeof(req));
+ gem_context_destroy(fd, ctx);
+
+ min[req.engine] = req.min;
+ max[req.engine] = req.max;
+
+ for (unsigned int n = 0; n < nengine; n++) {
+ igt_debug("[%d]: [%d, %d]\n", n, min[n], max[n]);
+ if (min[n] < req.min)
+ req.min = min[n];
+ if (max[n] > req.max)
+ req.max = max[n];
+ }
+ igt_assert(req.max >= req.min);
+
+ usleep(50000);
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+
+ if (measured <= req.min - 100 || measured >= req.max + 100)
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("Measured %.1fMHz, expected [%d, %d]Mhz\n",
+ measured, req.min, req.max);
+ igt_assert(measured > req.min - 100 &&
+ measured < req.max + 100);
+ }
+
+ do {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req = {};
+
+ write(link[1], &req, sizeof(req));
+ close(link[1]);
+ } while (0);
+ igt_waitchildren();
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+}
+
+static void invalid_context(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ const struct test {
+ uint32_t min, max;
+ } tests[] = {
+ { min - 50, max - 50 },
+ { min - 50, max },
+ { min - 50, max + 50 },
+ { min, max + 50 },
+ { min + 50, max + 50 },
+
+ { min - 50, min - 50 },
+
+ { min - 50, min },
+ { min + 50, min },
+ { min, min - 50 },
+
+ { max + 50, max },
+ { max, max + 50 },
+ { max, max - 50 },
+
+ { max + 50, max + 50 },
+
+ {}
+ };
+
+ for (const struct test *t = tests; t->min | t->max; t++) {
+ uint32_t cur_min, cur_max;
+
+ igt_assert_f(__set_freq(fd, ctx, t->min, t->max) == -EINVAL,
+ "Failed to reject invalid [%d, %d] (valid range [%d, %d]) on context %d\n",
+ t->min, t->max, min, max, ctx);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ }
+}
+
+static void invalid(int fd)
+{
+ uint32_t min, max, ctx;
+
+ get_freq(fd, 0, &min, &max);
+
+ invalid_context(fd, 0, min, max);
+
+ ctx = gem_context_create(fd);
+ invalid_context(fd, ctx, min, max);
+ gem_context_destroy(fd, ctx);
+}
+
+static void idempotent_context(int fd, uint32_t ctx)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, ctx, &min, &max);
+
+ set_freq(fd, ctx, max, max);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx, min, min);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ set_freq(fd, ctx, min, max);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void idempotent(int fd)
+{
+ uint32_t ctx;
+
+ idempotent_context(fd, 0);
+
+ ctx = gem_context_create(fd);
+ idempotent_context(fd, ctx);
+ gem_context_destroy(fd, ctx);
+}
+
+static void range_context(int fd, uint32_t ctx)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, ctx, &min, &max);
+
+ for (uint32_t freq = min; freq <= max; freq++) {
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+
+ igt_assert(cur_min >= min);
+ igt_assert(cur_max <= max);
+ }
+
+ set_freq(fd, ctx, min, max);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void range(int fd)
+{
+ uint32_t ctx;
+
+ range_context(fd, 0);
+
+ ctx = gem_context_create(fd);
+ range_context(fd, ctx);
+ gem_context_destroy(fd, ctx);
+}
+
+static void independent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+ uint32_t ctx[2];
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ ctx[0] = gem_context_create(fd);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ ctx[1] = gem_context_create(fd);
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx[1], max, max);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[1]);
+
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[0]);
+
+ set_freq(fd, 0, &min, &max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+static void restore_sysfs_freq(int sig)
+{
+ char buf[256];
+
+ if (igt_sysfs_read(sysfs, "gt_RPn_freq_mhz", buf, sizeof(buf)) > 0) {
+ igt_sysfs_set(sysfs, "gt_idle_freq_mhz", buf);
+ igt_sysfs_set(sysfs, "gt_min_freq_mhz", buf);
+ }
+
+ if (igt_sysfs_read(sysfs, "gt_RP0_freq_mhz", buf, sizeof(buf)) > 0) {
+ igt_sysfs_set(sysfs, "gt_max_freq_mhz", buf);
+ igt_sysfs_set(sysfs, "gt_boost_freq_mhz", buf);
+ }
+}
+
+static void disable_boost(int fd)
+{
+ char *value;
+
+ value = igt_sysfs_get(fd, "gt_RPn_freq_mhz");
+ igt_sysfs_set(fd, "gt_boost_freq_mhz", value);
+ free(value);
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+
+ sysfs = igt_sysfs_open(fd, NULL);
+ igt_assert(sysfs != -1);
+ igt_install_exit_handler(restore_sysfs_freq);
+
+ disable_boost(sysfs);
+ }
+
+ igt_subtest("invalid")
+ invalid(fd);
+
+ igt_subtest("idempotent")
+ idempotent(fd);
+
+ igt_subtest("range")
+ range(fd);
+
+ igt_subtest("independent")
+ independent(fd);
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ igt_subtest_group {
+ igt_fixture {
+ gem_require_ring(fd, e->exec_id | e->flags);
+ }
+
+ igt_subtest_f("%s-single", e->name)
+ single(fd, e);
+ igt_subtest_f("%s-continuous", e->name)
+ continuous(fd, e);
+ igt_subtest_f("%s-inflight", e->name)
+ inflight(fd, e);
+ igt_subtest_f("%s-sysfs", e->name)
+ sysfs_clamp(fd, e);
+ }
+ }
+
+ igt_subtest("sandwich")
+ sandwich(fd, 20);
+
+ igt_subtest("smoketest")
+ smoketest(fd, 20);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 1176463c..f07ad25e 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -36,6 +36,7 @@ test_progs = [
'gem_ctx_create',
'gem_ctx_exec',
'gem_ctx_isolation',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-13 12:38 ` Sagar Arun Kamble
@ 2018-03-13 12:50 ` Chris Wilson
0 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-13 12:50 UTC (permalink / raw)
To: Sagar Arun Kamble, intel-gfx; +Cc: Praveen Paneri
Quoting Sagar Arun Kamble (2018-03-13 12:38:04)
>
>
> On 3/10/2018 3:05 AM, Chris Wilson wrote:
> > +static void single(int fd, const struct intel_execution_engine *e)
> > +{
> > +#define N_STEPS 10
> > + const unsigned int engine = e->exec_id | e->flags;
> > + uint32_t ctx = gem_context_create(fd);
> > + uint32_t min, max;
> > + double measured;
> > + igt_spin_t *spin;
> > + int pmu;
> > +
> > + get_freq(fd, ctx, &min, &max);
> > + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
> > +
> > + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> > + igt_require(pmu >= 0);
> This igt_require can go to igt_fixture below.
Why?
> > +
> > + for (int step = 0; step <= 2*N_STEPS; step++) {
> > + int frac = step > N_STEPS ? 2*N_STEPS - step : step;
> > + uint32_t freq = min + (max - min) * frac / N_STEPS;
> > + uint32_t cur, discard;
> > +
> > + set_freq(fd, ctx, freq, freq);
> > + get_freq(fd, ctx, &cur, &discard);
> > +
> > + gem_quiescent_gpu(fd);
> > + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> > + usleep(10000);
> > +
> > + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> > + igt_debugfs_dump(fd, "i915_rps_boost_info");
> > +
> > + igt_spin_batch_free(fd, spin);
> > + igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
> > + e->name, measured, cur);
> > + igt_assert(measured > cur - 100 && measured < cur + 100);
> Is this margin of 100Mhz for PMU accuracy?
Yes, even then it sometimes exceeds it.
> > + }
> > + gem_quiescent_gpu(fd);
> > +
> > + close(pmu);
> > + gem_context_destroy(fd, ctx);
> > +
> > +#undef N_STEPS
> > +}
> > +static void inflight(int fd, const struct intel_execution_engine *e)
> > +{
...
> > + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> > + igt_debugfs_dump(fd, "i915_rps_boost_info");
> > + igt_info("%s(plug): Measured %.1fMHz, expected %dMhz\n",
> > + e->name, measured, min);
> > + igt_assert(measured > min - 100 && measured < min + 100);
> > +
> > + ctx = gem_context_create(fd);
> > + set_freq(fd, ctx, max, max);
> this set_freq can be removed.
No, we want to check it obeys the later restriction and not this one.
> > + work[0] = __igt_spin_batch_new(fd, ctx, engine, 0);
> > +
> > + /* work is now queued but not executing */
> > + freq = (max + min) / 2;
> > + set_freq(fd, ctx, freq, freq);
> > + get_freq(fd, ctx, &freq, &discard);
> > + gem_context_destroy(fd, ctx);
> > + for (unsigned int n = 0; n < nengine; n++) {
> > + igt_debug("[%d]: [%d, %d]\n", n, min[n], max[n]);
> > + if (min[n] < req.min)
> > + req.min = min[n];
> > + if (max[n] > req.max)
> > + req.max = max[n];
> > + }
> I thought policy i915 will be implementing is max of mins and min of maxes.
But the only policy I want userspace to be aware of is that the actual
frequency will be inside their desired range. (Unless contradicted by
the system). That's the ABI we want; how we handle it internally should
be left open with the prospect of either changing it or making it
adjustable.
> > +static void invalid_context(int fd, uint32_t ctx, uint32_t min, uint32_t max)
> > +{
> > + const struct test {
> > + uint32_t min, max;
> > + } tests[] = {
> > + { min - 50, max - 50 },
> > + { min - 50, max },
> > + { min - 50, max + 50 },
> > + { min, max + 50 },
> > + { min + 50, max + 50 },
> > +
> > + { min - 50, min - 50 },
> > +
> > + { min - 50, min },
> This one is similar to { min - 50, max } where max is in range but min
> is outside.
> Similarly on max side. what is the reasoning for these cases?
Checking two wrongs don't make a right.
> > + { min + 50, min },
> > + { min, min - 50 },
> > +
> > + { max + 50, max },
> > + { max, max + 50 },
> > + { max, max - 50 },
> > +
> > + { max + 50, max + 50 },
> > +
> > + {}
> > + };
> > +
> > + for (const struct test *t = tests; t->min | t->max; t++) {
> > + uint32_t cur_min, cur_max;
> > +
> > + igt_assert_f(__set_freq(fd, ctx, t->min, t->max) == -EINVAL,
> > + "Failed to reject invalid [%d, %d] (valid range [%d, %d]) on context %d\n",
> > + t->min, t->max, min, max, ctx);
> > +
> > + get_freq(fd, 0, &cur_min, &cur_max);
> > + igt_assert_eq(cur_min, min);
> > + igt_assert_eq(cur_max, max);
> > + }
> > +}
> > +
> > +static void independent(int fd)
> > +{
> > + uint32_t min, max;
> > + uint32_t cur_min, cur_max;
> > + uint32_t ctx[2];
> > +
> > + get_freq(fd, 0, &min, &max);
> > +
> > + set_freq(fd, 0, max, max);
> > + ctx[0] = gem_context_create(fd);
> > + get_freq(fd, ctx[0], &cur_min, &cur_max);
> > + igt_assert_eq(cur_min, min);
> > + igt_assert_eq(cur_max, max);
> > +
> > + set_freq(fd, 0, min, min);
> > + get_freq(fd, ctx[0], &cur_min, &cur_max);
> > + igt_assert_eq(cur_min, min);
> > + igt_assert_eq(cur_max, max);
> > +
> > + ctx[1] = gem_context_create(fd);
> > + get_freq(fd, ctx[1], &cur_min, &cur_max);
> > + igt_assert_eq(cur_min, min);
> > + igt_assert_eq(cur_max, max);
> > +
> > + set_freq(fd, ctx[1], max, max);
> > + get_freq(fd, ctx[0], &cur_min, &cur_max);
> > + igt_assert_eq(cur_min, min);
> > + igt_assert_eq(cur_max, max);
> > +
> > + get_freq(fd, 0, &cur_min, &cur_max);
> > + igt_assert_eq(cur_min, min);
> > + igt_assert_eq(cur_max, min);
> > +
> > + get_freq(fd, ctx[1], &cur_min, &cur_max);
> > + igt_assert_eq(cur_min, max);
> > + igt_assert_eq(cur_max, max);
> > + gem_context_destroy(fd, ctx[1]);
> > +
> > + get_freq(fd, ctx[0], &cur_min, &cur_max);
> There is no set_freq between earlier get_freq and this one for ctx[0] so
> we can skip one.
The point of this test is to say for sure that actions on one context do
not affect another.
> > + igt_assert_eq(cur_min, min);
> > + igt_assert_eq(cur_max, max);
> > + gem_context_destroy(fd, ctx[0]);
> Need to restore min/max for default context?
No, we assert it isn't changed.
So you think we should assert again to be sure.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-09 21:35 ` Chris Wilson
2018-03-12 21:13 ` Antonio Argenziano
@ 2018-03-13 12:38 ` Sagar Arun Kamble
2018-03-13 12:50 ` Chris Wilson
1 sibling, 1 reply; 36+ messages in thread
From: Sagar Arun Kamble @ 2018-03-13 12:38 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: Praveen Paneri
On 3/10/2018 3:05 AM, Chris Wilson wrote:
> Exercise some new API that allows applications to request that
> individual contexts are executed within a desired frequency range.
>
> v2: Split single/continuous set_freq subtests
> v3: Do an up/down ramp for individual freq request, check nothing
> changes after each invalid request
> v4: Check the frequencies reported by the kernel across the entire
> range.
> v5: Rewrite sandwich to create a sandwich between multiple concurrent
> engines.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Praveen Paneri <praveen.paneri@intel.com>
> Cc: Sagar A Kamble <sagar.a.kamble@intel.com>
> Cc: Antonio Argenziano <antonio.argenziano@intel.com>
<snip>
> +static void single(int fd, const struct intel_execution_engine *e)
> +{
> +#define N_STEPS 10
> + const unsigned int engine = e->exec_id | e->flags;
> + uint32_t ctx = gem_context_create(fd);
> + uint32_t min, max;
> + double measured;
> + igt_spin_t *spin;
> + int pmu;
> +
> + get_freq(fd, ctx, &min, &max);
> + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
This igt_require can go to igt_fixture below.
> +
> + for (int step = 0; step <= 2*N_STEPS; step++) {
> + int frac = step > N_STEPS ? 2*N_STEPS - step : step;
> + uint32_t freq = min + (max - min) * frac / N_STEPS;
> + uint32_t cur, discard;
> +
> + set_freq(fd, ctx, freq, freq);
> + get_freq(fd, ctx, &cur, &discard);
> +
> + gem_quiescent_gpu(fd);
> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> + usleep(10000);
> +
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> +
> + igt_spin_batch_free(fd, spin);
> + igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
> + e->name, measured, cur);
> + igt_assert(measured > cur - 100 && measured < cur + 100);
Is this margin of 100Mhz for PMU accuracy?
> + }
> + gem_quiescent_gpu(fd);
> +
> + close(pmu);
> + gem_context_destroy(fd, ctx);
> +
> +#undef N_STEPS
> +}
> +
> +static void continuous(int fd, const struct intel_execution_engine *e)
> +{
> +#define N_STEPS 10
> + const unsigned int engine = e->exec_id | e->flags;
> + uint32_t ctx = gem_context_create(fd);
> + uint32_t min, max;
> + double measured;
> + igt_spin_t *spin;
> + int pmu;
> +
> + get_freq(fd, ctx, &min, &max);
> + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
> +
> + gem_quiescent_gpu(fd);
> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> + for (int step = 0; step <= 2*N_STEPS; step++) {
> + int frac = step > N_STEPS ? 2*N_STEPS - step : step;
> + uint32_t freq = min + (max - min) * frac / N_STEPS;
> + uint32_t cur, discard;
> + igt_spin_t *kick;
> +
> + set_freq(fd, ctx, freq, freq);
> + get_freq(fd, ctx, &cur, &discard);
> +
> + /*
> + * When requesting a new frequency on the currently
> + * executing context, it does not take effect until the
> + * next context switch. In this case, we trigger a lite
> + * restore.
> + */
> + kick = __igt_spin_batch_new(fd, ctx, engine, 0);
> + igt_spin_batch_free(fd, spin);
> + spin = kick;
> +
> + usleep(10000);
> +
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> +
> + igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
> + e->name, measured, cur);
> + igt_assert(measured > cur - 100 && measured < cur + 100);
> + }
> + igt_spin_batch_free(fd, spin);
> + gem_quiescent_gpu(fd);
> +
> + close(pmu);
> + gem_context_destroy(fd, ctx);
> +#undef N_STEPS
> +}
> +
> +static void inflight(int fd, const struct intel_execution_engine *e)
> +{
> + const unsigned int engine = e->exec_id | e->flags;
> + uint32_t ctx, min, max, freq, discard;
> + double measured;
> + igt_spin_t *plug, *work[2];
> + int pmu;
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
> +
> + ctx = gem_context_create(fd);
> + get_freq(fd, ctx, &min, &max);
> + set_freq(fd, ctx, min, min);
> +
> + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
> +
> + gem_quiescent_gpu(fd);
> + plug = igt_spin_batch_new(fd, ctx, engine, 0);
> + gem_context_destroy(fd, ctx);
> + for (int n = 0; n < 16; n++) {
> + struct drm_i915_gem_exec_object2 obj = {
> + .handle = plug->handle,
> + };
> + struct drm_i915_gem_execbuffer2 eb = {
> + .buffer_count = 1,
> + .buffers_ptr = to_user_pointer(&obj),
> + .flags = engine,
> + .rsvd1 = gem_context_create(fd),
> + };
> + set_freq(fd, eb.rsvd1, min, min);
> + gem_execbuf(fd, &eb);
> + gem_context_destroy(fd, eb.rsvd1);
> + }
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> + igt_info("%s(plug): Measured %.1fMHz, expected %dMhz\n",
> + e->name, measured, min);
> + igt_assert(measured > min - 100 && measured < min + 100);
> +
> + ctx = gem_context_create(fd);
> + set_freq(fd, ctx, max, max);
this set_freq can be removed.
> + work[0] = __igt_spin_batch_new(fd, ctx, engine, 0);
> +
> + /* work is now queued but not executing */
> + freq = (max + min) / 2;
> + set_freq(fd, ctx, freq, freq);
> + get_freq(fd, ctx, &freq, &discard);
> + gem_context_destroy(fd, ctx);
> +
> + ctx = gem_context_create(fd);
> + set_freq(fd, ctx, max, max);
> + work[1] = __igt_spin_batch_new(fd, ctx, engine, 0);
> + gem_context_destroy(fd, ctx);
> +
> + igt_spin_batch_end(plug);
> + do
> + usleep(10000);
> + while (gem_bo_busy(fd, plug->handle));
> + igt_spin_batch_free(fd, plug);
> +
> + /* Now work will execute */
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> + igt_debugfs_dump(fd, "i915_engine_info");
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> + igt_info("%s(work0): Measured %.1fMHz, expected %dMhz\n",
> + e->name, measured, freq);
> + igt_assert(measured > freq - 100 && measured < freq + 100);
> +
> + igt_spin_batch_end(work[0]);
> + do
> + usleep(10000);
> + while (gem_bo_busy(fd, work[0]->handle));
> + igt_spin_batch_free(fd, work[0]);
> +
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> + igt_debugfs_dump(fd, "i915_engine_info");
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> + igt_info("%s(work1): Measured %.1fMHz, expected %dMhz\n",
> + e->name, measured, max);
> + igt_assert(measured > max - 100 && measured < max + 100);
> +
> + igt_spin_batch_free(fd, work[1]);
> + close(pmu);
> + gem_quiescent_gpu(fd);
> +}
> +
> +static void sandwich_engine(int fd, unsigned int engine, int timeout)
> +{
> + uint32_t ctx = gem_context_create(fd);
> + uint32_t min, max;
> + int pmu;
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
> +
> + get_freq(fd, ctx, &min, &max);
> +
> + igt_until_timeout(timeout) {
> + uint32_t range[2];
> + igt_spin_t *spin;
> + double measured;
> +
> + /* make sure we keep an overlap between all engines */
> + range[0] = min + (rand() % (max - min) / 2);
> + range[1] = max - (rand() % (max - min) / 2);
> +
> + set_freq(fd, ctx, range[0], range[1]);
> + get_freq(fd, ctx, &range[0], &range[1]);
> +
> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> +
> + usleep(10000);
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> + igt_spin_batch_free(fd, spin);
> +
> + igt_assert(measured >= range[0] - 100 &&
> + measured <= range[1] + 100);
> + }
> +
> + gem_context_destroy(fd, ctx);
> + close(pmu);
> +}
> +
> +static void sandwich(int fd, int timeout)
> +{
> + unsigned int engine;
> +
> + for_each_physical_engine(fd, engine) {
> + igt_fork(child, 1)
> + sandwich_engine(fd, engine, timeout);
> + }
> +
> + igt_waitchildren();
> + gem_quiescent_gpu(fd);
> +}
> +
> +static void pwm(int fd, unsigned int *engines, unsigned int nengine, int link)
> +{
> + uint32_t ctx[nengine];
> +
> + fcntl(link, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
> +
> + for (unsigned int n = 0; n < nengine; n++)
> + ctx[n] = gem_context_create(fd);
> +
> + do {
> + igt_spin_t *spin;
> + struct {
> + uint32_t engine;
> + uint32_t min;
> + uint32_t max;
> + } req;
> +
> + while (read(link, &req, sizeof(req)) > 0) {
> + if ((req.engine | req.min | req.max) == 0)
> + goto out;
> +
> + igt_assert(req.engine < nengine);
> + set_freq(fd, ctx[req.engine], req.min, req.max);
> + }
> +
> + /* Create a 20% load using busy spinners */
> + spin = __igt_spin_batch_new(fd, ctx[0], engines[0], 0);
> + for (unsigned int n = 1; n < nengine; n++) {
> + struct drm_i915_gem_exec_object2 obj = {
> + .handle = spin->handle,
> + };
> + struct drm_i915_gem_execbuffer2 eb = {
> + .buffer_count = 1,
> + .buffers_ptr = to_user_pointer(&obj),
> + .flags = engines[n],
> + .rsvd1 = ctx[n],
> + };
> + gem_execbuf(fd, &eb);
> + }
> + usleep(100);
> + igt_spin_batch_end(spin);
> +
> + do
> + usleep(10);
> + while (gem_bo_busy(fd, spin->handle));
> + igt_spin_batch_free(fd, spin);
> + usleep(400);
> + } while (1);
> +
> +out:
> + for (unsigned int n = 0; n < nengine; n++)
> + gem_context_destroy(fd, ctx[n]);
> +}
> +
> +static void smoketest(int fd, int timeout)
> +{
> + unsigned int engines[16];
> + unsigned int nengine;
> + unsigned int engine;
> + uint32_t min[16], max[16];
> + int pmu, link[2];
> +
> + get_freq(fd, 0, &min[0], &max[0]);
> +
> + nengine = 0;
> + for_each_physical_engine(fd, engine) {
> + if (nengine == ARRAY_SIZE(engines) - 1)
> + break;
> +
> + min[nengine] = min[0];
> + max[nengine] = max[0];
> + engines[nengine] = engine;
> + nengine++;
> + }
> + igt_require(nengine);
> +
> + igt_assert(pipe(link) == 0);
> + igt_fork(child, 1)
> + pwm(fd, engines, nengine, link[0]);
> + close(link[0]);
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
> +
> + igt_until_timeout(timeout) {
> + struct {
> + uint32_t engine;
> + uint32_t min;
> + uint32_t max;
> + } req;
> + double measured;
> + uint32_t ctx;
> +
> + req.engine = rand() % nengine;
> +
> + ctx = gem_context_create(fd);
> + get_freq(fd, ctx, &req.min, &req.max);
> + req.min = rand() % (req.max - req.min) + req.min;
> + req.max = rand() % (req.max - req.min) + req.min;
> + set_freq(fd, ctx, req.min, req.max);
> + get_freq(fd, ctx, &req.min, &req.max);
> +
> + igt_debug("Replacing (%d, %d) on engine %x with (%d, %d)\n",
> + min[req.engine], max[req.engine], req.engine,
> + req.min, req.max);
> + igt_assert(write(link[1], &req, sizeof(req)) == sizeof(req));
> + gem_context_destroy(fd, ctx);
> +
> + min[req.engine] = req.min;
> + max[req.engine] = req.max;
> +
> + for (unsigned int n = 0; n < nengine; n++) {
> + igt_debug("[%d]: [%d, %d]\n", n, min[n], max[n]);
> + if (min[n] < req.min)
> + req.min = min[n];
> + if (max[n] > req.max)
> + req.max = max[n];
> + }
I thought policy i915 will be implementing is max of mins and min of maxes.
> + igt_assert(req.max >= req.min);
> +
> + usleep(50000);
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> +
> + if (measured <= req.min - 100 || measured >= req.max + 100)
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> + igt_info("Measured %.1fMHz, expected [%d, %d]Mhz\n",
> + measured, req.min, req.max);
> + igt_assert(measured > req.min - 100 &&
> + measured < req.max + 100);
> + }
> +
> + do {
> + struct {
> + uint32_t engine;
> + uint32_t min;
> + uint32_t max;
> + } req = {};
> +
> + write(link[1], &req, sizeof(req));
> + close(link[1]);
> + } while (0);
> + igt_waitchildren();
> + gem_quiescent_gpu(fd);
> +
> + close(pmu);
> +}
> +
> +static void invalid_context(int fd, uint32_t ctx, uint32_t min, uint32_t max)
> +{
> + const struct test {
> + uint32_t min, max;
> + } tests[] = {
> + { min - 50, max - 50 },
> + { min - 50, max },
> + { min - 50, max + 50 },
> + { min, max + 50 },
> + { min + 50, max + 50 },
> +
> + { min - 50, min - 50 },
> +
> + { min - 50, min },
This one is similar to { min - 50, max } where max is in range but min
is outside.
Similarly on max side. what is the reasoning for these cases?
> + { min + 50, min },
> + { min, min - 50 },
> +
> + { max + 50, max },
> + { max, max + 50 },
> + { max, max - 50 },
> +
> + { max + 50, max + 50 },
> +
> + {}
> + };
> +
> + for (const struct test *t = tests; t->min | t->max; t++) {
> + uint32_t cur_min, cur_max;
> +
> + igt_assert_f(__set_freq(fd, ctx, t->min, t->max) == -EINVAL,
> + "Failed to reject invalid [%d, %d] (valid range [%d, %d]) on context %d\n",
> + t->min, t->max, min, max, ctx);
> +
> + get_freq(fd, 0, &cur_min, &cur_max);
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, max);
> + }
> +}
> +
> +static void invalid(int fd)
> +{
> + uint32_t min, max, ctx;
> +
> + get_freq(fd, 0, &min, &max);
> +
> + invalid_context(fd, 0, min, max);
> +
> + ctx = gem_context_create(fd);
> + invalid_context(fd, ctx, min, max);
> + gem_context_destroy(fd, ctx);
> +}
> +
> +static void idempotent_context(int fd, uint32_t ctx)
> +{
> + uint32_t min, max;
> + uint32_t cur_min, cur_max;
> +
> + get_freq(fd, ctx, &min, &max);
> +
> + set_freq(fd, ctx, max, max);
> + get_freq(fd, ctx, &cur_min, &cur_max);
> + igt_assert_eq(cur_min, max);
> + igt_assert_eq(cur_max, max);
> +
> + set_freq(fd, ctx, min, min);
> + get_freq(fd, ctx, &cur_min, &cur_max);
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, min);
> +
> + set_freq(fd, ctx, min, max);
> + get_freq(fd, ctx, &cur_min, &cur_max);
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, max);
> +}
> +
> +static void idempotent(int fd)
> +{
> + uint32_t ctx;
> +
> + idempotent_context(fd, 0);
> +
> + ctx = gem_context_create(fd);
> + idempotent_context(fd, ctx);
> + gem_context_destroy(fd, ctx);
> +}
> +
> +static void range_context(int fd, uint32_t ctx)
> +{
> + uint32_t min, max;
> + uint32_t cur_min, cur_max;
> +
> + get_freq(fd, ctx, &min, &max);
> +
> + for (uint32_t freq = min; freq <= max; freq++) {
> + set_freq(fd, ctx, freq, freq);
> + get_freq(fd, ctx, &cur_min, &cur_max);
> +
> + igt_assert(cur_min >= min);
> + igt_assert(cur_max <= max);
> + }
> +
> + set_freq(fd, ctx, min, max);
> + get_freq(fd, ctx, &cur_min, &cur_max);
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, max);
> +}
> +
> +static void range(int fd)
> +{
> + uint32_t ctx;
> +
> + range_context(fd, 0);
> +
> + ctx = gem_context_create(fd);
> + range_context(fd, ctx);
> + gem_context_destroy(fd, ctx);
> +}
> +
> +static void independent(int fd)
> +{
> + uint32_t min, max;
> + uint32_t cur_min, cur_max;
> + uint32_t ctx[2];
> +
> + get_freq(fd, 0, &min, &max);
> +
> + set_freq(fd, 0, max, max);
> + ctx[0] = gem_context_create(fd);
> + get_freq(fd, ctx[0], &cur_min, &cur_max);
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, max);
> +
> + set_freq(fd, 0, min, min);
> + get_freq(fd, ctx[0], &cur_min, &cur_max);
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, max);
> +
> + ctx[1] = gem_context_create(fd);
> + get_freq(fd, ctx[1], &cur_min, &cur_max);
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, max);
> +
> + set_freq(fd, ctx[1], max, max);
> + get_freq(fd, ctx[0], &cur_min, &cur_max);
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, max);
> +
> + get_freq(fd, 0, &cur_min, &cur_max);
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, min);
> +
> + get_freq(fd, ctx[1], &cur_min, &cur_max);
> + igt_assert_eq(cur_min, max);
> + igt_assert_eq(cur_max, max);
> + gem_context_destroy(fd, ctx[1]);
> +
> + get_freq(fd, ctx[0], &cur_min, &cur_max);
There is no set_freq between earlier get_freq and this one for ctx[0] so
we can skip one.
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, max);
> + gem_context_destroy(fd, ctx[0]);
Need to restore min/max for default context?
> +}
> +
> +static bool has_ctx_freq(int fd)
> +{
> + struct drm_i915_gem_context_param param = {
> + .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
> + };
> +
> + return __gem_context_get_param(fd, ¶m) == 0;
> +}
> +
> +igt_main
> +{
> + const struct intel_execution_engine *e;
> + int fd = -1;
> +
> + igt_fixture {
> + fd = drm_open_driver(DRIVER_INTEL);
> + igt_require_gem(fd);
> +
> + igt_require(has_ctx_freq(fd));
> + }
> +
> + igt_subtest("invalid")
> + invalid(fd);
> +
> + igt_subtest("idempotent")
> + idempotent(fd);
> +
> + igt_subtest("range")
> + range(fd);
> +
> + igt_subtest("independent")
> + independent(fd);
> +
> + igt_skip_on_simulation();
> +
> + for (e = intel_execution_engines; e->name; e++) {
> + igt_subtest_group {
> + igt_fixture {
> + gem_require_ring(fd, e->exec_id | e->flags);
> + }
> +
> + igt_subtest_f("%s-single", e->name)
> + single(fd, e);
> + igt_subtest_f("%s-continuous", e->name)
> + continuous(fd, e);
> + igt_subtest_f("%s-inflight", e->name)
> + inflight(fd, e);
> + }
> + }
> +
> + igt_subtest("sandwich")
> + sandwich(fd, 20);
> +
> + igt_subtest("smoketest")
> + smoketest(fd, 20);
> +}
> diff --git a/tests/meson.build b/tests/meson.build
> index 6e776bb7..fa5e3169 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -36,6 +36,7 @@ test_progs = [
> 'gem_ctx_create',
> 'gem_ctx_exec',
> 'gem_ctx_isolation',
> + 'gem_ctx_freq',
this should be one entry above
> 'gem_ctx_param',
> 'gem_ctx_switch',
> 'gem_ctx_thrash',
--
Thanks,
Sagar
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-09 21:35 ` Chris Wilson
@ 2018-03-12 21:13 ` Antonio Argenziano
2018-03-13 12:38 ` Sagar Arun Kamble
1 sibling, 0 replies; 36+ messages in thread
From: Antonio Argenziano @ 2018-03-12 21:13 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: Praveen Paneri
On 09/03/18 13:35, Chris Wilson wrote:
> Exercise some new API that allows applications to request that
> individual contexts are executed within a desired frequency range.
>
> v2: Split single/continuous set_freq subtests
> v3: Do an up/down ramp for individual freq request, check nothing
> changes after each invalid request
> v4: Check the frequencies reported by the kernel across the entire
> range.
> v5: Rewrite sandwich to create a sandwich between multiple concurrent
> engines.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Praveen Paneri <praveen.paneri@intel.com>
> Cc: Sagar A Kamble <sagar.a.kamble@intel.com>
> Cc: Antonio Argenziano <antonio.argenziano@intel.com>
LGTM.
Reviewed-by: Antonio Argenziano <antonio.argenziano@intel.com>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-08 17:13 [PATCH igt] " Chris Wilson
2018-03-09 0:45 ` Antonio Argenziano
2018-03-09 13:46 ` Chris Wilson
@ 2018-03-09 21:35 ` Chris Wilson
2018-03-12 21:13 ` Antonio Argenziano
2018-03-13 12:38 ` Sagar Arun Kamble
2018-03-13 13:26 ` Chris Wilson
2018-03-13 13:58 ` Chris Wilson
4 siblings, 2 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-09 21:35 UTC (permalink / raw)
To: intel-gfx; +Cc: Praveen Paneri
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
v2: Split single/continuous set_freq subtests
v3: Do an up/down ramp for individual freq request, check nothing
changes after each invalid request
v4: Check the frequencies reported by the kernel across the entire
range.
v5: Rewrite sandwich to create a sandwich between multiple concurrent
engines.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Praveen Paneri <praveen.paneri@intel.com>
Cc: Sagar A Kamble <sagar.a.kamble@intel.com>
Cc: Antonio Argenziano <antonio.argenziano@intel.com>
---
tests/Makefile.am | 1 +
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 691 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 694 insertions(+)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index dbc7be72..389f7fc7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4a81ac4a..3d079c42 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -58,6 +58,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_switch \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..fc5df3d9
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,691 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 7
+
+#define SAMPLE_PERIOD (USEC_PER_SEC / 10)
+
+static int __set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ return __gem_context_set_param(fd, ¶m);
+}
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ igt_assert_eq(__set_freq(fd, ctx, min, max), 0);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int period_us)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(period_us);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+#define N_STEPS 10
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ for (int step = 0; step <= 2*N_STEPS; step++) {
+ int frac = step > N_STEPS ? 2*N_STEPS - step : step;
+ uint32_t freq = min + (max - min) * frac / N_STEPS;
+ uint32_t cur, discard;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+
+#undef N_STEPS
+}
+
+static void continuous(int fd, const struct intel_execution_engine *e)
+{
+#define N_STEPS 10
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (int step = 0; step <= 2*N_STEPS; step++) {
+ int frac = step > N_STEPS ? 2*N_STEPS - step : step;
+ uint32_t freq = min + (max - min) * frac / N_STEPS;
+ uint32_t cur, discard;
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+#undef N_STEPS
+}
+
+static void inflight(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx, min, max, freq, discard;
+ double measured;
+ igt_spin_t *plug, *work[2];
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ gem_quiescent_gpu(fd);
+ plug = igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+ for (int n = 0; n < 16; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = plug->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = gem_context_create(fd),
+ };
+ set_freq(fd, eb.rsvd1, min, min);
+ gem_execbuf(fd, &eb);
+ gem_context_destroy(fd, eb.rsvd1);
+ }
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(plug): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, min);
+ igt_assert(measured > min - 100 && measured < min + 100);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[0] = __igt_spin_batch_new(fd, ctx, engine, 0);
+
+ /* work is now queued but not executing */
+ freq = (max + min) / 2;
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &freq, &discard);
+ gem_context_destroy(fd, ctx);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[1] = __igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+
+ igt_spin_batch_end(plug);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, plug->handle));
+ igt_spin_batch_free(fd, plug);
+
+ /* Now work will execute */
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work0): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+
+ igt_spin_batch_end(work[0]);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, work[0]->handle));
+ igt_spin_batch_free(fd, work[0]);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work1): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, max);
+ igt_assert(measured > max - 100 && measured < max + 100);
+
+ igt_spin_batch_free(fd, work[1]);
+ close(pmu);
+ gem_quiescent_gpu(fd);
+}
+
+static void sandwich_engine(int fd, unsigned int engine, int timeout)
+{
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ get_freq(fd, ctx, &min, &max);
+
+ igt_until_timeout(timeout) {
+ uint32_t range[2];
+ igt_spin_t *spin;
+ double measured;
+
+ /* make sure we keep an overlap between all engines */
+ range[0] = min + (rand() % (max - min) / 2);
+ range[1] = max - (rand() % (max - min) / 2);
+
+ set_freq(fd, ctx, range[0], range[1]);
+ get_freq(fd, ctx, &range[0], &range[1]);
+
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+
+ usleep(10000);
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_spin_batch_free(fd, spin);
+
+ igt_assert(measured >= range[0] - 100 &&
+ measured <= range[1] + 100);
+ }
+
+ gem_context_destroy(fd, ctx);
+ close(pmu);
+}
+
+static void sandwich(int fd, int timeout)
+{
+ unsigned int engine;
+
+ for_each_physical_engine(fd, engine) {
+ igt_fork(child, 1)
+ sandwich_engine(fd, engine, timeout);
+ }
+
+ igt_waitchildren();
+ gem_quiescent_gpu(fd);
+}
+
+static void pwm(int fd, unsigned int *engines, unsigned int nengine, int link)
+{
+ uint32_t ctx[nengine];
+
+ fcntl(link, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ for (unsigned int n = 0; n < nengine; n++)
+ ctx[n] = gem_context_create(fd);
+
+ do {
+ igt_spin_t *spin;
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+
+ while (read(link, &req, sizeof(req)) > 0) {
+ if ((req.engine | req.min | req.max) == 0)
+ goto out;
+
+ igt_assert(req.engine < nengine);
+ set_freq(fd, ctx[req.engine], req.min, req.max);
+ }
+
+ /* Create a 20% load using busy spinners */
+ spin = __igt_spin_batch_new(fd, ctx[0], engines[0], 0);
+ for (unsigned int n = 1; n < nengine; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engines[n],
+ .rsvd1 = ctx[n],
+ };
+ gem_execbuf(fd, &eb);
+ }
+ usleep(100);
+ igt_spin_batch_end(spin);
+
+ do
+ usleep(10);
+ while (gem_bo_busy(fd, spin->handle));
+ igt_spin_batch_free(fd, spin);
+ usleep(400);
+ } while (1);
+
+out:
+ for (unsigned int n = 0; n < nengine; n++)
+ gem_context_destroy(fd, ctx[n]);
+}
+
+static void smoketest(int fd, int timeout)
+{
+ unsigned int engines[16];
+ unsigned int nengine;
+ unsigned int engine;
+ uint32_t min[16], max[16];
+ int pmu, link[2];
+
+ get_freq(fd, 0, &min[0], &max[0]);
+
+ nengine = 0;
+ for_each_physical_engine(fd, engine) {
+ if (nengine == ARRAY_SIZE(engines) - 1)
+ break;
+
+ min[nengine] = min[0];
+ max[nengine] = max[0];
+ engines[nengine] = engine;
+ nengine++;
+ }
+ igt_require(nengine);
+
+ igt_assert(pipe(link) == 0);
+ igt_fork(child, 1)
+ pwm(fd, engines, nengine, link[0]);
+ close(link[0]);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ igt_until_timeout(timeout) {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+ double measured;
+ uint32_t ctx;
+
+ req.engine = rand() % nengine;
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &req.min, &req.max);
+ req.min = rand() % (req.max - req.min) + req.min;
+ req.max = rand() % (req.max - req.min) + req.min;
+ set_freq(fd, ctx, req.min, req.max);
+ get_freq(fd, ctx, &req.min, &req.max);
+
+ igt_debug("Replacing (%d, %d) on engine %x with (%d, %d)\n",
+ min[req.engine], max[req.engine], req.engine,
+ req.min, req.max);
+ igt_assert(write(link[1], &req, sizeof(req)) == sizeof(req));
+ gem_context_destroy(fd, ctx);
+
+ min[req.engine] = req.min;
+ max[req.engine] = req.max;
+
+ for (unsigned int n = 0; n < nengine; n++) {
+ igt_debug("[%d]: [%d, %d]\n", n, min[n], max[n]);
+ if (min[n] < req.min)
+ req.min = min[n];
+ if (max[n] > req.max)
+ req.max = max[n];
+ }
+ igt_assert(req.max >= req.min);
+
+ usleep(50000);
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+
+ if (measured <= req.min - 100 || measured >= req.max + 100)
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("Measured %.1fMHz, expected [%d, %d]Mhz\n",
+ measured, req.min, req.max);
+ igt_assert(measured > req.min - 100 &&
+ measured < req.max + 100);
+ }
+
+ do {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req = {};
+
+ write(link[1], &req, sizeof(req));
+ close(link[1]);
+ } while (0);
+ igt_waitchildren();
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+}
+
+static void invalid_context(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ const struct test {
+ uint32_t min, max;
+ } tests[] = {
+ { min - 50, max - 50 },
+ { min - 50, max },
+ { min - 50, max + 50 },
+ { min, max + 50 },
+ { min + 50, max + 50 },
+
+ { min - 50, min - 50 },
+
+ { min - 50, min },
+ { min + 50, min },
+ { min, min - 50 },
+
+ { max + 50, max },
+ { max, max + 50 },
+ { max, max - 50 },
+
+ { max + 50, max + 50 },
+
+ {}
+ };
+
+ for (const struct test *t = tests; t->min | t->max; t++) {
+ uint32_t cur_min, cur_max;
+
+ igt_assert_f(__set_freq(fd, ctx, t->min, t->max) == -EINVAL,
+ "Failed to reject invalid [%d, %d] (valid range [%d, %d]) on context %d\n",
+ t->min, t->max, min, max, ctx);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ }
+}
+
+static void invalid(int fd)
+{
+ uint32_t min, max, ctx;
+
+ get_freq(fd, 0, &min, &max);
+
+ invalid_context(fd, 0, min, max);
+
+ ctx = gem_context_create(fd);
+ invalid_context(fd, ctx, min, max);
+ gem_context_destroy(fd, ctx);
+}
+
+static void idempotent_context(int fd, uint32_t ctx)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, ctx, &min, &max);
+
+ set_freq(fd, ctx, max, max);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx, min, min);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ set_freq(fd, ctx, min, max);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void idempotent(int fd)
+{
+ uint32_t ctx;
+
+ idempotent_context(fd, 0);
+
+ ctx = gem_context_create(fd);
+ idempotent_context(fd, ctx);
+ gem_context_destroy(fd, ctx);
+}
+
+static void range_context(int fd, uint32_t ctx)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, ctx, &min, &max);
+
+ for (uint32_t freq = min; freq <= max; freq++) {
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+
+ igt_assert(cur_min >= min);
+ igt_assert(cur_max <= max);
+ }
+
+ set_freq(fd, ctx, min, max);
+ get_freq(fd, ctx, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void range(int fd)
+{
+ uint32_t ctx;
+
+ range_context(fd, 0);
+
+ ctx = gem_context_create(fd);
+ range_context(fd, ctx);
+ gem_context_destroy(fd, ctx);
+}
+
+static void independent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+ uint32_t ctx[2];
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ ctx[0] = gem_context_create(fd);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ ctx[1] = gem_context_create(fd);
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx[1], max, max);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[1]);
+
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[0]);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+ }
+
+ igt_subtest("invalid")
+ invalid(fd);
+
+ igt_subtest("idempotent")
+ idempotent(fd);
+
+ igt_subtest("range")
+ range(fd);
+
+ igt_subtest("independent")
+ independent(fd);
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ igt_subtest_group {
+ igt_fixture {
+ gem_require_ring(fd, e->exec_id | e->flags);
+ }
+
+ igt_subtest_f("%s-single", e->name)
+ single(fd, e);
+ igt_subtest_f("%s-continuous", e->name)
+ continuous(fd, e);
+ igt_subtest_f("%s-inflight", e->name)
+ inflight(fd, e);
+ }
+ }
+
+ igt_subtest("sandwich")
+ sandwich(fd, 20);
+
+ igt_subtest("smoketest")
+ smoketest(fd, 20);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 6e776bb7..fa5e3169 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -36,6 +36,7 @@ test_progs = [
'gem_ctx_create',
'gem_ctx_exec',
'gem_ctx_isolation',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-09 19:15 ` Antonio Argenziano
@ 2018-03-09 20:37 ` Chris Wilson
0 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-09 20:37 UTC (permalink / raw)
To: Antonio Argenziano, intel-gfx; +Cc: igt-dev, Praveen
Quoting Antonio Argenziano (2018-03-09 19:15:45)
>
>
> On 08/03/18 17:03, Chris Wilson wrote:
> > Quoting Antonio Argenziano (2018-03-09 00:45:42)
> >>
> >>
> >> On 08/03/18 09:13, Chris Wilson wrote:
> >>> Exercise some new API that allows applications to request that
> >>> individual contexts are executed within a desired frequency range.
> >>>
> >>> v2: Split single/continuous set_freq subtests
> >>>
> >>> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> >>> Cc: Paneri, Praveen <praveen.paneri@intel.com>
> >>> Cc: Kamble, Sagar A <sagar.a.kamble@intel.com>
> >>> Cc: Antonio Argenziano <antonio.argenziano@intel.com>
> >>> ---
> >>> tests/Makefile.am | 1 +
> >>> tests/Makefile.sources | 1 +
> >>> tests/gem_ctx_freq.c | 604 +++++++++++++++++++++++++++++++++++++++++++++++++
> >>> tests/meson.build | 1 +
> >>> 4 files changed, 607 insertions(+)
> >>> create mode 100644 tests/gem_ctx_freq.c
> >>>
> >>
>
> >>> + uint32_t cur, discard;
> >>> +
> >>> + set_freq(fd, ctx, freq, freq);
> >>> + get_freq(fd, ctx, &cur, &discard);
> >>
> >> igt_assert_eq(freq, cur)?
> >
> > Not quite. The trick is that the interface is not strictly idempotent,
> > since we pass in MHz, the driver converts that into freq bins and spits
> > it back out to the nearest MHz. So cur is not strictly freq, it just
> > happens that 50MHz is the bin size on gen9.
> >
> > The idea here is that we grab the adjusted freq from the driver to
> > validate with.
>
> I see, can we enforce a tolerance? It feels like we are trusting the
> kernel too much, but if that is the only thing we can do...
for (i = min; i <= max; i++)
igt_assert(min <= set_and_fetch_freq(i) <= max);
I don't think we want to constrain the ABI any more than that.
But adding that level of check seems ok.
The behaviour is we ask the kernel for a range, the kernel tells us what
range it can provide based on the request. Then we expect that the
kernel upholds that contract. (Except where we make a conflicting
contract with another party, either parallel execution or sysadmin
override.)
Binding ourselves into a tighter contract feels overly prescriptive and
not flexible enough to weasel our way out of bad situations in future.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-09 1:03 ` Chris Wilson
@ 2018-03-09 19:15 ` Antonio Argenziano
2018-03-09 20:37 ` Chris Wilson
0 siblings, 1 reply; 36+ messages in thread
From: Antonio Argenziano @ 2018-03-09 19:15 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: igt-dev, Praveen
On 08/03/18 17:03, Chris Wilson wrote:
> Quoting Antonio Argenziano (2018-03-09 00:45:42)
>>
>>
>> On 08/03/18 09:13, Chris Wilson wrote:
>>> Exercise some new API that allows applications to request that
>>> individual contexts are executed within a desired frequency range.
>>>
>>> v2: Split single/continuous set_freq subtests
>>>
>>> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
>>> Cc: Paneri, Praveen <praveen.paneri@intel.com>
>>> Cc: Kamble, Sagar A <sagar.a.kamble@intel.com>
>>> Cc: Antonio Argenziano <antonio.argenziano@intel.com>
>>> ---
>>> tests/Makefile.am | 1 +
>>> tests/Makefile.sources | 1 +
>>> tests/gem_ctx_freq.c | 604 +++++++++++++++++++++++++++++++++++++++++++++++++
>>> tests/meson.build | 1 +
>>> 4 files changed, 607 insertions(+)
>>> create mode 100644 tests/gem_ctx_freq.c
>>>
>>
>>> + uint32_t cur, discard;
>>> +
>>> + set_freq(fd, ctx, freq, freq);
>>> + get_freq(fd, ctx, &cur, &discard);
>>
>> igt_assert_eq(freq, cur)?
>
> Not quite. The trick is that the interface is not strictly idempotent,
> since we pass in MHz, the driver converts that into freq bins and spits
> it back out to the nearest MHz. So cur is not strictly freq, it just
> happens that 50MHz is the bin size on gen9.
>
> The idea here is that we grab the adjusted freq from the driver to
> validate with.
I see, can we enforce a tolerance? It feels like we are trusting the
kernel too much, but if that is the only thing we can do...
>>> +static void smoketest(int fd, int timeout)
>>> +{
>>> + unsigned int engines[16];
>>
>> use a macro instead of magic number 16.
>
> #define THIS_IS_FAR_MORE_MAGIC_THAN_A_MEANINGLESS_BARE_NUMBER_THAT_YOU_SHOULD_NOT_BE_READING_ANYTHING_INTO 16
> /rant
We call that MAX_EGINES in gem_exec_schedule ;).
Thanks,
Antonio
>
>>> +static void invalid_param(int fd)
>>> +{
>>
>> gem_ctx_param is going to be upset again pretty soon ;).
>
> Poor thing.
> -Chris
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-09 17:06 ` Tvrtko Ursulin
@ 2018-03-09 17:24 ` Chris Wilson
0 siblings, 0 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-09 17:24 UTC (permalink / raw)
To: Tvrtko Ursulin, intel-gfx; +Cc: igt-dev, Praveen
Quoting Tvrtko Ursulin (2018-03-09 17:06:45)
>
> On 09/03/2018 13:46, Chris Wilson wrote:
> > Exercise some new API that allows applications to request that
> > individual contexts are executed within a desired frequency range.
> >
> > v2: Split single/continuous set_freq subtests
> > v3: Do an up/down ramp for individual freq request, check nothing
> > changes after each invalid request
> >
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > Cc: Paneri, Praveen <praveen.paneri@intel.com>
> > Cc: Kamble, Sagar A <sagar.a.kamble@intel.com>
> > Cc: Antonio Argenziano <antonio.argenziano@intel.com>
> > ---
> > tests/Makefile.am | 1 +
> > tests/Makefile.sources | 1 +
> > tests/gem_ctx_freq.c | 648 +++++++++++++++++++++++++++++++++++++++++++++++++
> > tests/meson.build | 1 +
> > 4 files changed, 651 insertions(+)
> > create mode 100644 tests/gem_ctx_freq.c
> >
>
> [snip]
>
> > +static void check_invalid(int fd, uint32_t ctx, uint32_t min, uint32_t max)
> > +{
> > + const struct test {
> > + uint32_t min, max;
> > + } tests[] = {
> > + { min - 50, max - 50 },
> > + { min - 50, max },
> > + { min - 50, max + 50 },
> > + { min, max + 50 },
> > + { min + 50, max + 50 },
> > +
> > + { min - 50, min - 50 },
> > +
> > + { min - 50, min },
> > + { min + 50, min },
> > + { min, min - 50 },
> > +
> > + { max + 50, max },
> > + { max, max + 50 },
> > + { max, max - 50 },
> > +
> > + { max + 50, max + 50 },
>
> Is unprivileged "{ max, max }" allowed? In other words pin to max
> frequency by anyone? If so, what happens when all userspace learns about
> this and wants to use it just so to be lower latency than the other guy?
I've gone with allow, since (a) it's always constrained by the global
user imposed limit and (b) userspace can already keep the gpu at max
frequency by load. At the start I opined that only CAP_SYS_NICE would be
allowed to raise the frequency bounds, but realised that in practice it
is immaterial as they were already running at max frequency anyway.
/*
* As we constrain the frequency request from the
* context (application) by the sysadmin imposed limits,
* it is reasonable to allow the application to
* specify its preferred range within those limits.
* That is we do not need to restrict requesting
* a higher frequency to privileged (CAP_SYS_NICE)
* processes.
*/
> Or even on our integrated graphics, such userspace would unwisely take
> away power budget from the CPU. Or could it even harm itself by
> triggering too much thermal throttling and run slower than if it let the
> balance be controlled by the system?
It will indeed. Running at max frequency is not a sensible idea for
anything but a few applications (dare we say miners? ;). I thought
compositors might benefit from reduced latency by starting at max,
https://bugs.freedesktop.org/show_bug.cgi?id=102199
but realistically they care more about power consumption and gain most of
the latency reduction from priority sorting and preemption.
On the bright side, we give them a loaded gun with which they can shoot
both feet off. They have to be confident that they do know their
behaviour better than the hw (which for a few will be true). We give
them the means to do so, we do not say it is wise.
> Or will this be tied with the cgroup work to allow only clients allowed
> by sysadmin to do this?
That's what I think as well. I think we will end up with everything that
can be adjusted via CONTEXT_SETPARAM will be constrained by cgroup.
Once again, we can only look at the integration of schedfreq and CFS as
being the direction the GPUs will also eventually take.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-09 13:46 ` Chris Wilson
@ 2018-03-09 17:06 ` Tvrtko Ursulin
2018-03-09 17:24 ` Chris Wilson
0 siblings, 1 reply; 36+ messages in thread
From: Tvrtko Ursulin @ 2018-03-09 17:06 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: igt-dev, Praveen
On 09/03/2018 13:46, Chris Wilson wrote:
> Exercise some new API that allows applications to request that
> individual contexts are executed within a desired frequency range.
>
> v2: Split single/continuous set_freq subtests
> v3: Do an up/down ramp for individual freq request, check nothing
> changes after each invalid request
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Paneri, Praveen <praveen.paneri@intel.com>
> Cc: Kamble, Sagar A <sagar.a.kamble@intel.com>
> Cc: Antonio Argenziano <antonio.argenziano@intel.com>
> ---
> tests/Makefile.am | 1 +
> tests/Makefile.sources | 1 +
> tests/gem_ctx_freq.c | 648 +++++++++++++++++++++++++++++++++++++++++++++++++
> tests/meson.build | 1 +
> 4 files changed, 651 insertions(+)
> create mode 100644 tests/gem_ctx_freq.c
>
[snip]
> +static void check_invalid(int fd, uint32_t ctx, uint32_t min, uint32_t max)
> +{
> + const struct test {
> + uint32_t min, max;
> + } tests[] = {
> + { min - 50, max - 50 },
> + { min - 50, max },
> + { min - 50, max + 50 },
> + { min, max + 50 },
> + { min + 50, max + 50 },
> +
> + { min - 50, min - 50 },
> +
> + { min - 50, min },
> + { min + 50, min },
> + { min, min - 50 },
> +
> + { max + 50, max },
> + { max, max + 50 },
> + { max, max - 50 },
> +
> + { max + 50, max + 50 },
Is unprivileged "{ max, max }" allowed? In other words pin to max
frequency by anyone? If so, what happens when all userspace learns about
this and wants to use it just so to be lower latency than the other guy?
Or even on our integrated graphics, such userspace would unwisely take
away power budget from the CPU. Or could it even harm itself by
triggering too much thermal throttling and run slower than if it let the
balance be controlled by the system?
Or will this be tied with the cgroup work to allow only clients allowed
by sysadmin to do this?
Regards,
Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-08 17:13 [PATCH igt] " Chris Wilson
2018-03-09 0:45 ` Antonio Argenziano
@ 2018-03-09 13:46 ` Chris Wilson
2018-03-09 17:06 ` Tvrtko Ursulin
2018-03-09 21:35 ` Chris Wilson
` (2 subsequent siblings)
4 siblings, 1 reply; 36+ messages in thread
From: Chris Wilson @ 2018-03-09 13:46 UTC (permalink / raw)
To: intel-gfx; +Cc: Paneri, Kamble, igt-dev, Praveen
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
v2: Split single/continuous set_freq subtests
v3: Do an up/down ramp for individual freq request, check nothing
changes after each invalid request
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Paneri, Praveen <praveen.paneri@intel.com>
Cc: Kamble, Sagar A <sagar.a.kamble@intel.com>
Cc: Antonio Argenziano <antonio.argenziano@intel.com>
---
tests/Makefile.am | 1 +
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 648 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 651 insertions(+)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index dbc7be72..389f7fc7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4a81ac4a..3d079c42 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -58,6 +58,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_switch \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..f3cee838
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,648 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 7
+
+#define SAMPLE_PERIOD (USEC_PER_SEC / 10)
+
+static int __set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ return __gem_context_set_param(fd, ¶m);
+}
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ igt_assert_eq(__set_freq(fd, ctx, min, max), 0);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int period_us)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(period_us);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+#define N_STEPS 10
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ for (int step = 0; step <= 2*N_STEPS; step++) {
+ int frac = step > N_STEPS ? 2*N_STEPS - step : step;
+ uint32_t freq = min + (max - min) * frac / N_STEPS;
+ uint32_t cur, discard;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+
+#undef N_STEPS
+}
+
+static void continuous(int fd, const struct intel_execution_engine *e)
+{
+#define N_STEPS 10
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (int step = 0; step <= 2*N_STEPS; step++) {
+ int frac = step > N_STEPS ? 2*N_STEPS - step : step;
+ uint32_t freq = min + (max - min) * frac / N_STEPS;
+ uint32_t cur, discard;
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+#undef N_STEPS
+}
+
+static void inflight(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx, min, max, freq, discard;
+ double measured;
+ igt_spin_t *plug, *work[2];
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ gem_quiescent_gpu(fd);
+ plug = igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+ for (int n = 0; n < 16; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = plug->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = gem_context_create(fd),
+ };
+ set_freq(fd, eb.rsvd1, min, min);
+ gem_execbuf(fd, &eb);
+ gem_context_destroy(fd, eb.rsvd1);
+ }
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(plug): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, min);
+ igt_assert(measured > min - 100 && measured < min + 100);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[0] = __igt_spin_batch_new(fd, ctx, engine, 0);
+
+ /* work is now queued but not executing */
+ freq = (max + min) / 2;
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &freq, &discard);
+ gem_context_destroy(fd, ctx);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[1] = __igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+
+ igt_spin_batch_end(plug);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, plug->handle));
+ igt_spin_batch_free(fd, plug);
+
+ /* Now work will execute */
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work0): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+
+ igt_spin_batch_end(work[0]);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, work[0]->handle));
+ igt_spin_batch_free(fd, work[0]);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work1): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, max);
+ igt_assert(measured > max - 100 && measured < max + 100);
+
+ igt_spin_batch_free(fd, work[1]);
+ close(pmu);
+ gem_quiescent_gpu(fd);
+}
+
+static void sandwich(int fd)
+{
+ uint32_t ctx = gem_context_create(fd);
+ unsigned int engine;
+ uint32_t min, max;
+ igt_spin_t *spin;
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ spin = igt_spin_batch_new(fd, ctx, 0, 0);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+ for_each_physical_engine(fd, engine) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = ctx,
+ };
+ uint32_t cur, discard;
+ double measured;
+
+ min += 50;
+ if (min > max)
+ break;
+
+ set_freq(fd, ctx, min, min);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_execbuf(fd, &eb);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("Measured %.1fMHz, expected %dMhz\n", measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ gem_context_destroy(fd, ctx);
+ close(pmu);
+}
+
+static void pwm(int fd, unsigned int *engines, unsigned int nengine, int link)
+{
+ uint32_t ctx[nengine];
+
+ fcntl(link, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ for (unsigned int n = 0; n < nengine; n++)
+ ctx[n] = gem_context_create(fd);
+
+ do {
+ igt_spin_t *spin;
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+
+ while (read(link, &req, sizeof(req)) > 0) {
+ if ((req.engine | req.min | req.max) == 0)
+ goto out;
+
+ igt_assert(req.engine < nengine);
+ set_freq(fd, ctx[req.engine], req.min, req.max);
+ }
+
+ /* Create a 20% load using busy spinners */
+ spin = __igt_spin_batch_new(fd, ctx[0], engines[0], 0);
+ for (unsigned int n = 1; n < nengine; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engines[n],
+ .rsvd1 = ctx[n],
+ };
+ gem_execbuf(fd, &eb);
+ }
+ usleep(100);
+ igt_spin_batch_end(spin);
+
+ do
+ usleep(10);
+ while (gem_bo_busy(fd, spin->handle));
+ igt_spin_batch_free(fd, spin);
+ usleep(400);
+ } while (1);
+
+out:
+ for (unsigned int n = 0; n < nengine; n++)
+ gem_context_destroy(fd, ctx[n]);
+}
+
+static void smoketest(int fd, int timeout)
+{
+ unsigned int engines[16];
+ unsigned int nengine;
+ unsigned int engine;
+ uint32_t min[16], max[16];
+ int pmu, link[2];
+
+ get_freq(fd, 0, &min[0], &max[0]);
+
+ nengine = 0;
+ for_each_physical_engine(fd, engine) {
+ if (nengine == ARRAY_SIZE(engines) - 1)
+ break;
+
+ min[nengine] = min[0];
+ max[nengine] = max[0];
+ engines[nengine] = engine;
+ nengine++;
+ }
+ igt_require(nengine);
+
+ igt_assert(pipe(link) == 0);
+ igt_fork(child, 1)
+ pwm(fd, engines, nengine, link[0]);
+ close(link[0]);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ igt_until_timeout(timeout) {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+ double measured;
+ uint32_t ctx;
+
+ req.engine = rand() % nengine;
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &req.min, &req.max);
+ req.min = rand() % (req.max - req.min) + req.min;
+ req.max = rand() % (req.max - req.min) + req.min;
+ set_freq(fd, ctx, req.min, req.max);
+ get_freq(fd, ctx, &req.min, &req.max);
+
+ igt_debug("Replacing (%d, %d) on engine %x with (%d, %d)\n",
+ min[req.engine], max[req.engine], req.engine,
+ req.min, req.max);
+ igt_assert(write(link[1], &req, sizeof(req)) == sizeof(req));
+ gem_context_destroy(fd, ctx);
+
+ min[req.engine] = req.min;
+ max[req.engine] = req.max;
+
+ for (unsigned int n = 0; n < nengine; n++) {
+ igt_debug("[%d]: [%d, %d]\n", n, min[n], max[n]);
+ if (min[n] < req.min)
+ req.min = min[n];
+ if (max[n] > req.max)
+ req.max = max[n];
+ }
+ igt_assert(req.max >= req.min);
+
+ usleep(50000);
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+
+ if (measured <= req.min - 100 || measured >= req.max + 100)
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("Measured %.1fMHz, expected [%d, %d]Mhz\n",
+ measured, req.min, req.max);
+ igt_assert(measured > req.min - 100 &&
+ measured < req.max + 100);
+ }
+
+ do {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req = {};
+
+ write(link[1], &req, sizeof(req));
+ close(link[1]);
+ } while (0);
+ igt_waitchildren();
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+}
+
+static void check_invalid(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ const struct test {
+ uint32_t min, max;
+ } tests[] = {
+ { min - 50, max - 50 },
+ { min - 50, max },
+ { min - 50, max + 50 },
+ { min, max + 50 },
+ { min + 50, max + 50 },
+
+ { min - 50, min - 50 },
+
+ { min - 50, min },
+ { min + 50, min },
+ { min, min - 50 },
+
+ { max + 50, max },
+ { max, max + 50 },
+ { max, max - 50 },
+
+ { max + 50, max + 50 },
+
+ {}
+ };
+
+ for (const struct test *t = tests; t->min | t->max; t++) {
+ uint32_t cur_min, cur_max;
+
+ igt_assert_f(__set_freq(fd, ctx, t->min, t->max) == -EINVAL,
+ "Failed to reject invalid [%d, %d] (valid range [%d, %d]) on context %d\n",
+ t->min, t->max, min, max, ctx);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ }
+}
+
+static void invalid_param(int fd)
+{
+ uint32_t min, max, ctx;
+
+ get_freq(fd, 0, &min, &max);
+
+ check_invalid(fd, 0, min, max);
+
+ ctx = gem_context_create(fd);
+ check_invalid(fd, ctx, min, max);
+ gem_context_destroy(fd, ctx);
+}
+
+static void idempotent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ set_freq(fd, 0, min, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void independent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+ uint32_t ctx[2];
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ ctx[0] = gem_context_create(fd);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ ctx[1] = gem_context_create(fd);
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx[1], max, max);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[1]);
+
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[0]);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+ }
+
+ igt_subtest("invalid")
+ invalid_param(fd);
+
+ igt_subtest("idempotent")
+ idempotent(fd);
+
+ igt_subtest("independent")
+ independent(fd);
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ if (e->exec_id == 0)
+ continue;
+
+ igt_subtest_group {
+ igt_fixture {
+ igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
+ }
+
+ igt_subtest_f("%s-single", e->name)
+ single(fd, e);
+ igt_subtest_f("%s-continuous", e->name)
+ continuous(fd, e);
+ igt_subtest_f("%s-inflight", e->name)
+ inflight(fd, e);
+ }
+ }
+
+ igt_subtest("sandwich")
+ sandwich(fd);
+
+ igt_subtest("smoketest")
+ smoketest(fd, 20);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 6e776bb7..fa5e3169 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -36,6 +36,7 @@ test_progs = [
'gem_ctx_create',
'gem_ctx_exec',
'gem_ctx_isolation',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-09 0:45 ` Antonio Argenziano
@ 2018-03-09 1:03 ` Chris Wilson
2018-03-09 19:15 ` Antonio Argenziano
0 siblings, 1 reply; 36+ messages in thread
From: Chris Wilson @ 2018-03-09 1:03 UTC (permalink / raw)
To: Antonio Argenziano, intel-gfx; +Cc: igt-dev, Praveen
Quoting Antonio Argenziano (2018-03-09 00:45:42)
>
>
> On 08/03/18 09:13, Chris Wilson wrote:
> > Exercise some new API that allows applications to request that
> > individual contexts are executed within a desired frequency range.
> >
> > v2: Split single/continuous set_freq subtests
> >
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > Cc: Paneri, Praveen <praveen.paneri@intel.com>
> > Cc: Kamble, Sagar A <sagar.a.kamble@intel.com>
> > Cc: Antonio Argenziano <antonio.argenziano@intel.com>
> > ---
> > tests/Makefile.am | 1 +
> > tests/Makefile.sources | 1 +
> > tests/gem_ctx_freq.c | 604 +++++++++++++++++++++++++++++++++++++++++++++++++
> > tests/meson.build | 1 +
> > 4 files changed, 607 insertions(+)
> > create mode 100644 tests/gem_ctx_freq.c
> >
>
> > +static void single(int fd, const struct intel_execution_engine *e)
> > +{
> > + const unsigned int engine = e->exec_id | e->flags;
> > + uint32_t ctx = gem_context_create(fd);
> > + uint32_t min, max;
> > + double measured;
> > + igt_spin_t *spin;
> > + int pmu;
> > +
> > + get_freq(fd, ctx, &min, &max);
> > + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
> > +
> > + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> > + igt_require(pmu >= 0);
> > +
> > + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
>
> Although it is done in the smoke test, it would be interesting if freq's
> values were a bit randomized.
It was intentionally increment only originally because the
implementation was fast to upclock and slow to downclock. Given the
challenge of the smoketest, I've shelved that laziness until it can pass
that not particularly challenging test.
I did have in mind doing an up/down ramp. We should also check that
changing min while keeping max fixed should not affect a 100% load like
the spinners.
> > + uint32_t cur, discard;
> > +
> > + set_freq(fd, ctx, freq, freq);
> > + get_freq(fd, ctx, &cur, &discard);
>
> igt_assert_eq(freq, cur)?
Not quite. The trick is that the interface is not strictly idempotent,
since we pass in MHz, the driver converts that into freq bins and spits
it back out to the nearest MHz. So cur is not strictly freq, it just
happens that 50MHz is the bin size on gen9.
The idea here is that we grab the adjusted freq from the driver to
validate with.
> > +
> > + gem_quiescent_gpu(fd);
> > + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> > + usleep(10000);
>
> I guess here we wait for the frequency changes to take effect, maybe a
> small comment would help.
And for the batch to be submitted. Asynchronous interfaces make it hard
to pinpoint when things occur. We keep muttering about extending
igt_spin_t to have an option for wait-for-exec (basically have it write
out a dword that we can spin on)
usleep(10000); /* wait for execution + freq change */
> > +static void sandwich(int fd)
> > +{
> > + uint32_t ctx = gem_context_create(fd);
> > + unsigned int engine;
> > + uint32_t min, max;
> > + igt_spin_t *spin;
> > + int pmu;
> > +
> > + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> > + igt_require(pmu >= 0);
> > +
> > + spin = igt_spin_batch_new(fd, ctx, 0, 0);
> > + get_freq(fd, ctx, &min, &max);
> > + set_freq(fd, ctx, min, min);
> > + for_each_physical_engine(fd, engine) {
> > + struct drm_i915_gem_exec_object2 obj = {
> > + .handle = spin->handle,
> > + };
> > + struct drm_i915_gem_execbuffer2 eb = {
> > + .buffer_count = 1,
> > + .buffers_ptr = to_user_pointer(&obj),
> > + .flags = engine,
> > + .rsvd1 = ctx,
> > + };
> > + uint32_t cur, discard;
> > + double measured;
> > +
> > + min += 50;
> > + if (min > max)
> > + break;
> > +
> > + set_freq(fd, ctx, min, min);
> > + get_freq(fd, ctx, &cur, &discard);
> > +
> > + gem_execbuf(fd, &eb);
> > + usleep(10000);
> > +
> > + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> > + igt_debugfs_dump(fd, "i915_rps_boost_info");
> > +
> > + igt_info("Measured %.1fMHz, expected %dMhz\n", measured, cur);
> > + igt_assert(measured > cur - 100 && measured < cur + 100);
>
> Does the frequency change after each execbuf?
Yes. This turned into just an exercise across engines, bumping the
desired freq. I wanted to try and validate the min/max bounds, but ran
into the challenge that the gpu is only running at the highest frequency
it can get because of the busy spinner :)
> > +static void smoketest(int fd, int timeout)
> > +{
> > + unsigned int engines[16];
>
> use a macro instead of magic number 16.
#define THIS_IS_FAR_MORE_MAGIC_THAN_A_MEANINGLESS_BARE_NUMBER_THAT_YOU_SHOULD_NOT_BE_READING_ANYTHING_INTO 16
/rant
> > +static void invalid_param(int fd)
> > +{
>
> gem_ctx_param is going to be upset again pretty soon ;).
Poor thing.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
2018-03-08 17:13 [PATCH igt] " Chris Wilson
@ 2018-03-09 0:45 ` Antonio Argenziano
2018-03-09 1:03 ` Chris Wilson
2018-03-09 13:46 ` Chris Wilson
` (3 subsequent siblings)
4 siblings, 1 reply; 36+ messages in thread
From: Antonio Argenziano @ 2018-03-09 0:45 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: igt-dev, Praveen
On 08/03/18 09:13, Chris Wilson wrote:
> Exercise some new API that allows applications to request that
> individual contexts are executed within a desired frequency range.
>
> v2: Split single/continuous set_freq subtests
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Paneri, Praveen <praveen.paneri@intel.com>
> Cc: Kamble, Sagar A <sagar.a.kamble@intel.com>
> Cc: Antonio Argenziano <antonio.argenziano@intel.com>
> ---
> tests/Makefile.am | 1 +
> tests/Makefile.sources | 1 +
> tests/gem_ctx_freq.c | 604 +++++++++++++++++++++++++++++++++++++++++++++++++
> tests/meson.build | 1 +
> 4 files changed, 607 insertions(+)
> create mode 100644 tests/gem_ctx_freq.c
>
> +static void single(int fd, const struct intel_execution_engine *e)
> +{
> + const unsigned int engine = e->exec_id | e->flags;
> + uint32_t ctx = gem_context_create(fd);
> + uint32_t min, max;
> + double measured;
> + igt_spin_t *spin;
> + int pmu;
> +
> + get_freq(fd, ctx, &min, &max);
> + igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
> +
> + for (uint32_t freq = min + 50; freq <= max; freq += 100) {
Although it is done in the smoke test, it would be interesting if freq's
values were a bit randomized.
> + uint32_t cur, discard;
> +
> + set_freq(fd, ctx, freq, freq);
> + get_freq(fd, ctx, &cur, &discard);
igt_assert_eq(freq, cur)?
> +
> + gem_quiescent_gpu(fd);
> + spin = __igt_spin_batch_new(fd, ctx, engine, 0);
> + usleep(10000);
I guess here we wait for the frequency changes to take effect, maybe a
small comment would help.
> +
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> +
> + igt_spin_batch_free(fd, spin);
> + igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
> + e->name, measured, cur);
> + igt_assert(measured > cur - 100 && measured < cur + 100);
> + }
> + gem_quiescent_gpu(fd);
> +
> + close(pmu);
> + gem_context_destroy(fd, ctx);
> +}
> +
> +
> +static void sandwich(int fd)
> +{
> + uint32_t ctx = gem_context_create(fd);
> + unsigned int engine;
> + uint32_t min, max;
> + igt_spin_t *spin;
> + int pmu;
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
> +
> + spin = igt_spin_batch_new(fd, ctx, 0, 0);
> + get_freq(fd, ctx, &min, &max);
> + set_freq(fd, ctx, min, min);
> + for_each_physical_engine(fd, engine) {
> + struct drm_i915_gem_exec_object2 obj = {
> + .handle = spin->handle,
> + };
> + struct drm_i915_gem_execbuffer2 eb = {
> + .buffer_count = 1,
> + .buffers_ptr = to_user_pointer(&obj),
> + .flags = engine,
> + .rsvd1 = ctx,
> + };
> + uint32_t cur, discard;
> + double measured;
> +
> + min += 50;
> + if (min > max)
> + break;
> +
> + set_freq(fd, ctx, min, min);
> + get_freq(fd, ctx, &cur, &discard);
> +
> + gem_execbuf(fd, &eb);
> + usleep(10000);
> +
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> +
> + igt_info("Measured %.1fMHz, expected %dMhz\n", measured, cur);
> + igt_assert(measured > cur - 100 && measured < cur + 100);
Does the frequency change after each execbuf?
> + }
> + igt_spin_batch_free(fd, spin);
> + gem_quiescent_gpu(fd);
> +
> + gem_context_destroy(fd, ctx);
> + close(pmu);
> +}
> +
> +static void pwm(int fd, unsigned int *engines, unsigned int nengine, int link)
> +{
> + uint32_t ctx[nengine];
> +
> + fcntl(link, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
> +
> + for (unsigned int n = 0; n < nengine; n++)
> + ctx[n] = gem_context_create(fd);
> +
> + do {
> + igt_spin_t *spin;
> + struct {
> + uint32_t engine;
> + uint32_t min;
> + uint32_t max;
> + } req;
> +
> + while (read(link, &req, sizeof(req)) > 0) {
> + if ((req.engine | req.min | req.max) == 0)
> + goto out;
> +
> + igt_assert(req.engine < nengine);
> + set_freq(fd, ctx[req.engine], req.min, req.max);
> + }
> +
> + /* Create a 20% load using busy spinners */
> + spin = __igt_spin_batch_new(fd, ctx[0], engines[0], 0);
> + for (unsigned int n = 1; n < nengine; n++) {
> + struct drm_i915_gem_exec_object2 obj = {
> + .handle = spin->handle,
> + };
> + struct drm_i915_gem_execbuffer2 eb = {
> + .buffer_count = 1,
> + .buffers_ptr = to_user_pointer(&obj),
> + .flags = engines[n],
> + .rsvd1 = ctx[n],
> + };
> + gem_execbuf(fd, &eb);
> + }
> + usleep(100);
> + igt_spin_batch_end(spin);
> +
> + do
> + usleep(10);
> + while (gem_bo_busy(fd, spin->handle));
> + igt_spin_batch_free(fd, spin);
> + usleep(400);
> + } while (1);
> +
> +out:
> + for (unsigned int n = 0; n < nengine; n++)
> + gem_context_destroy(fd, ctx[n]);
> +}
> +
> +static void smoketest(int fd, int timeout)
> +{
> + unsigned int engines[16];
use a macro instead of magic number 16.
> + unsigned int nengine;
> + unsigned int engine;
> + uint32_t min[16], max[16];
> + int pmu, link[2];
> +
> + get_freq(fd, 0, &min[0], &max[0]);
> +
> + nengine = 0;
> + for_each_physical_engine(fd, engine) {
> + if (nengine == ARRAY_SIZE(engines) - 1)
> + break;
> +
> + min[nengine] = min[0];
> + max[nengine] = max[0];
> + engines[nengine] = engine;
> + nengine++;
> + }
> + igt_require(nengine);
> +
> + igt_assert(pipe(link) == 0);
> + igt_fork(child, 1)
> + pwm(fd, engines, nengine, link[0]);
> + close(link[0]);
> +
> + pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
> + igt_require(pmu >= 0);
> +
> + igt_until_timeout(timeout) {
> + struct {
> + uint32_t engine;
> + uint32_t min;
> + uint32_t max;
> + } req;
> + double measured;
> + uint32_t ctx;
> +
> + req.engine = rand() % nengine;
> +
> + ctx = gem_context_create(fd);
> + get_freq(fd, ctx, &req.min, &req.max);
> + req.min = rand() % (req.max - req.min) + req.min;
> + req.max = rand() % (req.max - req.min) + req.min;
> + set_freq(fd, ctx, req.min, req.max);
> + get_freq(fd, ctx, &req.min, &req.max);
> +
> + igt_debug("Replacing (%d, %d) on engine %x with (%d, %d)\n",
> + min[req.engine], max[req.engine], req.engine,
> + req.min, req.max);
> + igt_assert(write(link[1], &req, sizeof(req)) == sizeof(req));
> + gem_context_destroy(fd, ctx);
> +
> + min[req.engine] = req.min;
> + max[req.engine] = req.max;
> +
> + for (unsigned int n = 0; n < nengine; n++) {
> + igt_debug("[%d]: [%d, %d]\n", n, min[n], max[n]);
> + if (min[n] < req.min)
> + req.min = min[n];
> + if (max[n] > req.max)
> + req.max = max[n];
> + }
> + igt_assert(req.max >= req.min);
> +
> + usleep(50000);
> + measured = measure_frequency(pmu, SAMPLE_PERIOD);
> +
> + if (measured <= req.min - 100 || measured >= req.max + 100)
> + igt_debugfs_dump(fd, "i915_rps_boost_info");
> + igt_info("Measured %.1fMHz, expected [%d, %d]Mhz\n",
> + measured, req.min, req.max);
> + igt_assert(measured > req.min - 100 &&
> + measured < req.max + 100);
> + }
> +
> + do {
> + struct {
> + uint32_t engine;
> + uint32_t min;
> + uint32_t max;
> + } req = {};
> +
> + write(link[1], &req, sizeof(req));
> + close(link[1]);
> + } while (0);
> + igt_waitchildren();
> + gem_quiescent_gpu(fd);
> +
> + close(pmu);
> +}
> +
> +static void invalid_param(int fd)
> +{
gem_ctx_param is going to be upset again pretty soon ;).
> + uint32_t min, max;
> + uint32_t cur_min, cur_max;
> +
> + get_freq(fd, 0, &min, &max);
> +
> + igt_assert_eq(__set_freq(fd, 0, min - 50, max), -EINVAL);
> + igt_assert_eq(__set_freq(fd, 0, min, max + 50), -EINVAL);
One more case is both are out of boundary.
igt_assert_eq(__set_freq(fd, 0, min - 50, max + 50), -EINVAL);
> + igt_assert_eq(__set_freq(fd, 0, min + 50, min), -EINVAL);
> + igt_assert_eq(__set_freq(fd, 0, max, max - 50), -EINVAL);
> +
> + get_freq(fd, 0, &cur_min, &cur_max);
> + igt_assert_eq(cur_min, min);
> + igt_assert_eq(cur_max, max);
Check frequency didn't change after each ioctl.
Thanks,
Antonio
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx
@ 2018-03-08 17:13 Chris Wilson
2018-03-09 0:45 ` Antonio Argenziano
` (4 more replies)
0 siblings, 5 replies; 36+ messages in thread
From: Chris Wilson @ 2018-03-08 17:13 UTC (permalink / raw)
To: intel-gfx; +Cc: Paneri, Kamble, igt-dev, Praveen
Exercise some new API that allows applications to request that
individual contexts are executed within a desired frequency range.
v2: Split single/continuous set_freq subtests
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Paneri, Praveen <praveen.paneri@intel.com>
Cc: Kamble, Sagar A <sagar.a.kamble@intel.com>
Cc: Antonio Argenziano <antonio.argenziano@intel.com>
---
tests/Makefile.am | 1 +
tests/Makefile.sources | 1 +
tests/gem_ctx_freq.c | 604 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
4 files changed, 607 insertions(+)
create mode 100644 tests/gem_ctx_freq.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index dbc7be72..389f7fc7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -104,6 +104,7 @@ drm_import_export_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
drm_import_export_LDADD = $(LDADD) -lpthread
gem_close_race_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_close_race_LDADD = $(LDADD) -lpthread
+gem_ctx_freq_LDADD = $(LDADD) $(top_builddir)/lib/libigt_perf.la
gem_ctx_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
gem_ctx_thrash_LDADD = $(LDADD) -lpthread
gem_exec_parallel_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4a81ac4a..3d079c42 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -58,6 +58,7 @@ TESTS_progs = \
gem_ctx_bad_exec \
gem_ctx_create \
gem_ctx_exec \
+ gem_ctx_freq \
gem_ctx_isolation \
gem_ctx_param \
gem_ctx_switch \
diff --git a/tests/gem_ctx_freq.c b/tests/gem_ctx_freq.c
new file mode 100644
index 00000000..f7e79ac3
--- /dev/null
+++ b/tests/gem_ctx_freq.c
@@ -0,0 +1,604 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "igt.h"
+#include "igt_perf.h"
+
+#define LOCAL_CONTEXT_PARAM_FREQUENCY 8
+
+#define SAMPLE_PERIOD (USEC_PER_SEC / 10)
+
+static int __set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ .value = (uint64_t)max << 32 | min,
+ };
+
+ return __gem_context_set_param(fd, ¶m);
+}
+
+static void set_freq(int fd, uint32_t ctx, uint32_t min, uint32_t max)
+{
+ igt_assert_eq(__set_freq(fd, ctx, min, max), 0);
+}
+
+static void get_freq(int fd, uint32_t ctx, uint32_t *min, uint32_t *max)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = ctx,
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ gem_context_get_param(fd, ¶m);
+
+ *min = param.value & 0xffffffff;
+ *max = param.value >> 32;
+}
+
+static double measure_frequency(int pmu, int period_us)
+{
+ uint64_t data[2];
+ uint64_t d_t, d_v;
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v = -data[0];
+ d_t = -data[1];
+
+ usleep(period_us);
+
+ igt_assert_eq(read(pmu, data, sizeof(data)), sizeof(data));
+ d_v += data[0];
+ d_t += data[1];
+
+ return d_v * 1e9 / d_t;
+}
+
+static void single(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ uint32_t cur, discard;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_spin_batch_free(fd, spin);
+ igt_info("%s(single): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+}
+
+static void continuous(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx = gem_context_create(fd);
+ uint32_t min, max;
+ double measured;
+ igt_spin_t *spin;
+ int pmu;
+
+ get_freq(fd, ctx, &min, &max);
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ gem_quiescent_gpu(fd);
+ spin = __igt_spin_batch_new(fd, ctx, engine, 0);
+ for (uint32_t freq = min + 50; freq <= max; freq += 100) {
+ uint32_t cur, discard;
+ igt_spin_t *kick;
+
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &cur, &discard);
+
+ /*
+ * When requesting a new frequency on the currently
+ * executing context, it does not take effect until the
+ * next context switch. In this case, we trigger a lite
+ * restore.
+ */
+ kick = __igt_spin_batch_new(fd, ctx, engine, 0);
+ igt_spin_batch_free(fd, spin);
+ spin = kick;
+
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("%s(continuous): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+ gem_context_destroy(fd, ctx);
+}
+
+static void inflight(int fd, const struct intel_execution_engine *e)
+{
+ const unsigned int engine = e->exec_id | e->flags;
+ uint32_t ctx, min, max, freq, discard;
+ double measured;
+ igt_spin_t *plug, *work[2];
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+
+ igt_info("Min freq: %dMHz; Max freq: %dMHz\n", min, max);
+
+ gem_quiescent_gpu(fd);
+ plug = igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+ for (int n = 0; n < 16; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = plug->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = gem_context_create(fd),
+ };
+ set_freq(fd, eb.rsvd1, min, min);
+ gem_execbuf(fd, &eb);
+ gem_context_destroy(fd, eb.rsvd1);
+ }
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(plug): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, min);
+ igt_assert(measured > min - 100 && measured < min + 100);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[0] = __igt_spin_batch_new(fd, ctx, engine, 0);
+
+ /* work is now queued but not executing */
+ freq = (max + min) / 2;
+ set_freq(fd, ctx, freq, freq);
+ get_freq(fd, ctx, &freq, &discard);
+ gem_context_destroy(fd, ctx);
+
+ ctx = gem_context_create(fd);
+ set_freq(fd, ctx, max, max);
+ work[1] = __igt_spin_batch_new(fd, ctx, engine, 0);
+ gem_context_destroy(fd, ctx);
+
+ igt_spin_batch_end(plug);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, plug->handle));
+ igt_spin_batch_free(fd, plug);
+
+ /* Now work will execute */
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work0): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, freq);
+ igt_assert(measured > freq - 100 && measured < freq + 100);
+
+ igt_spin_batch_end(work[0]);
+ do
+ usleep(10000);
+ while (gem_bo_busy(fd, work[0]->handle));
+ igt_spin_batch_free(fd, work[0]);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_engine_info");
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("%s(work1): Measured %.1fMHz, expected %dMhz\n",
+ e->name, measured, max);
+ igt_assert(measured > max - 100 && measured < max + 100);
+
+ igt_spin_batch_free(fd, work[1]);
+ close(pmu);
+ gem_quiescent_gpu(fd);
+}
+
+static void sandwich(int fd)
+{
+ uint32_t ctx = gem_context_create(fd);
+ unsigned int engine;
+ uint32_t min, max;
+ igt_spin_t *spin;
+ int pmu;
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ spin = igt_spin_batch_new(fd, ctx, 0, 0);
+ get_freq(fd, ctx, &min, &max);
+ set_freq(fd, ctx, min, min);
+ for_each_physical_engine(fd, engine) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engine,
+ .rsvd1 = ctx,
+ };
+ uint32_t cur, discard;
+ double measured;
+
+ min += 50;
+ if (min > max)
+ break;
+
+ set_freq(fd, ctx, min, min);
+ get_freq(fd, ctx, &cur, &discard);
+
+ gem_execbuf(fd, &eb);
+ usleep(10000);
+
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+
+ igt_info("Measured %.1fMHz, expected %dMhz\n", measured, cur);
+ igt_assert(measured > cur - 100 && measured < cur + 100);
+ }
+ igt_spin_batch_free(fd, spin);
+ gem_quiescent_gpu(fd);
+
+ gem_context_destroy(fd, ctx);
+ close(pmu);
+}
+
+static void pwm(int fd, unsigned int *engines, unsigned int nengine, int link)
+{
+ uint32_t ctx[nengine];
+
+ fcntl(link, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ for (unsigned int n = 0; n < nengine; n++)
+ ctx[n] = gem_context_create(fd);
+
+ do {
+ igt_spin_t *spin;
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+
+ while (read(link, &req, sizeof(req)) > 0) {
+ if ((req.engine | req.min | req.max) == 0)
+ goto out;
+
+ igt_assert(req.engine < nengine);
+ set_freq(fd, ctx[req.engine], req.min, req.max);
+ }
+
+ /* Create a 20% load using busy spinners */
+ spin = __igt_spin_batch_new(fd, ctx[0], engines[0], 0);
+ for (unsigned int n = 1; n < nengine; n++) {
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = spin->handle,
+ };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1,
+ .buffers_ptr = to_user_pointer(&obj),
+ .flags = engines[n],
+ .rsvd1 = ctx[n],
+ };
+ gem_execbuf(fd, &eb);
+ }
+ usleep(100);
+ igt_spin_batch_end(spin);
+
+ do
+ usleep(10);
+ while (gem_bo_busy(fd, spin->handle));
+ igt_spin_batch_free(fd, spin);
+ usleep(400);
+ } while (1);
+
+out:
+ for (unsigned int n = 0; n < nengine; n++)
+ gem_context_destroy(fd, ctx[n]);
+}
+
+static void smoketest(int fd, int timeout)
+{
+ unsigned int engines[16];
+ unsigned int nengine;
+ unsigned int engine;
+ uint32_t min[16], max[16];
+ int pmu, link[2];
+
+ get_freq(fd, 0, &min[0], &max[0]);
+
+ nengine = 0;
+ for_each_physical_engine(fd, engine) {
+ if (nengine == ARRAY_SIZE(engines) - 1)
+ break;
+
+ min[nengine] = min[0];
+ max[nengine] = max[0];
+ engines[nengine] = engine;
+ nengine++;
+ }
+ igt_require(nengine);
+
+ igt_assert(pipe(link) == 0);
+ igt_fork(child, 1)
+ pwm(fd, engines, nengine, link[0]);
+ close(link[0]);
+
+ pmu = perf_i915_open(I915_PMU_REQUESTED_FREQUENCY);
+ igt_require(pmu >= 0);
+
+ igt_until_timeout(timeout) {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req;
+ double measured;
+ uint32_t ctx;
+
+ req.engine = rand() % nengine;
+
+ ctx = gem_context_create(fd);
+ get_freq(fd, ctx, &req.min, &req.max);
+ req.min = rand() % (req.max - req.min) + req.min;
+ req.max = rand() % (req.max - req.min) + req.min;
+ set_freq(fd, ctx, req.min, req.max);
+ get_freq(fd, ctx, &req.min, &req.max);
+
+ igt_debug("Replacing (%d, %d) on engine %x with (%d, %d)\n",
+ min[req.engine], max[req.engine], req.engine,
+ req.min, req.max);
+ igt_assert(write(link[1], &req, sizeof(req)) == sizeof(req));
+ gem_context_destroy(fd, ctx);
+
+ min[req.engine] = req.min;
+ max[req.engine] = req.max;
+
+ for (unsigned int n = 0; n < nengine; n++) {
+ igt_debug("[%d]: [%d, %d]\n", n, min[n], max[n]);
+ if (min[n] < req.min)
+ req.min = min[n];
+ if (max[n] > req.max)
+ req.max = max[n];
+ }
+ igt_assert(req.max >= req.min);
+
+ usleep(50000);
+ measured = measure_frequency(pmu, SAMPLE_PERIOD);
+
+ if (measured <= req.min - 100 || measured >= req.max + 100)
+ igt_debugfs_dump(fd, "i915_rps_boost_info");
+ igt_info("Measured %.1fMHz, expected [%d, %d]Mhz\n",
+ measured, req.min, req.max);
+ igt_assert(measured > req.min - 100 &&
+ measured < req.max + 100);
+ }
+
+ do {
+ struct {
+ uint32_t engine;
+ uint32_t min;
+ uint32_t max;
+ } req = {};
+
+ write(link[1], &req, sizeof(req));
+ close(link[1]);
+ } while (0);
+ igt_waitchildren();
+ gem_quiescent_gpu(fd);
+
+ close(pmu);
+}
+
+static void invalid_param(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ igt_assert_eq(__set_freq(fd, 0, min - 50, max), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, min, max + 50), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, min + 50, min), -EINVAL);
+ igt_assert_eq(__set_freq(fd, 0, max, max - 50), -EINVAL);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void idempotent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ set_freq(fd, 0, min, max);
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+}
+
+static void independent(int fd)
+{
+ uint32_t min, max;
+ uint32_t cur_min, cur_max;
+ uint32_t ctx[2];
+
+ get_freq(fd, 0, &min, &max);
+
+ set_freq(fd, 0, max, max);
+ ctx[0] = gem_context_create(fd);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, 0, min, min);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ ctx[1] = gem_context_create(fd);
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ set_freq(fd, ctx[1], max, max);
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+
+ get_freq(fd, 0, &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, min);
+
+ get_freq(fd, ctx[1], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, max);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[1]);
+
+ get_freq(fd, ctx[0], &cur_min, &cur_max);
+ igt_assert_eq(cur_min, min);
+ igt_assert_eq(cur_max, max);
+ gem_context_destroy(fd, ctx[0]);
+}
+
+static bool has_ctx_freq(int fd)
+{
+ struct drm_i915_gem_context_param param = {
+ .param = LOCAL_CONTEXT_PARAM_FREQUENCY,
+ };
+
+ return __gem_context_get_param(fd, ¶m) == 0;
+}
+
+igt_main
+{
+ const struct intel_execution_engine *e;
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require_gem(fd);
+
+ igt_require(has_ctx_freq(fd));
+ }
+
+ igt_subtest("invalid")
+ invalid_param(fd);
+
+ igt_subtest("idempotent")
+ idempotent(fd);
+
+ igt_subtest("independent")
+ independent(fd);
+
+ igt_skip_on_simulation();
+
+ for (e = intel_execution_engines; e->name; e++) {
+ if (e->exec_id == 0)
+ continue;
+
+ igt_subtest_group {
+ igt_fixture {
+ igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
+ }
+
+ igt_subtest_f("%s-single", e->name)
+ single(fd, e);
+ igt_subtest_f("%s-continuous", e->name)
+ continuous(fd, e);
+ igt_subtest_f("%s-inflight", e->name)
+ inflight(fd, e);
+ }
+ }
+
+ igt_subtest("sandwich")
+ sandwich(fd);
+
+ igt_subtest("smoketest")
+ smoketest(fd, 20);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 58729231..f1271274 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -35,6 +35,7 @@ test_progs = [
'gem_ctx_bad_exec',
'gem_ctx_create',
'gem_ctx_exec',
+ 'gem_ctx_freq',
'gem_ctx_param',
'gem_ctx_switch',
'gem_ctx_thrash',
--
2.16.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 36+ messages in thread
end of thread, other threads:[~2018-03-14 9:49 UTC | newest]
Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-07 22:49 [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx Chris Wilson
2018-03-07 22:49 ` [igt-dev] " Chris Wilson
2018-03-07 23:00 ` [igt-dev] ✗ Fi.CI.BAT: failure for " Patchwork
2018-03-08 0:13 ` [PATCH igt] " Chris Wilson
2018-03-08 0:13 ` [igt-dev] " Chris Wilson
2018-03-08 0:42 ` [igt-dev] ✓ Fi.CI.BAT: success for igt: Add gem_ctx_freq to exercise requesting freq on a ctx (rev2) Patchwork
2018-03-08 0:55 ` [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx Antonio Argenziano
2018-03-08 0:55 ` [Intel-gfx] " Antonio Argenziano
2018-03-08 1:18 ` Chris Wilson
2018-03-08 1:18 ` [igt-dev] [Intel-gfx] " Chris Wilson
2018-03-08 17:33 ` Antonio Argenziano
2018-03-08 17:33 ` [igt-dev] [Intel-gfx] " Antonio Argenziano
2018-03-08 17:39 ` Chris Wilson
2018-03-08 17:39 ` [igt-dev] [Intel-gfx] " Chris Wilson
2018-03-08 1:49 ` [igt-dev] ✗ Fi.CI.IGT: failure for igt: Add gem_ctx_freq to exercise requesting freq on a ctx (rev2) Patchwork
2018-03-08 1:59 ` [PATCH igt] igt: Add gem_ctx_freq to exercise requesting freq on a ctx Chris Wilson
2018-03-08 2:26 ` ✓ Fi.CI.BAT: success for " Patchwork
2018-03-08 3:12 ` ✓ Fi.CI.IGT: " Patchwork
2018-03-08 9:02 ` [PATCH igt v2] " Chris Wilson
2018-03-08 17:13 [PATCH igt] " Chris Wilson
2018-03-09 0:45 ` Antonio Argenziano
2018-03-09 1:03 ` Chris Wilson
2018-03-09 19:15 ` Antonio Argenziano
2018-03-09 20:37 ` Chris Wilson
2018-03-09 13:46 ` Chris Wilson
2018-03-09 17:06 ` Tvrtko Ursulin
2018-03-09 17:24 ` Chris Wilson
2018-03-09 21:35 ` Chris Wilson
2018-03-12 21:13 ` Antonio Argenziano
2018-03-13 12:38 ` Sagar Arun Kamble
2018-03-13 12:50 ` Chris Wilson
2018-03-13 13:26 ` Chris Wilson
2018-03-13 13:58 ` Chris Wilson
2018-03-14 8:15 ` Sagar Arun Kamble
2018-03-14 9:03 ` Chris Wilson
2018-03-14 9:49 ` Sagar Arun Kamble
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.