diff mbox

tests/gem_seqno_wrap: dont sync when crossing half of seqno space

Message ID 1355321758-13961-1-git-send-email-mika.kuoppala@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Mika Kuoppala Dec. 12, 2012, 2:15 p.m. UTC
For seqno comparison to work they have to be less than UINT32_MAX/2
apart. So when crossing the half way of seqno space, be careful not
to sync anything as this causes gpu hangs. Do real test with
syncing only when we are about to wrap.
---
 tests/gem_seqno_wrap.c |  161 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 117 insertions(+), 44 deletions(-)

Comments

Zhang, Xiong Y Dec. 12, 2012, 3:55 p.m. UTC | #1
Hi, all:

When gfx executes batch buffer in render ring buffer, it will do context switch .

Since only when the previous batch buffer has finished, the next batch buffer can start. the batch buffer is executed in order. So I think there is no need to do context switch.

Why i915 driver introduce context switch ?  If context switch is disabled, what error will occur ?

Why gfx need context switch, can somebody give me a example to use context switch ?

Thanks in advance.
Ben Widawsky Dec. 12, 2012, 8:34 p.m. UTC | #2
On Wed, Dec 12, 2012 at 03:55:46PM +0000, Zhang, Xiong Y wrote:
> Hi, all:
> 
> When gfx executes batch buffer in render ring buffer, it will do
> context switch .
> 
> Since only when the previous batch buffer has finished, the next batch
> buffer can start. the batch buffer is executed in order. So I think
> there is no need to do context switch.
> 
> Why i915 driver introduce context switch ?  If context switch is
> disabled, what error will occur ?

No GPU state is preserved in between execution unless you use contexts.
Before contexts, it was required that the client upload any and all
state required to perform operations. While most state is still uploaded
anyway, some of it is not.

If you use a mesa expecting HW contexts, and a kernel which doesn't do
contexts switches, the results are undefined.

> 
> Why gfx need context switch, can somebody give me a example to use
> context switch ?

Transform feedback.

> 
> Thanks in advance.  _______________________________________________
diff mbox

Patch

diff --git a/tests/gem_seqno_wrap.c b/tests/gem_seqno_wrap.c
index b70f886..5ce8c93 100644
--- a/tests/gem_seqno_wrap.c
+++ b/tests/gem_seqno_wrap.c
@@ -47,7 +47,7 @@ 
 #include "intel_gpu_tools.h"
 #include "rendercopy.h"
 
-#define BUFFERS_TO_SYNC 128
+#define SAFETY_REGION 0x1f
 
 static int devid;
 static uint32_t last_seqno = 0;
@@ -64,6 +64,8 @@  struct option_struct {
 	int timeout;
 	int dontwrap;
 	int prewrap_space;
+	int random;
+	int buffers;
 };
 
 static struct option_struct options;
@@ -159,21 +161,34 @@  static void render_copyfunc(struct scratch_buf *src,
 	}
 }
 
-static int run_sync_test(void)
+static void exchange_uint(void *array, unsigned i, unsigned j)
+{
+	unsigned *i_arr = array;
+	unsigned i_tmp;
+
+	i_tmp = i_arr[i];
+	i_arr[i] = i_arr[j];
+	i_arr[j] = i_tmp;
+}
+
+static int run_sync_test(int num_buffers, bool verify)
 {
 	drm_intel_bufmgr *bufmgr;
-	int num_buffers = BUFFERS_TO_SYNC, max;
+	int max;
 	drm_intel_bo *src[128], *dst1[128], *dst2[128];
 	int width = 128, height = 128;
 	int fd;
 	int i;
 	int r = -1;
 	int failed = 0;
-
+	unsigned int *p_dst1, *p_dst2;
 	struct scratch_buf s_src[128], s_dst[128];
 
 	fd = drm_open_any();
 	assert(fd >= 0);
+
+	gem_quiescent_gpu(fd);
+
 	devid = intel_get_drm_devid(fd);
 
 	max = gem_aperture_size (fd) / (1024 * 1024) / 2;
@@ -187,7 +202,16 @@  static int run_sync_test(void)
 	batch_3d = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
 	assert(batch_3d);
 
+	p_dst1 = malloc(num_buffers * sizeof(unsigned int));
+	if (p_dst1 == NULL)
+		return -ENOMEM;
+
+	p_dst2 = malloc(num_buffers * sizeof(unsigned int));
+	if (p_dst2 == NULL)
+		return -ENOMEM;
+
 	for (i = 0; i < num_buffers; i++) {
+		p_dst1[i] = p_dst2[i] = i;
 		src[i] = create_bo(bufmgr, i, width, height);
 		dst1[i] = create_bo(bufmgr, ~i, width, height);
 		dst2[i] = create_bo(bufmgr, ~i, width, height);
@@ -195,19 +219,27 @@  static int run_sync_test(void)
 		init_buffer(bufmgr, &s_dst[i], dst1[i], width, height);
 	}
 
-	/* dummy = create_bo(bufmgr, 0, width, height); */
-
-	for (i = 0; i < num_buffers; i++) {
-		render_copyfunc(&s_src[i], &s_dst[i], width, height);
-		intel_copy_bo(batch_blt, dst2[i], dst1[i], width, height);
-	}
-
-	for (i = 0; i < num_buffers; i++) {
-		r = cmp_bo(dst2[i], i, width, height);
-		if (r) {
-			printf("buffer %d differs, seqno_before_test 0x%x, approximated seqno on test fail 0x%x\n",
-			       i, last_seqno_write, last_seqno_write + i * 2);
-			failed = -1;
+	drmtest_permute_array(p_dst1, num_buffers, exchange_uint);
+	drmtest_permute_array(p_dst2, num_buffers, exchange_uint);
+
+	for (i = 0; i < num_buffers; i++)
+		render_copyfunc(&s_src[i], &s_dst[p_dst1[i]], width, height);
+
+	/* Only sync between buffers if this is actual test run and
+	 * not a seqno filler */
+	if (verify) {
+		for (i = 0; i < num_buffers; i++)
+			intel_copy_bo(batch_blt, dst2[p_dst2[i]], dst1[p_dst1[i]],
+				      width, height);
+
+		for (i = 0; i < num_buffers; i++) {
+			r = cmp_bo(dst2[p_dst2[i]], i, width, height);
+			if (r) {
+				printf("buffer %d differs, seqno_before_test 0x%x, "
+				       " approximated seqno on test fail 0x%x\n",
+				       i, last_seqno_write, last_seqno_write + i * 2);
+				failed = -1;
+			}
 		}
 	}
 
@@ -221,6 +253,11 @@  static int run_sync_test(void)
 	intel_batchbuffer_free(batch_blt);
 	drm_intel_bufmgr_destroy(bufmgr);
 
+	free(p_dst1);
+	free(p_dst2);
+
+	gem_quiescent_gpu(fd);
+
 	close(fd);
 
 	return failed;
@@ -270,7 +307,9 @@  static int run_cmd(char *s)
 			if (r == pid) {
 				if(WIFEXITED(status)) {
 					if (WEXITSTATUS(status))
-						fprintf(stderr, "child returned with %d\n", WEXITSTATUS(status));
+						fprintf(stderr,
+						    "child returned with %d\n",
+							WEXITSTATUS(status));
 					return WEXITSTATUS(status);
 				}
 			} else if (r != 0) {
@@ -365,9 +404,25 @@  static int write_seqno(uint32_t seqno)
 
 static uint32_t calc_prewrap_val(void)
 {
-	const int pval = options.prewrap_space - 1;
+	const int pval = options.prewrap_space;
+
+	if (options.random == 0)
+		return pval;
+
+	return random() % pval;
+}
+
+static int seqno_near_boundary(uint32_t seqno)
+{
+	if (seqno > UINT32_MAX - options.prewrap_space ||
+	    seqno < options.prewrap_space)
+		return 1;
 
-	return (pval >> 1) + (random() % (pval >> 1));
+	if (seqno < UINT32_MAX/2 + SAFETY_REGION &&
+	    seqno > UINT32_MAX/2 - SAFETY_REGION)
+		return 1;
+
+	return 0;
 }
 
 static int run_once(void)
@@ -382,29 +437,25 @@  static int run_once(void)
 	r = read_seqno(&seqno_before);
 	assert(r == 0);
 
-	if (seqno_before == last_seqno) {
-		sleep(2);
-		return 0;
-	}
-
 	seqno = last_seqno = seqno_before;
 
-	if (seqno < UINT32_MAX - options.prewrap_space) {
-		if (seqno < UINT32_MAX/2)
-			seqno = UINT32_MAX/2 - options.prewrap_space;
-		else
+	/* Skip seqno write if close to boundary */
+	if (!seqno_near_boundary(seqno)) {
+		if (seqno > UINT32_MAX/2 + 1)
 			seqno = UINT32_MAX - pw_val;
-
-		if ((int)(seqno - seqno_before) <= 0)
-			return 0;
+		else
+			seqno = UINT32_MAX/2 - SAFETY_REGION;
 
 		if (!options.dontwrap) {
 			r = write_seqno(seqno);
 			if (r < 0) {
-				fprintf(stderr, "write_seqno returned %d\n", r);
+				fprintf(stderr,
+					"write_seqno 0x%x returned %d\n",
+					seqno, r);
 
-				/* We might fail if we are at background and some
-				 * operations were done between seqno read and this write
+				/* We might fail if we are at background and
+				 * some operations were done between seqno
+				 * read and this write
 				 */
 				if (!options.background)
 					return r;
@@ -412,11 +463,18 @@  static int run_once(void)
 		}
 	}
 
-	if (options.background == 0) {
-		if (strnlen(options.cmd, sizeof(options.cmd)) > 0) {
-			r = run_cmd(options.cmd);
+	if (!options.background) {
+		/* Only run tests if we are across the half way of seqno space.
+		 * If we are not, run something which just increments seqnos
+		 */
+		if (seqno >= UINT32_MAX/2 + 1) {
+			if (strnlen(options.cmd, sizeof(options.cmd)) > 0) {
+				r = run_cmd(options.cmd);
+			} else {
+				r = run_sync_test(options.buffers, true);
+			}
 		} else {
-			r = run_sync_test();
+			r = run_sync_test(options.buffers, false);
 		}
 
 		if (r != 0) {
@@ -434,7 +492,8 @@  static int run_once(void)
 	if (seqno_before > seqno_after) {
 		if (options.verbose)
 			printf("before 0x%x, after 0x%x , diff %d\n",
-			       seqno_before, seqno_after, seqno_after - seqno_before);
+			       seqno_before, seqno_after,
+			       seqno_after - seqno_before);
 
 		return 1;
 	}
@@ -452,6 +511,8 @@  static void print_usage(const char *s)
 	printf("    -t --timeout=sec      set timeout to wait for testrun to sec seconds\n");
 	printf("    -d --dontwrap         don't wrap just run the test\n");
 	printf("    -p --prewrap=n        set seqno to WRAP - n for each testrun\n");
+	printf("    -r --norandom         dont randomize prewrap space\n");
+	printf("    -i --buffers          number of buffers to copy\n");
 	exit(-1);
 }
 
@@ -467,17 +528,21 @@  static void parse_options(int argc, char **argv)
 		{"dontwrap", no_argument, 0, 'd'},
 		{"verbose", no_argument, 0, 'v'},
 		{"prewrap", required_argument, 0, 'p'},
+		{"norandom", no_argument, 0, 'r'},
+		{"buffers", required_argument, 0, 'i'},
 	};
 
 	strcpy(options.cmd, "");
-	options.rounds = 5;
+	options.rounds = 50;
 	options.background = 0;
 	options.dontwrap = 0;
 	options.timeout = 20;
 	options.verbose = 0;
-	options.prewrap_space = BUFFERS_TO_SYNC/2;
+	options.random = 1;
+	options.prewrap_space = 30;
+	options.buffers = 20;
 
-	while((c = getopt_long(argc, argv, "c:n:bvt:dp:",
+	while((c = getopt_long(argc, argv, "c:n:bvt:dp:ri:",
 			       long_options, &option_index)) != -1) {
 		switch(c) {
 		case 'b':
@@ -497,15 +562,23 @@  static void parse_options(int argc, char **argv)
 			options.cmd[sizeof(options.cmd) - 1] = 0;
 			printf("cmd set to %s\n", options.cmd);
 			break;
+		case 'i':
+			options.buffers = atoi(optarg);
+			printf("buffers %d\n", options.buffers);
+			break;
 		case 't':
 			options.timeout = atoi(optarg);
 			if (options.timeout == 0)
 				options.timeout = 10;
-			printf("setting timeout to %d seconds\n", options.timeout);
+			printf("setting timeout to %d seconds\n",
+			       options.timeout);
 			break;
 		case 'v':
 			options.verbose = 1;
 			break;
+		case 'r':
+			options.random = 0;
+			break;
 		case 'p':
 			options.prewrap_space = atoi(optarg);
 			if (options.prewrap_space == 0)