Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftest: sync: stress consumer/producer test

This test is based on the libsync test suite from Android.
This commit includes a stress test that replicates a
consumer/producer pattern.

Signed-off-by: Emilio López <emilio.lopez@collabora.co.uk>
Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>

authored by

Emilio López and committed by
Shuah Khan
c52dee50 54b519f3

+190
+1
tools/testing/selftests/sync/Makefile
··· 15 15 TESTS += sync_merge.o 16 16 TESTS += sync_wait.o 17 17 TESTS += sync_stress_parallelism.o 18 + TESTS += sync_stress_consumer.o 18 19 19 20 sync_test: $(OBJS) $(TESTS) 20 21
+185
tools/testing/selftests/sync/sync_stress_consumer.c
··· 1 + /* 2 + * sync stress test: producer/consumer 3 + * Copyright 2015-2016 Collabora Ltd. 4 + * 5 + * Based on the implementation from the Android Open Source Project, 6 + * 7 + * Copyright 2012 Google, Inc 8 + * 9 + * Permission is hereby granted, free of charge, to any person obtaining a 10 + * copy of this software and associated documentation files (the "Software"), 11 + * to deal in the Software without restriction, including without limitation 12 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 + * and/or sell copies of the Software, and to permit persons to whom the 14 + * Software is furnished to do so, subject to the following conditions: 15 + * 16 + * The above copyright notice and this permission notice shall be included in 17 + * all copies or substantial portions of the Software. 18 + * 19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 + * OTHER DEALINGS IN THE SOFTWARE. 26 + */ 27 + 28 + #include <pthread.h> 29 + 30 + #include "sync.h" 31 + #include "sw_sync.h" 32 + #include "synctest.h" 33 + 34 + /* IMPORTANT NOTE: if you see this test failing on your system, it may be 35 + * due to a shortage of file descriptors. Please ensure your system has 36 + * a sensible limit for this test to finish correctly. 37 + */ 38 + 39 + /* Returns 1 on error, 0 on success */ 40 + static int busy_wait_on_fence(int fence) 41 + { 42 + int error, active; 43 + 44 + do { 45 + error = sync_fence_count_with_status(fence, FENCE_STATUS_ERROR); 46 + ASSERT(error == 0, "Error occurred on fence\n"); 47 + active = sync_fence_count_with_status(fence, 48 + FENCE_STATUS_ACTIVE); 49 + } while (active); 50 + 51 + return 0; 52 + } 53 + 54 + static struct { 55 + int iterations; 56 + int threads; 57 + int counter; 58 + int consumer_timeline; 59 + int *producer_timelines; 60 + pthread_mutex_t lock; 61 + } test_data_mpsc; 62 + 63 + static int mpsc_producer_thread(void *d) 64 + { 65 + int id = (long)d; 66 + int fence, valid, i; 67 + int *producer_timelines = test_data_mpsc.producer_timelines; 68 + int consumer_timeline = test_data_mpsc.consumer_timeline; 69 + int iterations = test_data_mpsc.iterations; 70 + 71 + for (i = 0; i < iterations; i++) { 72 + fence = sw_sync_fence_create(consumer_timeline, "fence", i); 73 + valid = sw_sync_fence_is_valid(fence); 74 + ASSERT(valid, "Failure creating fence\n"); 75 + 76 + /* 77 + * Wait for the consumer to finish. Use alternate 78 + * means of waiting on the fence 79 + */ 80 + 81 + if ((iterations + id) % 8 != 0) { 82 + ASSERT(sync_wait(fence, -1) > 0, 83 + "Failure waiting on fence\n"); 84 + } else { 85 + ASSERT(busy_wait_on_fence(fence) == 0, 86 + "Failure waiting on fence\n"); 87 + } 88 + 89 + /* 90 + * Every producer increments the counter, the consumer 91 + * checks and erases it 92 + */ 93 + pthread_mutex_lock(&test_data_mpsc.lock); 94 + test_data_mpsc.counter++; 95 + pthread_mutex_unlock(&test_data_mpsc.lock); 96 + 97 + ASSERT(sw_sync_timeline_inc(producer_timelines[id], 1) == 0, 98 + "Error advancing producer timeline\n"); 99 + 100 + sw_sync_fence_destroy(fence); 101 + } 102 + 103 + return 0; 104 + } 105 + 106 + static int mpcs_consumer_thread(void) 107 + { 108 + int fence, merged, tmp, valid, it, i; 109 + int *producer_timelines = test_data_mpsc.producer_timelines; 110 + int consumer_timeline = test_data_mpsc.consumer_timeline; 111 + int iterations = test_data_mpsc.iterations; 112 + int n = test_data_mpsc.threads; 113 + 114 + for (it = 1; it <= iterations; it++) { 115 + fence = sw_sync_fence_create(producer_timelines[0], "name", it); 116 + for (i = 1; i < n; i++) { 117 + tmp = sw_sync_fence_create(producer_timelines[i], 118 + "name", it); 119 + merged = sync_merge("name", tmp, fence); 120 + sw_sync_fence_destroy(tmp); 121 + sw_sync_fence_destroy(fence); 122 + fence = merged; 123 + } 124 + 125 + valid = sw_sync_fence_is_valid(fence); 126 + ASSERT(valid, "Failure merging fences\n"); 127 + 128 + /* 129 + * Make sure we see an increment from every producer thread. 130 + * Vary the means by which we wait. 131 + */ 132 + if (iterations % 8 != 0) { 133 + ASSERT(sync_wait(fence, -1) > 0, 134 + "Producers did not increment as expected\n"); 135 + } else { 136 + ASSERT(busy_wait_on_fence(fence) == 0, 137 + "Producers did not increment as expected\n"); 138 + } 139 + 140 + ASSERT(test_data_mpsc.counter == n * it, 141 + "Counter value mismatch!\n"); 142 + 143 + /* Release the producer threads */ 144 + ASSERT(sw_sync_timeline_inc(consumer_timeline, 1) == 0, 145 + "Failure releasing producer threads\n"); 146 + 147 + sw_sync_fence_destroy(fence); 148 + } 149 + 150 + return 0; 151 + } 152 + 153 + int test_consumer_stress_multi_producer_single_consumer(void) 154 + { 155 + int iterations = 1 << 12; 156 + int n = 5; 157 + long i, ret; 158 + int producer_timelines[n]; 159 + int consumer_timeline; 160 + pthread_t threads[n]; 161 + 162 + consumer_timeline = sw_sync_timeline_create(); 163 + for (i = 0; i < n; i++) 164 + producer_timelines[i] = sw_sync_timeline_create(); 165 + 166 + test_data_mpsc.producer_timelines = producer_timelines; 167 + test_data_mpsc.consumer_timeline = consumer_timeline; 168 + test_data_mpsc.iterations = iterations; 169 + test_data_mpsc.threads = n; 170 + test_data_mpsc.counter = 0; 171 + pthread_mutex_init(&test_data_mpsc.lock, NULL); 172 + 173 + for (i = 0; i < n; i++) { 174 + pthread_create(&threads[i], NULL, (void * (*)(void *)) 175 + mpsc_producer_thread, (void *)i); 176 + } 177 + 178 + /* Consumer thread runs here */ 179 + ret = mpcs_consumer_thread(); 180 + 181 + for (i = 0; i < n; i++) 182 + pthread_join(threads[i], NULL); 183 + 184 + return ret; 185 + }
+1
tools/testing/selftests/sync/sync_test.c
··· 67 67 err += RUN_TEST(test_fence_merge_same_fence); 68 68 err += RUN_TEST(test_fence_multi_timeline_wait); 69 69 err += RUN_TEST(test_stress_two_threads_shared_timeline); 70 + err += RUN_TEST(test_consumer_stress_multi_producer_single_consumer); 70 71 71 72 if (err) 72 73 printf("[FAIL]\tsync errors: %d\n", err);
+3
tools/testing/selftests/sync/synctest.h
··· 57 57 /* Stress test - parallelism */ 58 58 int test_stress_two_threads_shared_timeline(void); 59 59 60 + /* Stress test - consumer */ 61 + int test_consumer_stress_multi_producer_single_consumer(void); 62 + 60 63 #endif