2 * Copyright © 2012 Intel Corporation
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:
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
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
24 * Ben Widawsky <ben@bwidawsk.net>
31 #include <sys/ioctl.h>
42 #include "ioctl_wrappers.h"
44 #include "intel_bufmgr.h"
45 #include "intel_batchbuffer.h"
47 #include "intel_chipset.h"
50 #define MSEC_PER_SEC 1000L
51 #define USEC_PER_MSEC 1000L
52 #define NSEC_PER_USEC 1000L
53 #define NSEC_PER_MSEC 1000000L
54 #define USEC_PER_SEC 1000000L
55 #define NSEC_PER_SEC 1000000000L
57 #define ENOUGH_WORK_IN_SECONDS 2
58 #define BUF_SIZE (8<<20)
59 #define BUF_PAGES ((8<<20)>>12)
60 drm_intel_bo *dst, *dst2;
62 /* returns time diff in milliseconds */
64 do_time_diff(struct timespec *end, struct timespec *start)
67 ret = (MSEC_PER_SEC * difftime(end->tv_sec, start->tv_sec)) +
68 ((end->tv_nsec/NSEC_PER_MSEC) - (start->tv_nsec/NSEC_PER_MSEC));
72 /* to avoid stupid depencies on libdrm, copy&paste */
73 struct local_drm_i915_gem_wait {
74 /** Handle of BO we shall wait on */
77 /** Number of nanoseconds to wait, Returns time remaining. */
81 # define WAIT_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2c, struct local_drm_i915_gem_wait)
84 gem_bo_wait_timeout(int fd, uint32_t handle, uint64_t *timeout_ns)
86 struct local_drm_i915_gem_wait wait;
89 igt_assert(timeout_ns);
91 wait.bo_handle = handle;
92 wait.timeout_ns = *timeout_ns;
94 ret = drmIoctl(fd, WAIT_IOCTL, &wait);
95 *timeout_ns = wait.timeout_ns;
97 return ret ? -errno : 0;
100 static void blt_color_fill(struct intel_batchbuffer *batch,
102 const unsigned int pages)
104 const unsigned short height = pages/4;
105 const unsigned short width = 4096;
107 if (intel_gen(batch->devid) >= 8) {
110 OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | 5 |
111 COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
114 OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | 4 |
115 COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
117 OUT_BATCH((3 << 24) | /* 32 Bit Color */
118 (0xF0 << 16) | /* Raster OP copy background register */
119 0); /* Dest pitch is 0 */
121 OUT_BATCH(width << 16 |
123 OUT_RELOC(buf, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
124 if (intel_gen(batch->devid) >= 8)
126 OUT_BATCH(rand()); /* random pattern */
132 drm_intel_bufmgr *bufmgr;
133 struct intel_batchbuffer *batch;
134 uint64_t timeout = ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC;
136 const bool do_signals = true; /* signals will seem to make the operation
137 * use less process CPU time */
141 igt_skip_on_simulation();
145 bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
146 drm_intel_bufmgr_gem_enable_reuse(bufmgr);
147 batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
149 dst = drm_intel_bo_alloc(bufmgr, "dst", BUF_SIZE, 4096);
150 dst2 = drm_intel_bo_alloc(bufmgr, "dst2", BUF_SIZE, 4096);
152 igt_skip_on_f(gem_bo_wait_timeout(fd, dst->handle, &timeout) == -EINVAL,
153 "kernel doesn't support wait_timeout, skipping test\n");
154 timeout = ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC;
156 /* Figure out a rough number of fills required to consume 1 second of
160 struct timespec start, end;
163 #ifndef CLOCK_MONOTONIC_RAW
164 #define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
167 igt_assert(clock_gettime(CLOCK_MONOTONIC_RAW, &start) == 0);
168 for (i = 0; i < iter; i++)
169 blt_color_fill(batch, dst, BUF_PAGES);
170 intel_batchbuffer_flush(batch);
171 drm_intel_bo_wait_rendering(dst);
172 igt_assert(clock_gettime(CLOCK_MONOTONIC_RAW, &end) == 0);
174 diff = do_time_diff(&end, &start);
175 igt_assert(diff >= 0);
177 if ((diff / MSEC_PER_SEC) > ENOUGH_WORK_IN_SECONDS)
181 } while (!done && iter < 1000000);
183 igt_assert_cmpint(iter, <, >=, 1000000);
185 igt_info("%d iters is enough work\n", iter);
186 gem_quiescent_gpu(fd);
188 igt_fork_signal_helper();
190 /* We should be able to do half as much work in the same amount of time,
191 * but because we might schedule almost twice as much as required, we
192 * might accidentally time out. Hence add some fudge. */
193 for (i = 0; i < iter/3; i++)
194 blt_color_fill(batch, dst2, BUF_PAGES);
196 intel_batchbuffer_flush(batch);
197 igt_assert(gem_bo_busy(fd, dst2->handle) == true);
199 igt_assert_eq(gem_bo_wait_timeout(fd, dst2->handle, &timeout), 0);
200 igt_assert(gem_bo_busy(fd, dst2->handle) == false);
201 igt_assert_neq(timeout, 0);
202 if (timeout == (ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC))
203 igt_info("Buffer was already done!\n");
205 igt_info("Finished with %lu time remaining\n", timeout);
208 /* check that polling with timeout=0 works. */
210 igt_assert_eq(gem_bo_wait_timeout(fd, dst2->handle, &timeout), 0);
211 igt_assert_eq(timeout, 0);
213 /* Now check that we correctly time out, twice the auto-tune load should
215 timeout = ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC;
216 for (i = 0; i < iter*2; i++)
217 blt_color_fill(batch, dst2, BUF_PAGES);
219 intel_batchbuffer_flush(batch);
221 ret = gem_bo_wait_timeout(fd, dst2->handle, &timeout);
222 igt_assert_eq(ret, -ETIME);
223 igt_assert_eq(timeout, 0);
224 igt_assert(gem_bo_busy(fd, dst2->handle) == true);
226 /* check that polling with timeout=0 works. */
228 igt_assert_eq(gem_bo_wait_timeout(fd, dst2->handle, &timeout), -ETIME);
229 igt_assert_eq(timeout, 0);
233 igt_stop_signal_helper();
234 drm_intel_bo_unreference(dst2);
235 drm_intel_bo_unreference(dst);
236 intel_batchbuffer_free(batch);
237 drm_intel_bufmgr_destroy(bufmgr);