source: doc/theses/thierry_delisle_PhD/code/relaxed_list.cpp@ 95cb63b

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 95cb63b was 95cb63b, checked in by Thierry Delisle <tdelisle@…>, 6 years ago

Added benchmark called producer, which mimicks I/O scheduling

  • Property mode set to 100644
File size: 26.2 KB
Line 
1#include "relaxed_list.hpp"
2
3#include <array>
4#include <iomanip>
5#include <iostream>
6#include <locale>
7#include <string>
8#include <thread>
9#include <vector>
10
11#include <getopt.h>
12#include <unistd.h>
13#include <sys/sysinfo.h>
14
15#include "utils.hpp"
16
17struct __attribute__((aligned(64))) Node {
18 static std::atomic_size_t creates;
19 static std::atomic_size_t destroys;
20
21 _LinksFields_t<Node> _links;
22
23 int value;
24 int id;
25
26 Node() { creates++; }
27 Node(int value): value(value) { creates++; }
28 ~Node() { destroys++; }
29};
30
31std::atomic_size_t Node::creates = { 0 };
32std::atomic_size_t Node::destroys = { 0 };
33
34bool enable_stats = false;
35
36template<>
37thread_local relaxed_list<Node>::TLS relaxed_list<Node>::tls = {};
38
39template<>
40relaxed_list<Node> * relaxed_list<Node>::head = nullptr;
41
42#ifndef NO_STATS
43template<>
44relaxed_list<Node>::GlobalStats relaxed_list<Node>::global_stats = {};
45#endif
46
47// ================================================================================================
48// UTILS
49// ================================================================================================
50
51struct local_stat_t {
52 size_t in = 0;
53 size_t out = 0;
54 size_t empty = 0;
55 size_t crc_in = 0;
56 size_t crc_out = 0;
57 size_t valmax = 0;
58 size_t valmin = 100000000ul;
59 struct {
60 size_t val = 0;
61 size_t cnt = 0;
62 } comp;
63 struct {
64 size_t val = 0;
65 size_t cnt = 0;
66 } subm;
67};
68
69struct global_stat_t {
70 std::atomic_size_t in = { 0 };
71 std::atomic_size_t out = { 0 };
72 std::atomic_size_t empty = { 0 };
73 std::atomic_size_t crc_in = { 0 };
74 std::atomic_size_t crc_out = { 0 };
75 std::atomic_size_t valmax = { 0 };
76 std::atomic_size_t valmin = { 100000000ul };
77 struct {
78 std::atomic_size_t val = { 0 };
79 std::atomic_size_t cnt = { 0 };
80 } comp;
81 struct {
82 std::atomic_size_t val = { 0 };
83 std::atomic_size_t cnt = { 0 };
84 } subm;
85};
86
87void atomic_max(std::atomic_size_t & target, size_t value) {
88 for(;;) {
89 size_t expect = target.load(std::memory_order_relaxed);
90 if(value <= expect) return;
91 bool success = target.compare_exchange_strong(expect, value);
92 if(success) return;
93 }
94}
95
96void atomic_min(std::atomic_size_t & target, size_t value) {
97 for(;;) {
98 size_t expect = target.load(std::memory_order_relaxed);
99 if(value >= expect) return;
100 bool success = target.compare_exchange_strong(expect, value);
101 if(success) return;
102 }
103}
104
105void tally_stats(global_stat_t & global, local_stat_t & local) {
106
107 global.in += local.in;
108 global.out += local.out;
109 global.empty += local.empty;
110
111 global.crc_in += local.crc_in;
112 global.crc_out += local.crc_out;
113
114 global.comp.val += local.comp.val;
115 global.comp.cnt += local.comp.cnt;
116 global.subm.val += local.subm.val;
117 global.subm.cnt += local.subm.cnt;
118
119 atomic_max(global.valmax, local.valmax);
120 atomic_min(global.valmin, local.valmin);
121
122 relaxed_list<Node>::stats_tls_tally();
123}
124
125void waitfor(double & duration, barrier_t & barrier, std::atomic_bool & done) {
126 std::cout << "Starting" << std::endl;
127 auto before = Clock::now();
128 barrier.wait(0);
129
130 while(true) {
131 usleep(100000);
132 auto now = Clock::now();
133 duration_t durr = now - before;
134 if( durr.count() > duration ) {
135 done = true;
136 break;
137 }
138 std::cout << "\r" << std::setprecision(4) << durr.count();
139 std::cout.flush();
140 }
141
142 barrier.wait(0);
143 auto after = Clock::now();
144 duration_t durr = after - before;
145 duration = durr.count();
146 std::cout << "\rClosing down" << std::endl;
147}
148
149void waitfor(double & duration, barrier_t & barrier, const std::atomic_size_t & count) {
150 std::cout << "Starting" << std::endl;
151 auto before = Clock::now();
152 barrier.wait(0);
153
154 while(true) {
155 usleep(100000);
156 size_t c = count.load();
157 if( c == 0 ) {
158 break;
159 }
160 std::cout << "\r" << c;
161 std::cout.flush();
162 }
163
164 barrier.wait(0);
165 auto after = Clock::now();
166 duration_t durr = after - before;
167 duration = durr.count();
168 std::cout << "\rClosing down" << std::endl;
169}
170
171void print_stats(double duration, unsigned nthread, global_stat_t & global) {
172 assert(Node::creates == Node::destroys);
173 assert(global.crc_in == global.crc_out);
174
175 std::cout << "Done" << std::endl;
176
177 size_t ops = global.in + global.out;
178 size_t ops_sec = size_t(double(ops) / duration);
179 size_t ops_thread = ops_sec / nthread;
180 auto dur_nano = duration_cast<std::nano>(1.0);
181
182 if(global.valmax != 0) {
183 std::cout << "Max runs : " << global.valmax << "\n";
184 std::cout << "Min runs : " << global.valmin << "\n";
185 }
186 if(global.comp.cnt != 0) {
187 std::cout << "Submit count : " << global.subm.cnt << "\n";
188 std::cout << "Submit average: " << ((double(global.subm.val)) / global.subm.cnt) << "\n";
189 std::cout << "Complete count: " << global.comp.cnt << "\n";
190 std::cout << "Complete avg : " << ((double(global.comp.val)) / global.comp.cnt) << "\n";
191 }
192 std::cout << "Duration : " << duration << "s\n";
193 std::cout << "ns/Op : " << ( dur_nano / ops_thread )<< "\n";
194 std::cout << "Ops/sec/thread: " << ops_thread << "\n";
195 std::cout << "Ops/sec : " << ops_sec << "\n";
196 std::cout << "Total ops : " << ops << "(" << global.in << "i, " << global.out << "o, " << global.empty << "e)\n";
197 #ifndef NO_STATS
198 relaxed_list<Node>::stats_print(std::cout);
199 #endif
200}
201
202void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output);
203
204// ================================================================================================
205// EXPERIMENTS
206// ================================================================================================
207
208// ================================================================================================
209__attribute__((noinline)) void runChurn_body(
210 std::atomic<bool>& done,
211 Random & rand,
212 Node * my_nodes[],
213 unsigned nslots,
214 local_stat_t & local,
215 relaxed_list<Node> & list
216) {
217 while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
218 int idx = rand.next() % nslots;
219 if (auto node = my_nodes[idx]) {
220 local.crc_in += node->value;
221 list.push(node);
222 my_nodes[idx] = nullptr;
223 local.in++;
224 }
225 else if(auto node = list.pop()) {
226 local.crc_out += node->value;
227 my_nodes[idx] = node;
228 local.out++;
229 }
230 else {
231 local.empty++;
232 }
233 }
234}
235
236void runChurn(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes, const unsigned nslots) {
237 std::cout << "Churn Benchmark" << std::endl;
238 assert(nnodes <= nslots);
239 // List being tested
240
241 // Barrier for synchronization
242 barrier_t barrier(nthread + 1);
243
244 // Data to check everything is OK
245 global_stat_t global;
246
247 // Flag to signal termination
248 std::atomic_bool done = { false };
249
250 // Prep nodes
251 std::cout << "Initializing ";
252 size_t npushed = 0;
253 relaxed_list<Node> list = { nthread * nqueues };
254 {
255 Node** all_nodes[nthread];
256 for(auto & nodes : all_nodes) {
257 nodes = new __attribute__((aligned(64))) Node*[nslots + 8];
258 Random rand(rdtscl());
259 for(unsigned i = 0; i < nnodes; i++) {
260 nodes[i] = new Node(rand.next() % 100);
261 }
262
263 for(unsigned i = nnodes; i < nslots; i++) {
264 nodes[i] = nullptr;
265 }
266
267 for(int i = 0; i < 10 && i < (int)nslots; i++) {
268 int idx = rand.next() % nslots;
269 if (auto node = nodes[idx]) {
270 global.crc_in += node->value;
271 list.push(node);
272 npushed++;
273 nodes[idx] = nullptr;
274 }
275 }
276 }
277
278 std::cout << nnodes << " nodes (" << nslots << " slots)" << std::endl;
279
280 enable_stats = true;
281
282 std::thread * threads[nthread];
283 unsigned i = 1;
284 for(auto & t : threads) {
285 auto & my_nodes = all_nodes[i - 1];
286 t = new std::thread([&done, &list, &barrier, &global, &my_nodes, nslots](unsigned tid) {
287 Random rand(tid + rdtscl());
288
289 local_stat_t local;
290
291 // affinity(tid);
292
293 barrier.wait(tid);
294
295 // EXPERIMENT START
296
297 runChurn_body(done, rand, my_nodes, nslots, local, list);
298
299 // EXPERIMENT END
300
301 barrier.wait(tid);
302
303 tally_stats(global, local);
304
305 for(unsigned i = 0; i < nslots; i++) {
306 delete my_nodes[i];
307 }
308 }, i++);
309 }
310
311 waitfor(duration, barrier, done);
312
313 for(auto t : threads) {
314 t->join();
315 delete t;
316 }
317
318 enable_stats = false;
319
320 while(auto node = list.pop()) {
321 global.crc_out += node->value;
322 delete node;
323 }
324
325 for(auto nodes : all_nodes) {
326 delete[] nodes;
327 }
328 }
329
330 print_stats(duration, nthread, global);
331}
332
333// ================================================================================================
334__attribute__((noinline)) void runPingPong_body(
335 std::atomic<bool>& done,
336 Node initial_nodes[],
337 unsigned nnodes,
338 local_stat_t & local,
339 relaxed_list<Node> & list
340) {
341 Node * nodes[nnodes];
342 {
343 unsigned i = 0;
344 for(auto & n : nodes) {
345 n = &initial_nodes[i++];
346 }
347 }
348
349 while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
350
351 for(Node * & node : nodes) {
352 local.crc_in += node->value;
353 list.push(node);
354 local.in++;
355 }
356
357 // -----
358
359 for(Node * & node : nodes) {
360 node = list.pop();
361 assert(node);
362 local.crc_out += node->value;
363 local.out++;
364 }
365 }
366}
367
368void runPingPong(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes) {
369 std::cout << "PingPong Benchmark" << std::endl;
370
371
372 // Barrier for synchronization
373 barrier_t barrier(nthread + 1);
374
375 // Data to check everything is OK
376 global_stat_t global;
377
378 // Flag to signal termination
379 std::atomic_bool done = { false };
380
381 std::cout << "Initializing ";
382 // List being tested
383 relaxed_list<Node> list = { nthread * nqueues };
384 {
385 enable_stats = true;
386
387 std::thread * threads[nthread];
388 unsigned i = 1;
389 for(auto & t : threads) {
390 t = new std::thread([&done, &list, &barrier, &global, nnodes](unsigned tid) {
391 Random rand(tid + rdtscl());
392
393 Node nodes[nnodes];
394 for(auto & n : nodes) {
395 n.value = (int)rand.next() % 100;
396 }
397
398 local_stat_t local;
399
400 // affinity(tid);
401
402 barrier.wait(tid);
403
404 // EXPERIMENT START
405
406 runPingPong_body(done, nodes, nnodes, local, list);
407
408 // EXPERIMENT END
409
410 barrier.wait(tid);
411
412 tally_stats(global, local);
413 }, i++);
414 }
415
416 waitfor(duration, barrier, done);
417
418 for(auto t : threads) {
419 t->join();
420 delete t;
421 }
422
423 enable_stats = false;
424 }
425
426 print_stats(duration, nthread, global);
427}
428
429// ================================================================================================
430struct __attribute__((aligned(64))) Slot {
431 Node * volatile node;
432};
433
434__attribute__((noinline)) void runProducer_body(
435 std::atomic<bool>& done,
436 Random & rand,
437 Slot * slots,
438 int nslots,
439 local_stat_t & local,
440 relaxed_list<Node> & list
441) {
442 while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
443
444 Node * node = list.pop();
445 if(!node) {
446 local.empty ++;
447 continue;
448 }
449
450 local.crc_out += node->value;
451 local.out++;
452
453 if(node->id == 0) {
454 unsigned cnt = 0;
455 for(int i = 0; i < nslots; i++) {
456 Node * found = __atomic_exchange_n( &slots[i].node, nullptr, __ATOMIC_SEQ_CST );
457 if( found ) {
458 local.crc_in += found->value;
459 local.in++;
460 cnt++;
461 list.push( found );
462 }
463 }
464
465 local.crc_in += node->value;
466 local.in++;
467 list.push( node );
468
469 local.comp.cnt++;
470 local.comp.val += cnt;
471 }
472 else {
473 unsigned len = 0;
474 while(true) {
475 auto off = rand.next();
476 for(int i = 0; i < nslots; i++) {
477 Node * expected = nullptr;
478 int idx = (i + off) % nslots;
479 Slot & slot = slots[ idx ];
480 if(
481 slot.node == nullptr &&
482 __atomic_compare_exchange_n( &slot.node, &expected, node, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST )
483 ) {
484 local.subm.cnt++;
485 local.subm.val += len;
486 goto LOOP;
487 }
488 assert( expected != node );
489 len++;
490 }
491 }
492 }
493
494 LOOP:;
495 }
496}
497
498void runProducer(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes) {
499 std::cout << "Producer Benchmark" << std::endl;
500
501 // Barrier for synchronization
502 barrier_t barrier(nthread + 1);
503
504 // Data to check everything is OK
505 global_stat_t global;
506
507 // Flag to signal termination
508 std::atomic_bool done = { false };
509
510 std::cout << "Initializing ";
511
512 int nslots = nnodes * 4;
513 Slot * slots = new Slot[nslots];
514 std::cout << nnodes << " nodes (" << nslots << " slots)" << std::endl;
515
516 // List being tested
517 relaxed_list<Node> list = { nthread * nqueues };
518 {
519 Random rand(rdtscl());
520 for(unsigned i = 0; i < nnodes; i++) {
521 Node * node = new Node(rand.next() % 100);
522 node->id = i;
523 global.crc_in += node->value;
524 list.push(node);
525 }
526
527 for(int i = 0; i < nslots; i++) {
528 slots[i].node = nullptr;
529 }
530 }
531
532 {
533 enable_stats = true;
534
535 std::thread * threads[nthread];
536 unsigned i = 1;
537 for(auto & t : threads) {
538 t = new std::thread([&done, &list, &barrier, &global, slots, nslots](unsigned tid) {
539 Random rand(tid + rdtscl());
540
541 local_stat_t local;
542 barrier.wait(tid);
543
544 // EXPERIMENT START
545
546 runProducer_body(done, rand, slots, nslots, local, list);
547
548 // EXPERIMENT END
549
550 barrier.wait(tid);
551
552 tally_stats(global, local);
553 }, i++);
554 }
555
556 waitfor(duration, barrier, done);
557
558 for(auto t : threads) {
559 t->join();
560 delete t;
561 }
562
563 enable_stats = false;
564 }
565
566 {
567 while(Node * node = list.pop()) {
568 global.crc_out += node->value;
569 delete node;
570 }
571
572 for(int i = 0; i < nslots; i++) {
573 delete slots[i].node;
574 }
575
576 delete [] slots;
577 }
578
579 print_stats(duration, nthread, global);
580}
581
582// ================================================================================================
583__attribute__((noinline)) void runFairness_body(
584 unsigned tid,
585 size_t width,
586 size_t length,
587 int output[],
588 std::atomic_size_t & count,
589 Node initial_nodes[],
590 unsigned nnodes,
591 local_stat_t & local,
592 relaxed_list<Node> & list
593) {
594 Node * nodes[nnodes];
595 {
596 unsigned i = 0;
597 for(auto & n : nodes) {
598 n = &initial_nodes[i++];
599 }
600 }
601
602 while(__builtin_expect(0 != count.load(std::memory_order_relaxed), true)) {
603
604 for(Node * & node : nodes) {
605 local.crc_in += node->id;
606 list.push(node);
607 local.in++;
608 }
609
610 // -----
611
612 for(Node * & node : nodes) {
613 node = list.pop();
614 assert(node);
615
616 if (unsigned(node->value) < length) {
617 size_t idx = (node->value * width) + node->id;
618 assert(idx < (width * length));
619 output[idx] = tid;
620 }
621
622 node->value++;
623 if(unsigned(node->value) == length) count--;
624
625 local.crc_out += node->id;
626 local.out++;
627 }
628 }
629}
630
631void runFairness(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes, const std::string & output) {
632 std::cout << "Fairness Benchmark, outputing to : " << output << std::endl;
633
634 // Barrier for synchronization
635 barrier_t barrier(nthread + 1);
636
637 // Data to check everything is OK
638 global_stat_t global;
639
640 std::cout << "Initializing ";
641
642 // Check fairness by creating a png of where the threads ran
643 size_t width = nthread * nnodes;
644 size_t length = 100000;
645
646 std::unique_ptr<int[]> data_out { new int[width * length] };
647
648 // Flag to signal termination
649 std::atomic_size_t count = width;
650
651 // List being tested
652 relaxed_list<Node> list = { nthread * nqueues };
653 {
654 enable_stats = true;
655
656 std::thread * threads[nthread];
657 unsigned i = 1;
658 for(auto & t : threads) {
659 t = new std::thread([&count, &list, &barrier, &global, nnodes, width, length, data_out = data_out.get()](unsigned tid) {
660 unsigned int start = (tid - 1) * nnodes;
661 Node nodes[nnodes];
662 for(auto & n : nodes) {
663 n.id = start;
664 n.value = 0;
665 start++;
666 }
667
668 local_stat_t local;
669
670 // affinity(tid);
671
672 barrier.wait(tid);
673
674 // EXPERIMENT START
675
676 runFairness_body(tid, width, length, data_out, count, nodes, nnodes, local, list);
677
678 // EXPERIMENT END
679
680 barrier.wait(tid);
681
682 for(const auto & n : nodes) {
683 local.valmax = max(local.valmax, size_t(n.value));
684 local.valmin = min(local.valmin, size_t(n.value));
685 }
686
687 tally_stats(global, local);
688 }, i++);
689 }
690
691 waitfor(duration, barrier, count);
692
693 for(auto t : threads) {
694 t->join();
695 delete t;
696 }
697
698 enable_stats = false;
699 }
700
701 print_stats(duration, nthread, global);
702
703 // save_fairness(data_out.get(), 100, nthread, width, length, output);
704}
705
706// ================================================================================================
707
708bool iequals(const std::string& a, const std::string& b)
709{
710 return std::equal(a.begin(), a.end(),
711 b.begin(), b.end(),
712 [](char a, char b) {
713 return std::tolower(a) == std::tolower(b);
714 });
715}
716
717int main(int argc, char * argv[]) {
718
719 double duration = 5.0;
720 unsigned nthreads = 2;
721 unsigned nqueues = 4;
722 unsigned nnodes = 100;
723 unsigned nslots = 100;
724 std::string out = "fairness.png";
725
726 enum {
727 Churn,
728 PingPong,
729 Producer,
730 Fairness,
731 NONE
732 } benchmark = NONE;
733
734 std::cout.imbue(std::locale(""));
735
736 for(;;) {
737 static struct option options[] = {
738 {"duration", required_argument, 0, 'd'},
739 {"nthreads", required_argument, 0, 't'},
740 {"nqueues", required_argument, 0, 'q'},
741 {"benchmark", required_argument, 0, 'b'},
742 {0, 0, 0, 0}
743 };
744
745 int idx = 0;
746 int opt = getopt_long(argc, argv, "d:t:q:b:", options, &idx);
747
748 std::string arg = optarg ? optarg : "";
749 size_t len = 0;
750 switch(opt) {
751 // Exit Case
752 case -1:
753 /* paranoid */ assert(optind <= argc);
754 switch(benchmark) {
755 case NONE:
756 std::cerr << "Must specify a benchmark" << std::endl;
757 goto usage;
758 case PingPong:
759 nnodes = 1;
760 switch(argc - optind) {
761 case 0: break;
762 case 1:
763 try {
764 arg = optarg = argv[optind];
765 nnodes = stoul(optarg, &len);
766 if(len != arg.size()) { throw std::invalid_argument(""); }
767 } catch(std::invalid_argument &) {
768 std::cerr << "Number of nodes must be a positive integer, was " << arg << std::endl;
769 goto usage;
770 }
771 break;
772 default:
773 std::cerr << "'PingPong' benchmark doesn't accept more than 1 extra arguments" << std::endl;
774 goto usage;
775 }
776 break;
777 case Producer:
778 nnodes = 32;
779 switch(argc - optind) {
780 case 0: break;
781 case 1:
782 try {
783 arg = optarg = argv[optind];
784 nnodes = stoul(optarg, &len);
785 if(len != arg.size()) { throw std::invalid_argument(""); }
786 } catch(std::invalid_argument &) {
787 std::cerr << "Number of nodes must be a positive integer, was " << arg << std::endl;
788 goto usage;
789 }
790 break;
791 default:
792 std::cerr << "'Producer' benchmark doesn't accept more than 1 extra arguments" << std::endl;
793 goto usage;
794 }
795 break;
796 case Churn:
797 nnodes = 100;
798 nslots = 100;
799 switch(argc - optind) {
800 case 0: break;
801 case 1:
802 try {
803 arg = optarg = argv[optind];
804 nnodes = stoul(optarg, &len);
805 if(len != arg.size()) { throw std::invalid_argument(""); }
806 nslots = nnodes;
807 } catch(std::invalid_argument &) {
808 std::cerr << "Number of nodes must be a positive integer, was " << arg << std::endl;
809 goto usage;
810 }
811 break;
812 case 2:
813 try {
814 arg = optarg = argv[optind];
815 nnodes = stoul(optarg, &len);
816 if(len != arg.size()) { throw std::invalid_argument(""); }
817 } catch(std::invalid_argument &) {
818 std::cerr << "Number of nodes must be a positive integer, was " << arg << std::endl;
819 goto usage;
820 }
821 try {
822 arg = optarg = argv[optind + 1];
823 nslots = stoul(optarg, &len);
824 if(len != arg.size()) { throw std::invalid_argument(""); }
825 } catch(std::invalid_argument &) {
826 std::cerr << "Number of slots must be a positive integer, was " << arg << std::endl;
827 goto usage;
828 }
829 break;
830 default:
831 std::cerr << "'Churn' benchmark doesn't accept more than 2 extra arguments" << std::endl;
832 goto usage;
833 }
834 break;
835 case Fairness:
836 nnodes = 1;
837 switch(argc - optind) {
838 case 0: break;
839 case 1:
840 arg = optarg = argv[optind];
841 out = arg;
842 break;
843 default:
844 std::cerr << "'Churn' benchmark doesn't accept more than 2 extra arguments" << std::endl;
845 goto usage;
846 }
847 }
848 goto run;
849 // Benchmarks
850 case 'b':
851 if(benchmark != NONE) {
852 std::cerr << "Only when benchmark can be run" << std::endl;
853 goto usage;
854 }
855 if(iequals(arg, "churn")) {
856 benchmark = Churn;
857 break;
858 }
859 if(iequals(arg, "pingpong")) {
860 benchmark = PingPong;
861 break;
862 }
863 if(iequals(arg, "producer")) {
864 benchmark = Producer;
865 break;
866 }
867 if(iequals(arg, "fairness")) {
868 benchmark = Fairness;
869 break;
870 }
871 std::cerr << "Unkown benchmark " << arg << std::endl;
872 goto usage;
873 // Numeric Arguments
874 case 'd':
875 try {
876 duration = stod(optarg, &len);
877 if(len != arg.size()) { throw std::invalid_argument(""); }
878 } catch(std::invalid_argument &) {
879 std::cerr << "Duration must be a valid double, was " << arg << std::endl;
880 goto usage;
881 }
882 break;
883 case 't':
884 try {
885 nthreads = stoul(optarg, &len);
886 if(len != arg.size()) { throw std::invalid_argument(""); }
887 } catch(std::invalid_argument &) {
888 std::cerr << "Number of threads must be a positive integer, was " << arg << std::endl;
889 goto usage;
890 }
891 break;
892 case 'q':
893 try {
894 nqueues = stoul(optarg, &len);
895 if(len != arg.size()) { throw std::invalid_argument(""); }
896 } catch(std::invalid_argument &) {
897 std::cerr << "Number of queues must be a positive integer, was " << arg << std::endl;
898 goto usage;
899 }
900 break;
901 // Other cases
902 default: /* ? */
903 std::cerr << opt << std::endl;
904 usage:
905 std::cerr << "Usage: " << argv[0] << ": [options] -b churn [NNODES] [NSLOTS = NNODES]" << std::endl;
906 std::cerr << " or: " << argv[0] << ": [options] -b pingpong [NNODES]" << std::endl;
907 std::cerr << " or: " << argv[0] << ": [options] -b producer [NNODES]" << std::endl;
908 std::cerr << std::endl;
909 std::cerr << " -d, --duration=DURATION Duration of the experiment, in seconds" << std::endl;
910 std::cerr << " -t, --nthreads=NTHREADS Number of kernel threads" << std::endl;
911 std::cerr << " -q, --nqueues=NQUEUES Number of queues per threads" << std::endl;
912 std::exit(1);
913 }
914 }
915 run:
916
917 check_cache_line_size();
918
919 std::cout << "Running " << nthreads << " threads (" << (nthreads * nqueues) << " queues) for " << duration << " seconds" << std::endl;
920 switch(benchmark) {
921 case Churn:
922 runChurn(nthreads, nqueues, duration, nnodes, nslots);
923 break;
924 case PingPong:
925 runPingPong(nthreads, nqueues, duration, nnodes);
926 break;
927 case Producer:
928 runProducer(nthreads, nqueues, duration, nnodes);
929 break;
930 case Fairness:
931 runFairness(nthreads, nqueues, duration, nnodes, out);
932 break;
933 default:
934 abort();
935 }
936 return 0;
937}
938
939const char * __my_progname = "Relaxed List";
940
941struct rgb_t {
942 double r; // a fraction between 0 and 1
943 double g; // a fraction between 0 and 1
944 double b; // a fraction between 0 and 1
945};
946
947struct hsv_t {
948 double h; // angle in degrees
949 double s; // a fraction between 0 and 1
950 double v; // a fraction between 0 and 1
951};
952
953rgb_t hsv2rgb(hsv_t in) {
954 double hh, p, q, t, ff;
955 long i;
956 rgb_t out;
957
958 if(in.s <= 0.0) { // < is bogus, just shuts up warnings
959 out.r = in.v;
960 out.g = in.v;
961 out.b = in.v;
962 return out;
963 }
964 hh = in.h;
965 if(hh >= 360.0) hh = 0.0;
966 hh /= 60.0;
967 i = (long)hh;
968 ff = hh - i;
969 p = in.v * (1.0 - in.s);
970 q = in.v * (1.0 - (in.s * ff));
971 t = in.v * (1.0 - (in.s * (1.0 - ff)));
972
973 switch(i) {
974 case 0:
975 out.r = in.v;
976 out.g = t;
977 out.b = p;
978 break;
979 case 1:
980 out.r = q;
981 out.g = in.v;
982 out.b = p;
983 break;
984 case 2:
985 out.r = p;
986 out.g = in.v;
987 out.b = t;
988 break;
989
990 case 3:
991 out.r = p;
992 out.g = q;
993 out.b = in.v;
994 break;
995 case 4:
996 out.r = t;
997 out.g = p;
998 out.b = in.v;
999 break;
1000 case 5:
1001 default:
1002 out.r = in.v;
1003 out.g = p;
1004 out.b = q;
1005 break;
1006 }
1007 return out;
1008}
1009
1010// void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output) {
1011// std::ofstream os(output);
1012// os << "<html>\n";
1013// os << "<head>\n";
1014// os << "<style>\n";
1015// os << "</style>\n";
1016// os << "</head>\n";
1017// os << "<body>\n";
1018// os << "<table style=\"width=100%\">\n";
1019
1020// size_t idx = 0;
1021// for(size_t r = 0ul; r < rows; r++) {
1022// os << "<tr>\n";
1023// for(size_t c = 0ul; c < columns; c++) {
1024// os << "<td class=\"custom custom" << data[idx] << "\"></td>\n";
1025// idx++;
1026// }
1027// os << "</tr>\n";
1028// }
1029
1030// os << "</table>\n";
1031// os << "</body>\n";
1032// os << "</html>\n";
1033// os << std::endl;
1034// }
1035
1036// #include <png.h>
1037// #include <setjmp.h>
1038
1039/*
1040void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output) {
1041 int width = columns * factor;
1042 int height = rows / factor;
1043
1044 int code = 0;
1045 int idx = 0;
1046 FILE *fp = NULL;
1047 png_structp png_ptr = NULL;
1048 png_infop info_ptr = NULL;
1049 png_bytep row = NULL;
1050
1051 // Open file for writing (binary mode)
1052 fp = fopen(output.c_str(), "wb");
1053 if (fp == NULL) {
1054 fprintf(stderr, "Could not open file %s for writing\n", output.c_str());
1055 code = 1;
1056 goto finalise;
1057 }
1058
1059 // Initialize write structure
1060 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1061 if (png_ptr == NULL) {
1062 fprintf(stderr, "Could not allocate write struct\n");
1063 code = 1;
1064 goto finalise;
1065 }
1066
1067 // Initialize info structure
1068 info_ptr = png_create_info_struct(png_ptr);
1069 if (info_ptr == NULL) {
1070 fprintf(stderr, "Could not allocate info struct\n");
1071 code = 1;
1072 goto finalise;
1073 }
1074
1075 // Setup Exception handling
1076 if (setjmp(png_jmpbuf(png_ptr))) {
1077 fprintf(stderr, "Error during png creation\n");
1078 code = 1;
1079 goto finalise;
1080 }
1081
1082 png_init_io(png_ptr, fp);
1083
1084 // Write header (8 bit colour depth)
1085 png_set_IHDR(png_ptr, info_ptr, width, height,
1086 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
1087 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
1088
1089 png_write_info(png_ptr, info_ptr);
1090
1091 // Allocate memory for one row (3 bytes per pixel - RGB)
1092 row = (png_bytep) malloc(3 * width * sizeof(png_byte));
1093
1094 // Write image data
1095 int x, y;
1096 for (y=0 ; y<height ; y++) {
1097 for (x=0 ; x<width ; x++) {
1098 auto & r = row[(x * 3) + 0];
1099 auto & g = row[(x * 3) + 1];
1100 auto & b = row[(x * 3) + 2];
1101 assert(idx < (rows * columns));
1102 int color = data[idx] - 1;
1103 assert(color < nthreads);
1104 assert(color >= 0);
1105 idx++;
1106
1107 double angle = double(color) / double(nthreads);
1108
1109 auto c = hsv2rgb({ 360.0 * angle, 0.8, 0.8 });
1110
1111 r = char(c.r * 255.0);
1112 g = char(c.g * 255.0);
1113 b = char(c.b * 255.0);
1114
1115 }
1116 png_write_row(png_ptr, row);
1117 }
1118
1119 assert(idx == (rows * columns));
1120
1121 // End write
1122 png_write_end(png_ptr, NULL);
1123
1124 finalise:
1125 if (fp != NULL) fclose(fp);
1126 if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
1127 if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
1128 if (row != NULL) free(row);
1129}
1130*/
Note: See TracBrowser for help on using the repository browser.