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

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast-unique-expr pthread-emulation qualifiedEnum stuck-waitfor-destruct
Last change on this file since d035cf7 was d035cf7, checked in by Thierry Delisle <tdelisle@…>, 5 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.