source: doc/theses/thierry_delisle_PhD/code/relaxed_list.cpp@ 433d352

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 433d352 was b232745, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Several changes to relaxed list prototype and added workstealing for comparison

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