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

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

proto-gui now supports passing settings as std arguments

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