source: doc/theses/thierry_delisle_PhD/code/relaxed_list.cpp @ 8e1b1bb

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 8e1b1bb was 8e1b1bb, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Now using a single macro for algorithmic variants

  • Property mode set to 100644
File size: 26.3 KB
RevLine 
[b2a37b0]1#include "relaxed_list.hpp"
2
3#include <array>
[c921712]4#include <iomanip>
[b2a37b0]5#include <iostream>
6#include <locale>
7#include <string>
8#include <thread>
9#include <vector>
10
[9421f3d8]11#include <getopt.h>
[b2a37b0]12#include <unistd.h>
13#include <sys/sysinfo.h>
14
15#include "utils.hpp"
16
[50aeb6f]17struct __attribute__((aligned(64))) Node {
[b2a37b0]18        static std::atomic_size_t creates;
19        static std::atomic_size_t destroys;
20
21        _LinksFields_t<Node> _links;
22
23        int value;
[807a632]24        int id;
[b2a37b0]25
[9421f3d8]26        Node() { creates++; }
27        Node(int value): value(value) { creates++; }
28        ~Node() { destroys++; }
[b2a37b0]29};
30
31std::atomic_size_t Node::creates  = { 0 };
32std::atomic_size_t Node::destroys = { 0 };
33
34bool enable_stats = false;
35
[9421f3d8]36template<>
37thread_local relaxed_list<Node>::TLS relaxed_list<Node>::tls = {};
38
39template<>
[807a632]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
[9421f3d8]46
47// ================================================================================================
48//                        UTILS
49// ================================================================================================
50
[50aeb6f]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;
[807a632]57        size_t valmax = 0;
58        size_t valmin = 100000000ul;
[95cb63b]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;
[50aeb6f]67};
68
[9421f3d8]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 };
[807a632]75        std::atomic_size_t valmax = { 0 };
76        std::atomic_size_t valmin = { 100000000ul };
[95cb63b]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;
[9421f3d8]85};
86
[807a632]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
[9421f3d8]105void tally_stats(global_stat_t & global, local_stat_t & local) {
[807a632]106
[9421f3d8]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
[95cb63b]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
[807a632]119        atomic_max(global.valmax, local.valmax);
120        atomic_min(global.valmin, local.valmin);
[9421f3d8]121
[807a632]122        relaxed_list<Node>::stats_tls_tally();
[9421f3d8]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
[807a632]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
[9421f3d8]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
[95cb63b]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        }
[9421f3d8]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
[807a632]198                relaxed_list<Node>::stats_print(std::cout);
[9421f3d8]199        #endif
200}
201
[807a632]202void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output);
203
[9421f3d8]204// ================================================================================================
205//                        EXPERIMENTS
206// ================================================================================================
207
208// ================================================================================================
209__attribute__((noinline)) void runChurn_body(
[50aeb6f]210        std::atomic<bool>& done,
211        Random & rand,
[9421f3d8]212        Node * my_nodes[],
213        unsigned nslots,
[50aeb6f]214        local_stat_t & local,
215        relaxed_list<Node> & list
216) {
217        while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
[9421f3d8]218                int idx = rand.next() % nslots;
[50aeb6f]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}
[b2a37b0]235
[9421f3d8]236void runChurn(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes, const unsigned nslots) {
237        std::cout << "Churn Benchmark" << std::endl;
238        assert(nnodes <= nslots);
[b2a37b0]239        // List being tested
240
241        // Barrier for synchronization
242        barrier_t barrier(nthread + 1);
243
244        // Data to check everything is OK
[9421f3d8]245        global_stat_t global;
[b2a37b0]246
247        // Flag to signal termination
248        std::atomic_bool done  = { false };
249
250        // Prep nodes
[c921712]251        std::cout << "Initializing ";
252        size_t npushed = 0;
[807a632]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                        }
[9421f3d8]262
[807a632]263                        for(unsigned i = nnodes; i < nslots; i++) {
264                                nodes[i] = nullptr;
265                        }
[b2a37b0]266
[807a632]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                                }
[b2a37b0]275                        }
276                }
277
[807a632]278                std::cout << nnodes << " nodes (" << nslots << " slots)" << std::endl;
[c921712]279
[807a632]280                enable_stats = true;
[b2a37b0]281
[807a632]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());
[b2a37b0]288
[807a632]289                                local_stat_t local;
[b2a37b0]290
[807a632]291                                // affinity(tid);
[b2a37b0]292
[807a632]293                                barrier.wait(tid);
[b2a37b0]294
[807a632]295                                // EXPERIMENT START
[b2a37b0]296
[807a632]297                                runChurn_body(done, rand, my_nodes, nslots, local, list);
[b2a37b0]298
[807a632]299                                // EXPERIMENT END
[b2a37b0]300
[807a632]301                                barrier.wait(tid);
[b2a37b0]302
[807a632]303                                tally_stats(global, local);
[b2a37b0]304
[807a632]305                                for(unsigned i = 0; i < nslots; i++) {
306                                        delete my_nodes[i];
307                                }
308                        }, i++);
309                }
[b2a37b0]310
[807a632]311                waitfor(duration, barrier, done);
[b2a37b0]312
[807a632]313                for(auto t : threads) {
314                        t->join();
315                        delete t;
316                }
[b2a37b0]317
[807a632]318                enable_stats = false;
[b2a37b0]319
[807a632]320                while(auto node = list.pop()) {
321                        global.crc_out += node->value;
322                        delete node;
323                }
[b2a37b0]324
[807a632]325                for(auto nodes : all_nodes) {
326                        delete[] nodes;
327                }
[9421f3d8]328        }
[b2a37b0]329
[9421f3d8]330        print_stats(duration, nthread, global);
331}
[b2a37b0]332
[9421f3d8]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        }
[b2a37b0]348
[9421f3d8]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 ";
[807a632]382        // List being tested
383        relaxed_list<Node> list = { nthread * nqueues };
384        {
385                enable_stats = true;
[9421f3d8]386
[807a632]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());
[9421f3d8]392
[807a632]393                                Node nodes[nnodes];
394                                for(auto & n : nodes) {
395                                        n.value = (int)rand.next() % 100;
396                                }
[9421f3d8]397
[807a632]398                                local_stat_t local;
[9421f3d8]399
[807a632]400                                // affinity(tid);
[9421f3d8]401
[807a632]402                                barrier.wait(tid);
[9421f3d8]403
[807a632]404                                // EXPERIMENT START
[9421f3d8]405
[807a632]406                                runPingPong_body(done, nodes, nnodes, local, list);
[9421f3d8]407
[807a632]408                                // EXPERIMENT END
[9421f3d8]409
[807a632]410                                barrier.wait(tid);
[9421f3d8]411
[807a632]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;
[9421f3d8]424        }
425
[807a632]426        print_stats(duration, nthread, global);
427}
[9421f3d8]428
[95cb63b]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
[807a632]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                }
[9421f3d8]600        }
601
[807a632]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        }
[9421f3d8]700
701        print_stats(duration, nthread, global);
[807a632]702
[95cb63b]703        // save_fairness(data_out.get(), 100, nthread, width, length, output);
[b2a37b0]704}
705
[807a632]706// ================================================================================================
707
[9421f3d8]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                      });
[b2a37b0]715}
716
717int main(int argc, char * argv[]) {
718
719        double duration   = 5.0;
720        unsigned nthreads = 2;
[9421f3d8]721        unsigned nqueues  = 4;
722        unsigned nnodes   = 100;
723        unsigned nslots   = 100;
[807a632]724        std::string out   = "fairness.png";
[9421f3d8]725
726        enum {
727                Churn,
728                PingPong,
[95cb63b]729                Producer,
[807a632]730                Fairness,
[9421f3d8]731                NONE
732        } benchmark = NONE;
[b2a37b0]733
734        std::cout.imbue(std::locale(""));
735
[9421f3d8]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:
[95cb63b]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;
[9421f3d8]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;
[807a632]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                                        }
[9421f3d8]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                                }
[95cb63b]863                                if(iequals(arg, "producer")) {
864                                        benchmark = Producer;
865                                        break;
866                                }
[807a632]867                                if(iequals(arg, "fairness")) {
868                                        benchmark = Fairness;
869                                        break;
870                                }
[9421f3d8]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;
[95cb63b]907                                std::cerr << "  or:  " << argv[0] << ": [options] -b producer [NNODES]" << std::endl;
[9421f3d8]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);
[b2a37b0]913                }
914        }
[9421f3d8]915        run:
[b2a37b0]916
917        check_cache_line_size();
918
[50aeb6f]919        std::cout << "Running " << nthreads << " threads (" << (nthreads * nqueues) << " queues) for " << duration << " seconds" << std::endl;
[8e1b1bb]920        std::cout << "Relaxed list variant: " << relaxed_list<Node>::name() << std::endl;
[9421f3d8]921        switch(benchmark) {
922                case Churn:
923                        runChurn(nthreads, nqueues, duration, nnodes, nslots);
924                        break;
925                case PingPong:
926                        runPingPong(nthreads, nqueues, duration, nnodes);
927                        break;
[95cb63b]928                case Producer:
929                        runProducer(nthreads, nqueues, duration, nnodes);
930                        break;
[807a632]931                case Fairness:
932                        runFairness(nthreads, nqueues, duration, nnodes, out);
933                        break;
[9421f3d8]934                default:
935                        abort();
936        }
[b2a37b0]937        return 0;
938}
939
[807a632]940const char * __my_progname = "Relaxed List";
941
942struct rgb_t {
943    double r;       // a fraction between 0 and 1
944    double g;       // a fraction between 0 and 1
945    double b;       // a fraction between 0 and 1
946};
947
948struct hsv_t {
949    double h;       // angle in degrees
950    double s;       // a fraction between 0 and 1
951    double v;       // a fraction between 0 and 1
952};
953
954rgb_t hsv2rgb(hsv_t in) {
955        double hh, p, q, t, ff;
956        long   i;
957        rgb_t  out;
958
959        if(in.s <= 0.0) {       // < is bogus, just shuts up warnings
960                out.r = in.v;
961                out.g = in.v;
962                out.b = in.v;
963                return out;
964        }
965        hh = in.h;
966        if(hh >= 360.0) hh = 0.0;
967        hh /= 60.0;
968        i = (long)hh;
969        ff = hh - i;
970        p = in.v * (1.0 - in.s);
971        q = in.v * (1.0 - (in.s * ff));
972        t = in.v * (1.0 - (in.s * (1.0 - ff)));
973
974        switch(i) {
975        case 0:
976                out.r = in.v;
977                out.g = t;
978                out.b = p;
979                break;
980        case 1:
981                out.r = q;
982                out.g = in.v;
983                out.b = p;
984                break;
985        case 2:
986                out.r = p;
987                out.g = in.v;
988                out.b = t;
989                break;
990
991        case 3:
992                out.r = p;
993                out.g = q;
994                out.b = in.v;
995                break;
996        case 4:
997                out.r = t;
998                out.g = p;
999                out.b = in.v;
1000                break;
1001        case 5:
1002        default:
1003                out.r = in.v;
1004                out.g = p;
1005                out.b = q;
1006                break;
1007        }
1008        return out;
1009}
1010
[95cb63b]1011// void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output) {
1012//      std::ofstream os(output);
1013//      os << "<html>\n";
1014//      os << "<head>\n";
1015//      os << "<style>\n";
1016//      os << "</style>\n";
1017//      os << "</head>\n";
1018//      os << "<body>\n";
1019//      os << "<table style=\"width=100%\">\n";
1020
1021//      size_t idx = 0;
1022//      for(size_t r = 0ul; r < rows; r++) {
1023//              os << "<tr>\n";
1024//              for(size_t c = 0ul; c < columns; c++) {
1025//                      os << "<td class=\"custom custom" << data[idx] << "\"></td>\n";
1026//                      idx++;
1027//              }
1028//              os << "</tr>\n";
1029//      }
1030
1031//      os << "</table>\n";
1032//      os << "</body>\n";
1033//      os << "</html>\n";
1034//      os << std::endl;
1035// }
1036
1037// #include <png.h>
1038// #include <setjmp.h>
[807a632]1039
1040/*
1041void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output) {
1042        int width  = columns * factor;
1043        int height = rows / factor;
1044
1045        int code = 0;
1046        int idx = 0;
1047        FILE *fp = NULL;
1048        png_structp png_ptr = NULL;
1049        png_infop info_ptr = NULL;
1050        png_bytep row = NULL;
1051
1052        // Open file for writing (binary mode)
1053        fp = fopen(output.c_str(), "wb");
1054        if (fp == NULL) {
1055                fprintf(stderr, "Could not open file %s for writing\n", output.c_str());
1056                code = 1;
1057                goto finalise;
1058        }
1059
1060           // Initialize write structure
1061        png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1062        if (png_ptr == NULL) {
1063                fprintf(stderr, "Could not allocate write struct\n");
1064                code = 1;
1065                goto finalise;
1066        }
1067
1068        // Initialize info structure
1069        info_ptr = png_create_info_struct(png_ptr);
1070        if (info_ptr == NULL) {
1071                fprintf(stderr, "Could not allocate info struct\n");
1072                code = 1;
1073                goto finalise;
1074        }
1075
1076        // Setup Exception handling
1077        if (setjmp(png_jmpbuf(png_ptr))) {
1078                fprintf(stderr, "Error during png creation\n");
1079                code = 1;
1080                goto finalise;
1081        }
1082
1083        png_init_io(png_ptr, fp);
1084
1085        // Write header (8 bit colour depth)
1086        png_set_IHDR(png_ptr, info_ptr, width, height,
1087                8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
1088                PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
1089
1090        png_write_info(png_ptr, info_ptr);
1091
1092        // Allocate memory for one row (3 bytes per pixel - RGB)
1093        row = (png_bytep) malloc(3 * width * sizeof(png_byte));
1094
1095        // Write image data
1096        int x, y;
1097        for (y=0 ; y<height ; y++) {
1098                for (x=0 ; x<width ; x++) {
1099                        auto & r = row[(x * 3) + 0];
1100                        auto & g = row[(x * 3) + 1];
1101                        auto & b = row[(x * 3) + 2];
1102                        assert(idx < (rows * columns));
1103                        int color = data[idx] - 1;
1104                        assert(color < nthreads);
1105                        assert(color >= 0);
1106                        idx++;
1107
1108                        double angle = double(color) / double(nthreads);
1109
1110                        auto c = hsv2rgb({ 360.0 * angle, 0.8, 0.8 });
1111
1112                        r = char(c.r * 255.0);
1113                        g = char(c.g * 255.0);
1114                        b = char(c.b * 255.0);
1115
1116                }
1117                png_write_row(png_ptr, row);
1118        }
1119
1120        assert(idx == (rows * columns));
1121
1122        // End write
1123        png_write_end(png_ptr, NULL);
1124
1125        finalise:
1126        if (fp != NULL) fclose(fp);
1127        if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
1128        if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
1129        if (row != NULL) free(row);
1130}
1131*/
Note: See TracBrowser for help on using the repository browser.