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