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

ADT ast-experimental pthread-emulation
Last change on this file since 80d16f8 was 72b1800, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Some previous in progress work.
Commited only so it stops showing in my git status.

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