[Intel-gfx] [PATCH i-g-t 1/4] lib/igt_bb_factory: Add igt_bb_factory library
Derek Morton
derek.j.morton at intel.com
Fri Feb 12 09:38:51 UTC 2016
Adds functions to create a number of different batch buffers to perform
several functions including:
Batch buffer which will run for a long duration to provide a delay on a
specified ring.
Function to calibrate the delay batch buffer to run for a specified period
of time.
Function to create a batch buffer which writes timestamps to a buffer object.
Function to compare timestamps allowing for wrapping of the values.
Intended for use by the gem_scheduler test initially but will be used by other
tests in development.
Signed-off-by: Derek Morton <derek.j.morton at intel.com>
---
lib/Makefile.sources | 2 +
lib/igt.h | 1 +
lib/igt_bb_factory.c | 401 +++++++++++++++++++++++++++++++++++++++++++++++++++
lib/igt_bb_factory.h | 47 ++++++
4 files changed, 451 insertions(+)
create mode 100644 lib/igt_bb_factory.c
create mode 100644 lib/igt_bb_factory.h
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index 4999868..c560b3e 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -7,6 +7,8 @@ libintel_tools_la_SOURCES = \
i915_reg.h \
i915_pciids.h \
igt.h \
+ igt_bb_factory.c \
+ igt_bb_factory.h \
igt_debugfs.c \
igt_debugfs.h \
igt_aux.c \
diff --git a/lib/igt.h b/lib/igt.h
index 3be2551..0f29420 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -36,6 +36,7 @@
#include "igt_gt.h"
#include "igt_kms.h"
#include "igt_stats.h"
+#include "igt_bb_factory.h"
#include "instdone.h"
#include "intel_batchbuffer.h"
#include "intel_chipset.h"
diff --git a/lib/igt_bb_factory.c b/lib/igt_bb_factory.c
new file mode 100644
index 0000000..eea63c6
--- /dev/null
+++ b/lib/igt_bb_factory.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright © 2016 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.
+ *
+ * Authors:
+ * Derek Morton <derek.j.morton at intel.com>
+ *
+ */
+
+#include "igt.h"
+#include "intel_batchbuffer.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include <time.h>
+
+#define SEC_TO_NSEC (1000 * 1000 * 1000)
+#define DWORDS_TO_BYTES(x) ((x)*4)
+
+#define MI_STORE_REGISTER_MEM(LENGTH) ((0x024 << 23) | ((LENGTH - 2) & 0xff))
+#define MI_MATH(NrInst) ((0x01A << 23) | ((NrInst - 1) & 0x3f))
+#define MI_CONDITIONAL_BATCH_BUFFER_END ((0x036 << 23) | (1 << 21) | 2)
+#define MI_COPY_MEM_MEM ((0x02E << 23) | (3))
+
+#define ALU_LOAD(TO, FROM) ((0x080 << 20) | ((TO) << 10) | (FROM))
+#define ALU_SUB ( 0x101 << 20)
+#define ALU_STORE(TO, FROM) ((0x180 << 20) | ((TO) << 10) | (FROM))
+
+#define TIMESTAMP_offset (0x358) /* Elapsed time from system start */
+#define CTX_TIMESTAMP_offset (0x3A8) /* Elapsed Time from context creation */
+#define ALU_GPU_R0_LSB_offset (0x600)
+#define ALU_GPU_R0_MSB_offset (0x604)
+#define ALU_GPU_R1_LSB_offset (0x608)
+#define ALU_GPU_R1_MSB_offset (0x60C)
+#define ALU_GPU_R2_LSB_offset (0x610)
+#define ALU_GPU_R2_MSB_offset (0x614)
+
+#define ALU_R0_ENCODING (0x00)
+#define ALU_R1_ENCODING (0x01)
+#define ALU_SRCA_ENCODING (0x20)
+#define ALU_SRCB_ENCODING (0x21)
+#define ALU_ACCU_ENCODING (0x31)
+
+/**
+ * SECTION:igt_bb_factory
+ * @short_description: Utility functions for creating batch buffers
+ * @title: Batch Buffer Factory
+ * @include: igt.h
+ *
+ * This library implements functions for creating batch buffers which may be
+ * useful to multiple tests.
+ */
+
+static void check_gen_8(int fd)
+{
+ static bool checked = false;
+ if(!checked) {
+ igt_require(intel_gen(intel_get_drm_devid(fd)) >= 8);
+ checked = true;
+ }
+}
+
+static int bb_address_size_dw(int fd)
+{
+ if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+ return 2;
+ else
+ return 1;
+}
+
+static uint32_t get_register_offset(int ringid)
+{
+ switch (ringid) {
+ case I915_EXEC_RENDER:
+ return 0x02000;
+ case I915_EXEC_BSD:
+ return 0x12000;
+ case I915_EXEC_BLT:
+ return 0x22000;
+ case I915_EXEC_VEBOX:
+ return 0x1A000;
+ default:
+ igt_assert_f(0, "Invalid ringid %d passed to get_register_offset()\n", ringid);
+ }
+}
+
+/**
+ * igt_create_delay_bb:
+ * @fd: file descriptor for i915 driver instance
+ * @bufmgr: Buffer manager to be used for creation of batch buffers
+ * ringid: Ring to create batch buffer for. e.g. I915_EXEC_RENDER
+ * loops: Number of times to loop
+ * dest: Buffer to use for saving the current loop count and timestamp.
+ *
+ * This creates a batch buffer which will iterate a loop a specified number
+ * of times. Intended for creating batch buffers which take an arbitarily
+ * long time to execute. This can be useful to keep a ring busy while
+ * constructing a test scenario.
+ *
+ * The dest buffer will have a number of Dwords written by the batch buffer
+ * when it runs. They are:
+ * DW0 & DW1 - These are loade with the value of 'loops' and are decremented
+ * as the batch buffer executes. They will be 0 after the batch
+ * buffer completes if it finished succesfully.
+ * DW2 Timestamp - An indication of when the batch buffer ran allowing a
+ * comparison between batch buffers to show execution order.
+ * May wrap so igt_compare_timestamps() should be used to
+ * compare timestamps.
+ *
+ * Returns:
+ * The struct intel_batchbuffer created.
+ */
+struct intel_batchbuffer *igt_create_delay_bb(int fd, drm_intel_bufmgr *bufmgr,
+ int ringid, uint32_t loops, drm_intel_bo *dest)
+{
+ struct intel_batchbuffer *batch;
+ int addr_size_dw;
+ uint32_t regOffset;
+
+ check_gen_8(fd);
+
+ addr_size_dw = bb_address_size_dw(fd);
+ regOffset = get_register_offset(ringid);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+ igt_assert(batch);
+
+ BEGIN_BATCH(32, 5);
+ /* store current timestamp in DW2 */
+ OUT_BATCH(MI_STORE_REGISTER_MEM(addr_size_dw + 2));
+ OUT_BATCH(regOffset + TIMESTAMP_offset);
+ OUT_RELOC(dest, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, DWORDS_TO_BYTES(2));
+
+ /* Load R0 with loops */
+ OUT_BATCH(MI_LOAD_REGISTER_IMM);
+ OUT_BATCH(regOffset + ALU_GPU_R0_LSB_offset);
+ OUT_BATCH(loops);
+ OUT_BATCH(MI_LOAD_REGISTER_IMM);
+ OUT_BATCH(regOffset + ALU_GPU_R0_MSB_offset);
+ OUT_BATCH(0x00000000);
+ /* Load R1 with 1 */
+ OUT_BATCH(MI_LOAD_REGISTER_IMM);
+ OUT_BATCH(regOffset + ALU_GPU_R1_LSB_offset);
+ OUT_BATCH(0x00000001);
+ OUT_BATCH(MI_LOAD_REGISTER_IMM);
+ OUT_BATCH(regOffset + ALU_GPU_R1_MSB_offset);
+ OUT_BATCH(0x00000000);
+ /* Copy R0 / R1 into SRCA / SRCB, Perform R0 - R1, Store result in R0 */
+ /* e.g. R0 -= 1 */
+ OUT_BATCH(MI_MATH(4));
+ OUT_BATCH(ALU_LOAD(ALU_SRCA_ENCODING, ALU_R0_ENCODING));
+ OUT_BATCH(ALU_LOAD(ALU_SRCB_ENCODING, ALU_R1_ENCODING));
+ OUT_BATCH(ALU_SUB);
+ OUT_BATCH(ALU_STORE(ALU_R0_ENCODING, ALU_ACCU_ENCODING));
+ /* Copy R0 to dest
+ * On Gen8 MI_CONDITIONAL_BATCH_BUFFER_END BSD ring Compare address
+ * points to 2 Dwords, a mask (DW0) and data (DW1) which are ANDed
+ * together.
+ * On Gen9+, and the other rings on Gen8 Compare address points to
+ * just Data (DW0). For simplicity always copy R0 LSB to DW0 and DW1.
+ */
+ OUT_BATCH(MI_STORE_REGISTER_MEM(addr_size_dw + 2));
+ OUT_BATCH(regOffset + ALU_GPU_R0_LSB_offset);
+ OUT_RELOC(dest, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 0);
+ OUT_BATCH(MI_STORE_REGISTER_MEM(addr_size_dw + 2));
+ OUT_BATCH(regOffset + ALU_GPU_R0_LSB_offset);
+ OUT_RELOC(dest, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, DWORDS_TO_BYTES(1));
+ /* Repeat until R0 == 0 */
+ OUT_BATCH(MI_CONDITIONAL_BATCH_BUFFER_END);
+ OUT_BATCH(0x00000000);
+ OUT_RELOC(dest, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 0);
+ OUT_BATCH(MI_BATCH_BUFFER_START | (addr_size_dw - 1));
+ OUT_RELOC(batch->bo, I915_GEM_DOMAIN_INSTRUCTION, 0, DWORDS_TO_BYTES(15));
+ /* Should never get here, but end if it happens */
+
+ OUT_BATCH(MI_BATCH_BUFFER_END);
+ ADVANCE_BATCH();
+
+ return batch;
+}
+
+/**
+ * igt_create_timestamp_bb:
+ * @fd: file descriptor for i915 driver instance
+ * @bufmgr: Buffer manager to be used for creation of batch buffers
+ * ringid: Ring to create batch buffer for. e.g. I915_EXEC_RENDER
+ * dest: Buffer to use for saving the timestamps.
+ * load: Buffer to access. Set NULL if not required.
+ * write: If true and load is not NULL, will also write a timestamp to load
+ * buffer. If false and load is not NULL, will read from load buffer into dest.
+ * Intended for dependency checking.
+ *
+ * This creates a batch buffer which writes timestamps into a buffer object.
+ * If 'load' is non null, data is either written to 'load' or copied from 'load'
+ * depending on whether 'write' is set.
+ *
+ * The dest buffer will have a number of Dwords written by the batch buffer
+ * when it runs. They are:
+ * DW0 Reported timestamp - An indication of when the batch buffer ran allowing a
+ * comparison between batch buffers to show execution order.
+ * May wrap so igt_compare_timestamps() should be used to
+ * compare timestamps.
+ * DW1 Context timestamp - Elapsed time since context was created.
+ * DW2 Value copied from DW0 of load if write == false
+ *
+ * Returns:
+ * The struct intel_batchbuffer created.
+ */
+struct intel_batchbuffer *igt_create_timestamp_bb(int fd, drm_intel_bufmgr *bufmgr,
+ int ringid, drm_intel_bo *dest, drm_intel_bo *load, bool write)
+{
+ struct intel_batchbuffer *batch;
+ int addr_size_dw;
+ uint32_t regOffset;
+
+ check_gen_8(fd);
+
+ addr_size_dw = bb_address_size_dw(fd);
+ regOffset = get_register_offset(ringid);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+ igt_assert(batch);
+
+ BEGIN_BATCH(6, 2);
+ /* store current reported timestamp in DW0 */
+ OUT_BATCH(MI_STORE_REGISTER_MEM(addr_size_dw + 2));
+ OUT_BATCH(regOffset + TIMESTAMP_offset);
+ OUT_RELOC(dest, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, DWORDS_TO_BYTES(0));
+
+ /* store current context timestamp in DW1 */
+ OUT_BATCH(MI_STORE_REGISTER_MEM(addr_size_dw + 2));
+ OUT_BATCH(regOffset + CTX_TIMESTAMP_offset);
+ OUT_RELOC(dest, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, DWORDS_TO_BYTES(1));
+
+ ADVANCE_BATCH();
+
+ if(load != NULL) {
+ if(write) {
+ BEGIN_BATCH(3, 1);
+ OUT_BATCH(MI_STORE_REGISTER_MEM(addr_size_dw + 2));
+ OUT_BATCH(regOffset + TIMESTAMP_offset);
+ OUT_RELOC(load, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, DWORDS_TO_BYTES(0));
+ ADVANCE_BATCH();
+ }
+ else {
+ BEGIN_BATCH(3, 2);
+ OUT_BATCH(MI_COPY_MEM_MEM);
+ OUT_RELOC(dest, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, DWORDS_TO_BYTES(2));
+ OUT_RELOC(load, I915_GEM_DOMAIN_INSTRUCTION, 0, DWORDS_TO_BYTES(0));
+ ADVANCE_BATCH();
+ }
+ }
+
+ BEGIN_BATCH(1, 0);
+ OUT_BATCH(MI_BATCH_BUFFER_END);
+ ADVANCE_BATCH();
+
+ return batch;
+}
+
+/**
+ * igt_create_noop_bb:
+ * @fd: file descriptor for i915 driver instance
+ * @bufmgr: Buffer manager to be used for creation of batch buffers
+ * ringid: Ring to create batch buffer for. e.g. I915_EXEC_RENDER
+ * noops: Number of MI_NOOP instructions to add to the batch buffer.
+ *
+ * This creates a batch buffer with a specified number of MI_NOOP instructions.
+ *
+ * Returns:
+ * The struct intel_batchbuffer created.
+ */
+struct intel_batchbuffer *igt_create_noop_bb(int fd, drm_intel_bufmgr *bufmgr,
+ int ringid, int noops)
+{
+ struct intel_batchbuffer *batch;
+ int loop;
+
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+ igt_assert(batch);
+
+ BEGIN_BATCH(noops + 1, 0);
+ for(loop = 0; loop < noops; loop++)
+ OUT_BATCH(MI_NOOP);
+ OUT_BATCH(MI_BATCH_BUFFER_END);
+ ADVANCE_BATCH();
+
+ return batch;
+}
+
+/* Store calibrated values so they only need calculating once.
+ * I915_EXEC_RING_MASK allows 3 bits for ring ids so allow for storing 8 values */
+static uint32_t calibrated_ring_value[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+/**
+ * igt_calibrate_delay_bb:
+ * @fd: file descriptor for i915 driver instance
+ * @bufmgr: Buffer manager to be used for creation of batch buffers
+ * ringid: Ring to calibrate. e.g. I915_EXEC_RENDER
+ *
+ * This calculates the value of loops that would need to be passed to
+ * igt_create_delay_bb() to create a delay of about 1 second on the specified
+ * ring.
+ *
+ * Returns:
+ * uint32_t to be passed to igt_create_delay_bb().
+ */
+#define CAL_SEED (0x100000)
+uint32_t igt_calibrate_delay_bb(int fd, drm_intel_bufmgr *bufmgr, int ringid)
+{
+ uint32_t *buf;
+ struct intel_batchbuffer *bb;
+ struct timespec start, end;
+ uint64_t duration;
+ uint64_t calibrated;
+ drm_intel_bo *target_bo;
+
+ igt_assert(ringid < 8);
+ if(calibrated_ring_value[ringid] != 0)
+ return calibrated_ring_value[ringid];
+
+ target_bo = drm_intel_bo_alloc(bufmgr, "target bo", BATCH_SZ, BATCH_SZ);
+ igt_assert(target_bo);
+
+ /* Put some non zero values in the target bo */
+ drm_intel_bo_map(target_bo, 1);
+ buf = target_bo->virtual;
+ buf[0] = 0xff;
+ drm_intel_bo_unmap(target_bo);
+
+ bb = igt_create_delay_bb(fd, bufmgr, ringid, CAL_SEED, target_bo);
+
+ gem_quiescent_gpu(fd);
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ intel_batchbuffer_flush_on_ring(bb, ringid);
+ /* This will not return until the bo has finished executing */
+ drm_intel_bo_map(target_bo, 0);
+ clock_gettime(CLOCK_MONOTONIC, &end);
+
+ buf = target_bo->virtual;
+ /* buf[0] in the target buffer should be 0 if the batch buffer completed */
+ igt_assert_f(buf[0] == 0, "buf[0] expected 0x0, got 0x%x\n", buf[0]);
+
+ duration = ((((uint64_t)end.tv_sec - (uint64_t)start.tv_sec) * SEC_TO_NSEC)
+ + (uint64_t)end.tv_nsec) - (uint64_t)start.tv_nsec;
+
+ calibrated = (((uint64_t)(CAL_SEED) * SEC_TO_NSEC) / duration);
+ igt_debug("Uncalibrated run took %" PRIu64 ".%04" PRIu64 "s\n",
+ duration / SEC_TO_NSEC,
+ (duration % SEC_TO_NSEC) / 100000);
+ drm_intel_bo_unreference(target_bo);
+ intel_batchbuffer_free(bb);
+
+ /* Sanity check. If duration < 100ms, something has clearly gone wrong
+ * */
+ igt_assert(duration > (SEC_TO_NSEC / 10));
+
+ igt_assert_f(calibrated <= UINT32_MAX, "Calibrated value > UINT32_MAX\n");
+
+ calibrated_ring_value[ringid] = (uint32_t)calibrated;
+ return (uint32_t)calibrated;
+}
+
+/**
+ * igt_compare_timestamps:
+ * @ts1: timestamp 1
+ * @ts2: timestamp 2
+ *
+ * This compares two uint32_t timestamps. To handle wrapping it assumes the
+ * difference between the two timestamps is less than 1/4 the max elapsed time
+ * represented by the counters.
+ * It also assumes the timestamps are samples from the same counter.
+ *
+ * Returns:
+ * True if ts2 > ts1, allowing for counter wrapping, false otherwise.
+ */
+
+bool igt_compare_timestamps(uint32_t ts1, uint32_t ts2)
+{
+ if (ts2 > ts1)
+ return true;
+ else if ((ts1 > 0x80000000) && (ts2 < 0x40000000))
+ return true; /* Assuming timestamp counter wrapped */
+ else
+ return false;
+}
diff --git a/lib/igt_bb_factory.h b/lib/igt_bb_factory.h
new file mode 100644
index 0000000..3ab7f13
--- /dev/null
+++ b/lib/igt_bb_factory.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2016 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.
+ *
+ * Authors:
+ * Derek Morton <derek.j.morton at intel.com>
+ *
+ */
+
+#ifndef IGT_BB_FACTORY_H
+#define IGT_BB_FACTORY_H
+
+#include "intel_batchbuffer.h"
+#include <stdint.h>
+
+struct intel_batchbuffer *igt_create_delay_bb(int fd, drm_intel_bufmgr *bufmgr,
+ int ringid, uint32_t loops, drm_intel_bo *dest);
+
+struct intel_batchbuffer *igt_create_timestamp_bb(int fd, drm_intel_bufmgr *bufmgr,
+ int ringid, drm_intel_bo *dest, drm_intel_bo *load, bool write);
+
+struct intel_batchbuffer *igt_create_noop_bb(int fd, drm_intel_bufmgr *bufmgr,
+ int ringid, int noops);
+
+uint32_t igt_calibrate_delay_bb(int fd, drm_intel_bufmgr *bufmgr, int ringid);
+
+bool igt_compare_timestamps(uint32_t ts1, uint32_t ts2);
+
+#endif /* IGT_BB_FACTORY_H */
--
1.9.1
More information about the Intel-gfx
mailing list