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