Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  sync stress test: producer/consumer
0003  *  Copyright 2015-2016 Collabora Ltd.
0004  *
0005  *  Based on the implementation from the Android Open Source Project,
0006  *
0007  *  Copyright 2012 Google, Inc
0008  *
0009  *  Permission is hereby granted, free of charge, to any person obtaining a
0010  *  copy of this software and associated documentation files (the "Software"),
0011  *  to deal in the Software without restriction, including without limitation
0012  *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
0013  *  and/or sell copies of the Software, and to permit persons to whom the
0014  *  Software is furnished to do so, subject to the following conditions:
0015  *
0016  *  The above copyright notice and this permission notice shall be included in
0017  *  all copies or substantial portions of the Software.
0018  *
0019  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0020  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0021  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
0022  *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
0023  *  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0024  *  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0025  *  OTHER DEALINGS IN THE SOFTWARE.
0026  */
0027 
0028 #include <pthread.h>
0029 
0030 #include "sync.h"
0031 #include "sw_sync.h"
0032 #include "synctest.h"
0033 
0034 /* IMPORTANT NOTE: if you see this test failing on your system, it may be
0035  * due to a shortage of file descriptors. Please ensure your system has
0036  * a sensible limit for this test to finish correctly.
0037  */
0038 
0039 /* Returns 1 on error, 0 on success */
0040 static int busy_wait_on_fence(int fence)
0041 {
0042     int error, active;
0043 
0044     do {
0045         error = sync_fence_count_with_status(fence, FENCE_STATUS_ERROR);
0046         ASSERT(error == 0, "Error occurred on fence\n");
0047         active = sync_fence_count_with_status(fence,
0048                               FENCE_STATUS_ACTIVE);
0049     } while (active);
0050 
0051     return 0;
0052 }
0053 
0054 static struct {
0055     int iterations;
0056     int threads;
0057     int counter;
0058     int consumer_timeline;
0059     int *producer_timelines;
0060     pthread_mutex_t lock;
0061 } test_data_mpsc;
0062 
0063 static int mpsc_producer_thread(void *d)
0064 {
0065     int id = (long)d;
0066     int fence, valid, i;
0067     int *producer_timelines = test_data_mpsc.producer_timelines;
0068     int consumer_timeline = test_data_mpsc.consumer_timeline;
0069     int iterations = test_data_mpsc.iterations;
0070 
0071     for (i = 0; i < iterations; i++) {
0072         fence = sw_sync_fence_create(consumer_timeline, "fence", i);
0073         valid = sw_sync_fence_is_valid(fence);
0074         ASSERT(valid, "Failure creating fence\n");
0075 
0076         /*
0077          * Wait for the consumer to finish. Use alternate
0078          * means of waiting on the fence
0079          */
0080 
0081         if ((iterations + id) % 8 != 0) {
0082             ASSERT(sync_wait(fence, -1) > 0,
0083                    "Failure waiting on fence\n");
0084         } else {
0085             ASSERT(busy_wait_on_fence(fence) == 0,
0086                    "Failure waiting on fence\n");
0087         }
0088 
0089         /*
0090          * Every producer increments the counter, the consumer
0091          * checks and erases it
0092          */
0093         pthread_mutex_lock(&test_data_mpsc.lock);
0094         test_data_mpsc.counter++;
0095         pthread_mutex_unlock(&test_data_mpsc.lock);
0096 
0097         ASSERT(sw_sync_timeline_inc(producer_timelines[id], 1) == 0,
0098                "Error advancing producer timeline\n");
0099 
0100         sw_sync_fence_destroy(fence);
0101     }
0102 
0103     return 0;
0104 }
0105 
0106 static int mpcs_consumer_thread(void)
0107 {
0108     int fence, merged, tmp, valid, it, i;
0109     int *producer_timelines = test_data_mpsc.producer_timelines;
0110     int consumer_timeline = test_data_mpsc.consumer_timeline;
0111     int iterations = test_data_mpsc.iterations;
0112     int n = test_data_mpsc.threads;
0113 
0114     for (it = 1; it <= iterations; it++) {
0115         fence = sw_sync_fence_create(producer_timelines[0], "name", it);
0116         for (i = 1; i < n; i++) {
0117             tmp = sw_sync_fence_create(producer_timelines[i],
0118                            "name", it);
0119             merged = sync_merge("name", tmp, fence);
0120             sw_sync_fence_destroy(tmp);
0121             sw_sync_fence_destroy(fence);
0122             fence = merged;
0123         }
0124 
0125         valid = sw_sync_fence_is_valid(fence);
0126         ASSERT(valid, "Failure merging fences\n");
0127 
0128         /*
0129          * Make sure we see an increment from every producer thread.
0130          * Vary the means by which we wait.
0131          */
0132         if (iterations % 8 != 0) {
0133             ASSERT(sync_wait(fence, -1) > 0,
0134                    "Producers did not increment as expected\n");
0135         } else {
0136             ASSERT(busy_wait_on_fence(fence) == 0,
0137                    "Producers did not increment as expected\n");
0138         }
0139 
0140         ASSERT(test_data_mpsc.counter == n * it,
0141                "Counter value mismatch!\n");
0142 
0143         /* Release the producer threads */
0144         ASSERT(sw_sync_timeline_inc(consumer_timeline, 1) == 0,
0145                "Failure releasing producer threads\n");
0146 
0147         sw_sync_fence_destroy(fence);
0148     }
0149 
0150     return 0;
0151 }
0152 
0153 int test_consumer_stress_multi_producer_single_consumer(void)
0154 {
0155     int iterations = 1 << 12;
0156     int n = 5;
0157     long i, ret;
0158     int producer_timelines[n];
0159     int consumer_timeline;
0160     pthread_t threads[n];
0161 
0162     consumer_timeline = sw_sync_timeline_create();
0163     for (i = 0; i < n; i++)
0164         producer_timelines[i] = sw_sync_timeline_create();
0165 
0166     test_data_mpsc.producer_timelines = producer_timelines;
0167     test_data_mpsc.consumer_timeline = consumer_timeline;
0168     test_data_mpsc.iterations = iterations;
0169     test_data_mpsc.threads = n;
0170     test_data_mpsc.counter = 0;
0171     pthread_mutex_init(&test_data_mpsc.lock, NULL);
0172 
0173     for (i = 0; i < n; i++) {
0174         pthread_create(&threads[i], NULL, (void * (*)(void *))
0175                    mpsc_producer_thread, (void *)i);
0176     }
0177 
0178     /* Consumer thread runs here */
0179     ret = mpcs_consumer_thread();
0180 
0181     for (i = 0; i < n; i++)
0182         pthread_join(threads[i], NULL);
0183 
0184     return ret;
0185 }