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

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

Working towards allowing different thread frameworks to be picked from the command line

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