1 /*
2 * Copyright © 2017 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
25 #include "igt.h"
26
27 #define MAX_ERROR 5 /* % */
28
29 #define assert_within_epsilon(x, ref, tolerance) \
30 igt_assert_f(100 * x <= (100 + tolerance) * ref && \
31 100 * x >= (100 - tolerance) * ref, \
32 "'%s' != '%s' (%lld not within %d%% tolerance of %lld)\n",\
33 #x, #ref, (long long)x, tolerance, (long long)ref)
34
spin(int fd,const struct intel_execution_engine2 * e2,unsigned int timeout_sec)35 static void spin(int fd, const struct intel_execution_engine2 *e2,
36 unsigned int timeout_sec)
37 {
38 const uint64_t timeout_100ms = 100000000LL;
39 unsigned long loops = 0;
40 igt_spin_t *spin;
41 struct timespec tv = { };
42 struct timespec itv = { };
43 uint64_t elapsed;
44
45 spin = __igt_spin_new(fd, .engine = e2->flags);
46 while ((elapsed = igt_nsec_elapsed(&tv)) >> 30 < timeout_sec) {
47 igt_spin_t *next = __igt_spin_new(fd, .engine = e2->flags);
48
49 igt_spin_set_timeout(spin,
50 timeout_100ms - igt_nsec_elapsed(&itv));
51 gem_sync(fd, spin->handle);
52 igt_debug("loop %lu: interval=%fms (target 100ms), elapsed %fms\n",
53 loops,
54 igt_nsec_elapsed(&itv) * 1e-6,
55 igt_nsec_elapsed(&tv) * 1e-6);
56 memset(&itv, 0, sizeof(itv));
57
58 igt_spin_free(fd, spin);
59 spin = next;
60 loops++;
61 }
62 igt_spin_free(fd, spin);
63
64 igt_info("Completed %ld loops in %lld ns, target %ld\n",
65 loops, (long long)elapsed, (long)(elapsed / timeout_100ms));
66
67 assert_within_epsilon(timeout_100ms * loops, elapsed, MAX_ERROR);
68 }
69
70 #define RESUBMIT_NEW_CTX (1 << 0)
71 #define RESUBMIT_ALL_ENGINES (1 << 1)
72
spin_resubmit(int fd,const struct intel_execution_engine2 * e2,unsigned int flags)73 static void spin_resubmit(int fd, const struct intel_execution_engine2 *e2,
74 unsigned int flags)
75 {
76 const uint32_t ctx0 = gem_context_create(fd);
77 const uint32_t ctx1 = (flags & RESUBMIT_NEW_CTX) ?
78 gem_context_create(fd) : ctx0;
79 igt_spin_t *spin = __igt_spin_new(fd, .ctx = ctx0, .engine = e2->flags);
80 const struct intel_execution_engine2 *other;
81
82 struct drm_i915_gem_execbuffer2 eb = {
83 .buffer_count = 1,
84 .buffers_ptr = to_user_pointer(&spin->obj[IGT_SPIN_BATCH]),
85 .rsvd1 = ctx1,
86 };
87
88 igt_assert(gem_context_has_engine_map(fd, 0) ||
89 !(flags & RESUBMIT_ALL_ENGINES));
90
91 if (flags & RESUBMIT_ALL_ENGINES) {
92 gem_context_set_all_engines(fd, ctx0);
93 if (ctx0 != ctx1)
94 gem_context_set_all_engines(fd, ctx1);
95
96 for_each_context_engine(fd, ctx1, other) {
97 if (gem_engine_is_equal(other, e2))
98 continue;
99
100 eb.flags = other->flags;
101 gem_execbuf(fd, &eb);
102 }
103 } else {
104 eb.flags = e2->flags;
105 gem_execbuf(fd, &eb);
106 }
107
108 igt_spin_end(spin);
109
110 gem_sync(fd, spin->handle);
111
112 igt_spin_free(fd, spin);
113
114 if (ctx1 != ctx0)
115 gem_context_destroy(fd, ctx1);
116
117 gem_context_destroy(fd, ctx0);
118 }
119
spin_exit_handler(int sig)120 static void spin_exit_handler(int sig)
121 {
122 igt_terminate_spins();
123 }
124
spin_on_all_engines(int fd,unsigned int timeout_sec)125 static void spin_on_all_engines(int fd, unsigned int timeout_sec)
126 {
127 const struct intel_execution_engine2 *e2;
128
129 __for_each_physical_engine(fd, e2) {
130 igt_fork(child, 1) {
131 igt_install_exit_handler(spin_exit_handler);
132 spin(fd, e2, timeout_sec);
133 }
134 }
135
136 igt_waitchildren();
137 }
138
139 igt_main
140 {
141 const struct intel_execution_engine2 *e2;
142 const struct intel_execution_engine *e;
143 struct intel_execution_engine2 e2__;
144 int fd = -1;
145
146 igt_skip_on_simulation();
147
148 igt_fixture {
149 fd = drm_open_driver(DRIVER_INTEL);
150 igt_require_gem(fd);
151 igt_fork_hang_detector(fd);
152 }
153
154 for (e = intel_execution_engines; e->name; e++) {
155 e2__ = gem_eb_flags_to_engine(e->exec_id | e->flags);
156 if (e2__.flags == -1)
157 continue;
158 e2 = &e2__;
159
160 igt_subtest_f("legacy-%s", e->name)
161 spin(fd, e2, 3);
162
163 igt_subtest_f("legacy-resubmit-%s", e->name)
164 spin_resubmit(fd, e2, 0);
165
166 igt_subtest_f("legacy-resubmit-new-%s", e->name)
167 spin_resubmit(fd, e2, RESUBMIT_NEW_CTX);
168 }
169
__for_each_physical_engine(fd,e2)170 __for_each_physical_engine(fd, e2) {
171 igt_subtest_f("%s", e2->name)
172 spin(fd, e2, 3);
173
174 igt_subtest_f("resubmit-%s", e2->name)
175 spin_resubmit(fd, e2, 0);
176
177 igt_subtest_f("resubmit-new-%s", e2->name)
178 spin_resubmit(fd, e2, RESUBMIT_NEW_CTX);
179
180 igt_subtest_f("resubmit-all-%s", e2->name)
181 spin_resubmit(fd, e2, RESUBMIT_ALL_ENGINES);
182
183 igt_subtest_f("resubmit-new-all-%s", e2->name)
184 spin_resubmit(fd, e2,
185 RESUBMIT_NEW_CTX |
186 RESUBMIT_ALL_ENGINES);
187 }
188
189 igt_subtest("spin-each")
190 spin_on_all_engines(fd, 3);
191
192 igt_fixture {
193 igt_stop_hang_detector();
194 close(fd);
195 }
196 }
197