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

arm-ehjacob/cs343-translationnew-ast-unique-expr
Last change on this file since 4e39f51 was 4e39f51, checked in by Thierry Delisle <tdelisle@…>, 14 months ago

More work towards dynamically picking a framework, however initial-exec tls is not working correctly

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