[PATCH i-g-t v3 10/13] tests/sw_sync: Add subtest test_sync_multi_consumer_producer

robert.foss
2016-09-13T18:23:23Z

This test verifies that stressing the kernel by creating multiple
consumer/producer threads that wait on a single timeline to be incremented
by another conumer/producer thread does not fail.
And that the order amongst the threads is maintained.

Signed-off-by: Robert Foss <robert.foss@collabora.com>
Reviewed-by: Eric Engestrom <eric@engestrom.ch>
---
tests/sw_sync.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)

diff --git a/tests/sw_sync.c b/tests/sw_sync.c
index 7de93a8..27531ab 100644
--- a/tests/sw_sync.c
+++ b/tests/sw_sync.c
@@ -304,6 +304,86 @@ static void test_sync_multi_consumer(void)
igt_assert_f(thread_ret == 0, "A sync thread reported failure.\n");
}

+static void * test_sync_multi_consumer_producer_thread(void *arg)
+{
+ data_t *data = arg;
+ int thread_id = data->thread_id;
+ int nbr_threads = data->nbr_threads;
+ int timeline = data->timeline;
+ int iterations = data->nbr_iterations;
+ int ret, i;
+
+ for (i = 0; i < iterations; i++) {
+ int next_point = i * nbr_threads + thread_id;
+ int fence = sw_sync_fence_create(timeline, next_point);
+
+ ret = sw_sync_wait(fence, 1000);
+ if (ret <= 0)
+ {
+ return (void *) 1;
+ }
+
+ if (*(data->counter) != next_point)
+ {
+ return (void *) 1;
+ }
+
+ (*data->counter)++;
+
+ /* Kick off the next thread. */
+ sw_sync_timeline_inc(timeline, 1);
+
+ close(fence);
+ }
+ return NULL;
+}
+
+static void test_sync_multi_consumer_producer(void)
+{
+ const uint32_t nbr_threads = 8;
+ const uint32_t nbr_iterations = 1 << 14;
+ data_t data_arr[nbr_threads];
+ pthread_t thread_arr[nbr_threads];
+ int timeline;
+ volatile uint32_t counter = 0;
+ uintptr_t thread_ret = 0;
+ data_t data;
+ int i, ret;
+
+ timeline = sw_sync_timeline_create();
+
+ data.nbr_iterations = nbr_iterations;
+ data.nbr_threads = nbr_threads;
+ data.counter = &counter;
+ data.timeline = timeline;
+
+ /* Start consumer threads. */
+ for (i = 0; i < nbr_threads; i++)
+ {
+ data_arr[i] = data;
+ data_arr[i].thread_id = i;
+ ret = pthread_create(&thread_arr[i], NULL,
+ test_sync_multi_consumer_producer_thread,
+ (void *) &(data_arr[i]));
+ igt_assert_eq(ret, 0);
+ }
+
+ /* Wait for threads to complete. */
+ for (i = 0; i < nbr_threads; i++)
+ {
+ uintptr_t local_thread_ret;
+ pthread_join(thread_arr[i], (void **)&local_thread_ret);
+ thread_ret |= local_thread_ret;
+ }
+
+ close(timeline);
+
+ igt_assert_f(counter == nbr_threads * nbr_iterations,
+ "Counter has unexpected value.\n");
+
+ igt_assert_f(thread_ret == 0, "A sync thread reported failure.\n");
+}
+
igt_main
{
igt_subtest("alloc_timeline")
@@ -329,5 +409,8 @@ igt_main

igt_subtest("sync_multi_consumer")
test_sync_multi_consumer();
+
+ igt_subtest("sync_multi_consumer_producer")
+ test_sync_multi_consumer_producer();