source: doc/theses/thierry_delisle_PhD/code/readQ_example/proto-gui/main.cpp @ d035cf7

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since d035cf7 was d035cf7, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Added first attempt at libfibre implementation

  • Property mode set to 100644
File size: 6.8 KB
Line 
1#include "thrdlib/thread.h"
2
3#include <cassert>
4
5#include <algorithm>
6#include <atomic>
7#include <iostream>
8#include <memory>
9#include <vector>
10
11#include <getopt.h>
12
13//--------------------
14// Constants
15unsigned nframes;
16unsigned fsize;
17unsigned nproduce;
18
19//--------------------
20// Frame management
21
22class Frame {
23        static const thread_t reset;
24        static const thread_t set;
25        std::atomic<thread_t> rdy_state = { reset };
26        std::atomic<thread_t> rnd_state = { set };
27public:
28        unsigned number;
29        std::unique_ptr<unsigned char[]> data;
30
31private:
32        inline bool wait( thread_t self, std::atomic<thread_t> & state, std::atomic<thread_t> & other ) {
33                bool ret;
34                while(true) {
35                        thread_t expected = state;
36                        if( expected == set ) { ret = false; goto END; }
37                        assert( expected == reset );
38                        if( std::atomic_compare_exchange_strong( &state, &expected, self) ) {
39                                thrdlib_park( self );
40                                ret = true;
41                                goto END;
42                        }
43                }
44                END:
45                assert( state == set );
46                assert( other != set );
47                state = reset;
48                return ret;
49        }
50
51        inline bool publish(  std::atomic<thread_t> & state ) {
52                thread_t got = std::atomic_exchange( &state, set );
53                assert( got != set );
54
55                if( got == reset ) return false;
56
57                thrdlib_unpark( got );
58                return true;
59        }
60
61public:
62        inline bool wait_rendered( thread_t self ) {
63                return wait( self, rnd_state, rdy_state );
64        }
65
66        inline bool wait_ready   ( thread_t self ) {
67                return wait( self, rdy_state, rnd_state );
68        }
69
70        inline bool publish() {
71                return publish( rdy_state );
72        }
73
74        inline bool release() {
75                return publish( rnd_state );
76        }
77};
78
79const thread_t Frame::reset = nullptr;
80const thread_t Frame::set   = reinterpret_cast<thread_t>(1);
81
82std::unique_ptr<Frame[]> frames;
83volatile unsigned last_produced = 0;
84
85//--------------------
86// Threads
87thread_t volatile the_stats_thread = nullptr;
88
89inline void fence(void) {
90        std::atomic_thread_fence(std::memory_order_seq_cst);
91}
92
93struct {
94        struct {
95                volatile unsigned long long   parks = 0;
96                volatile unsigned long long unparks = 0;
97        } sim;
98        struct {
99                volatile unsigned long long   parks = 0;
100                volatile unsigned long long unparks = 0;
101        } rend;
102
103        struct {
104                volatile unsigned long long ran = 0;
105                volatile unsigned long long saw = 0;
106        } stats;
107} thrd_stats;
108
109void Stats( thread_t self ) {
110        the_stats_thread = self;
111        fence();
112        thrdlib_park( self );
113
114        std::vector<bool> seen;
115        seen.resize(nproduce, false);
116
117        while(last_produced < nproduce) {
118                thrdlib_yield();
119                thrd_stats.stats.ran++;
120                if( last_produced > 0 ) seen.at(last_produced - 1) = true;
121        }
122
123        thrd_stats.stats.saw = std::count(seen.begin(), seen.end(), true);
124}
125
126void Simulator( thread_t self ) {
127        for(unsigned i = 0; i < nproduce; i++) {
128                auto & frame = frames[i % nframes];
129                // Wait for the frames to be rendered
130                if( frame.wait_rendered( self ) ) {
131                        thrd_stats.sim.parks++;
132                }
133
134                // Write the frame information
135                frame.number = i;
136                for( unsigned x = 0; x < fsize; x++ ) {
137                        frame.data[x] = i;
138                }
139                std::cout << "Simulated " << i << std::endl;
140                last_produced = i+1;
141
142                // Publish it
143                if( frame.publish()  ) {
144                        thrd_stats.sim.unparks++;
145                }
146        }
147}
148
149void Renderer( thread_t self ) {
150        thrdlib_unpark( the_stats_thread );
151        for(unsigned i = 0; i < nproduce; i++) {
152                auto & frame = frames[i % nframes];
153                // Wait for the frames to be ready
154                if( frame.wait_ready( self ) ) {
155                        thrd_stats.rend.parks++;
156                }
157
158                // Render the frame
159                unsigned total = 0;
160                for( unsigned x = 0; x < fsize; x++ ) {
161                        total += frame.data[x];
162                }
163
164                std::cout << "Rendered " << i << std::endl;
165                assert(total == i * fsize);
166
167                // Release
168                if( frame.release() ) {
169                        thrd_stats.rend.unparks++;
170                }
171        }
172
173}
174
175
176
177int main(int argc, char * argv[]) {
178        nframes  = 3;
179        fsize    = 1000;
180        nproduce = 60;
181
182        for(;;) {
183                static struct option options[] = {
184                        {"buff",  required_argument, 0, 'b'},
185                        {"nprod",  required_argument, 0, 'p'},
186                        {"fsize",   required_argument, 0, 'f'},
187                        {0, 0, 0, 0}
188                };
189
190                int idx = 0;
191                int opt = getopt_long(argc, argv, "b:p:f:", options, &idx);
192
193                std::string arg = optarg ? optarg : "";
194                size_t len = 0;
195                switch(opt) {
196                        // Exit Case
197                        case -1:
198                                /* paranoid */ assert(optind <= argc);
199                                goto run;
200                        case 'b':
201                                try {
202                                        nframes = std::stoul(optarg, &len);
203                                        if(nframes == 0 || len != arg.size()) { throw std::invalid_argument(""); }
204                                } catch(std::invalid_argument &) {
205                                        std::cerr << "Number of buffered frames must be at least 1, was" << arg << std::endl;
206                                        goto usage;
207                                }
208                                break;
209                        case 'p':
210                                try {
211                                        nproduce = std::stoul(optarg, &len);
212                                        if(nproduce == 0 || len != arg.size()) { throw std::invalid_argument(""); }
213                                } catch(std::invalid_argument &) {
214                                        std::cerr << "Number of produced frames must be at least 1, was" << arg << std::endl;
215                                        goto usage;
216                                }
217                                break;
218                        case 'f':
219                                try {
220                                        fsize = std::stoul(optarg, &len);
221                                        if(fsize == 0 || len != arg.size()) { throw std::invalid_argument(""); }
222                                } catch(std::invalid_argument &) {
223                                        std::cerr << "Size of produced frames must be at least 1, was" << arg << std::endl;
224                                        goto usage;
225                                }
226                                break;
227                        // Other cases
228                        default: /* ? */
229                                std::cerr << opt << std::endl;
230                        usage:
231                                std::cerr << "Usage: " << argv[0] << " [options]" << std::endl;
232                                std::cerr << std::endl;
233                                std::cerr << "  -b, --buff=COUNT    Number of frames to buffer" << std::endl;
234                                std::cerr << "  -p, --nprod=COUNT   Number of frames to produce" << std::endl;
235                                std::cerr << "  -f, --fsize=SIZE    Size of each frame in bytes" << std::endl;
236                                std::exit(1);
237                }
238        }
239        run:
240
241        frames.reset(new Frame[nframes]);
242        for(unsigned i = 0; i < nframes; i++) {
243                frames[i].number = 0;
244                frames[i].data.reset(new unsigned char[fsize]);
245        }
246        std::cout << "Created frames of " << fsize << " bytes" << std::endl;
247        std::cout << "(Buffering " << nframes << ")" << std::endl;
248
249        thrdlib_init( 2 );
250
251        thread_t stats     = thrdlib_create( Stats     );
252        std::cout << "Created Stats Thread" << std::endl;
253        while( the_stats_thread == nullptr ) thrdlib_yield();
254        std::cout << "Creating Main Threads" << std::endl;
255        thread_t renderer  = thrdlib_create( Renderer  );
256        // while(true);
257        thread_t simulator = thrdlib_create( Simulator );
258
259        std::cout << "Running" << std::endl;
260
261        thrdlib_join( simulator );
262        thrdlib_join( renderer  );
263        thrdlib_join( stats     );
264
265        thrdlib_clean();
266
267        std::cout << "----------" << std::endl;
268        std::cout << "# Parks" << std::endl;
269        std::cout << "  Renderer   park: " << thrd_stats. sim.  parks << std::endl;
270        std::cout << "  Renderer unpark: " << thrd_stats. sim.unparks << std::endl;
271        std::cout << " Simulator   park: " << thrd_stats.rend.  parks << std::endl;
272        std::cout << " Simulator unpark: " << thrd_stats.rend.unparks << std::endl;
273
274        std::cout << "Stats thread" << std::endl;
275        std::cout << " Ran             : " << thrd_stats.stats.ran << " times" << std::endl;
276        std::cout << " Saw             : " << thrd_stats.stats.saw << " (" << ((100.f * thrd_stats.stats.saw) / nproduce) << "%)" << std::endl;
277}
Note: See TracBrowser for help on using the repository browser.