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

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 6750bcd was 6750bcd, checked in by Thierry Delisle <tdelisle@…>, 5 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.