source: doc/theses/thierry_delisle_PhD/code/relaxed_list.cpp@ edb2fe0

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 edb2fe0 was 16ee228, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Changed benchmark to only print progress if in a tty

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