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

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