Changeset 95cb63b


Ignore:
Timestamp:
May 22, 2020, 3:22:43 PM (17 months ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
arm-eh, jacob/cs343-translation, master, new-ast, new-ast-unique-expr
Children:
8f4f3e0
Parents:
0e4df2e
Message:

Added benchmark called producer, which mimicks I/O scheduling

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/thierry_delisle_PhD/code/relaxed_list.cpp

    r0e4df2e r95cb63b  
    5757        size_t valmax = 0;
    5858        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;
    5967};
    6068
     
    6775        std::atomic_size_t valmax = { 0 };
    6876        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;
    6985};
    7086
     
    95111        global.crc_in  += local.crc_in;
    96112        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;
    97118
    98119        atomic_max(global.valmax, local.valmax);
     
    159180        auto dur_nano = duration_cast<std::nano>(1.0);
    160181
     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        }
    161192        std::cout << "Duration      : " << duration << "s\n";
    162193        std::cout << "ns/Op         : " << ( dur_nano / ops_thread )<< "\n";
     
    164195        std::cout << "Ops/sec       : " << ops_sec << "\n";
    165196        std::cout << "Total ops     : " << ops << "(" << global.in << "i, " << global.out << "o, " << global.empty << "e)\n";
    166         if(global.valmax != 0) {
    167                 std::cout << "Max runs      : " << global.valmax << "\n";
    168                 std::cout << "Min runs      : " << global.valmin << "\n";
    169         }
    170197        #ifndef NO_STATS
    171198                relaxed_list<Node>::stats_print(std::cout);
     
    395422
    396423                enable_stats = false;
     424        }
     425
     426        print_stats(duration, nthread, global);
     427}
     428
     429// ================================================================================================
     430struct __attribute__((aligned(64))) Slot {
     431        Node * volatile node;
     432};
     433
     434__attribute__((noinline)) void runProducer_body(
     435        std::atomic<bool>& done,
     436        Random & rand,
     437        Slot * slots,
     438        int nslots,
     439        local_stat_t & local,
     440        relaxed_list<Node> & list
     441) {
     442        while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
     443
     444                Node * node = list.pop();
     445                if(!node) {
     446                        local.empty ++;
     447                        continue;
     448                }
     449
     450                local.crc_out += node->value;
     451                local.out++;
     452
     453                if(node->id == 0) {
     454                        unsigned cnt = 0;
     455                        for(int i = 0; i < nslots; i++) {
     456                                Node * found = __atomic_exchange_n( &slots[i].node, nullptr, __ATOMIC_SEQ_CST );
     457                                if( found ) {
     458                                        local.crc_in += found->value;
     459                                        local.in++;
     460                                        cnt++;
     461                                        list.push( found );
     462                                }
     463                        }
     464
     465                        local.crc_in += node->value;
     466                        local.in++;
     467                        list.push( node );
     468
     469                        local.comp.cnt++;
     470                        local.comp.val += cnt;
     471                }
     472                else {
     473                        unsigned len = 0;
     474                        while(true) {
     475                                auto off = rand.next();
     476                                for(int i = 0; i < nslots; i++) {
     477                                        Node * expected = nullptr;
     478                                        int idx = (i + off) % nslots;
     479                                        Slot & slot = slots[ idx ];
     480                                        if(
     481                                                slot.node == nullptr &&
     482                                                __atomic_compare_exchange_n( &slot.node, &expected, node, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST )
     483                                        ) {
     484                                                local.subm.cnt++;
     485                                                local.subm.val += len;
     486                                                goto LOOP;
     487                                        }
     488                                        assert( expected != node );
     489                                        len++;
     490                                }
     491                        }
     492                }
     493
     494                LOOP:;
     495        }
     496}
     497
     498void runProducer(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes) {
     499        std::cout << "Producer Benchmark" << std::endl;
     500
     501        // Barrier for synchronization
     502        barrier_t barrier(nthread + 1);
     503
     504        // Data to check everything is OK
     505        global_stat_t global;
     506
     507        // Flag to signal termination
     508        std::atomic_bool done  = { false };
     509
     510        std::cout << "Initializing ";
     511
     512        int nslots = nnodes * 4;
     513        Slot * slots = new Slot[nslots];
     514        std::cout << nnodes << " nodes (" << nslots << " slots)" << std::endl;
     515
     516        // List being tested
     517        relaxed_list<Node> list = { nthread * nqueues };
     518        {
     519                Random rand(rdtscl());
     520                for(unsigned i = 0; i < nnodes; i++) {
     521                        Node * node = new Node(rand.next() % 100);
     522                        node->id = i;
     523                        global.crc_in += node->value;
     524                        list.push(node);
     525                }
     526
     527                for(int i = 0; i < nslots; i++) {
     528                        slots[i].node = nullptr;
     529                }
     530        }
     531
     532        {
     533                enable_stats = true;
     534
     535                std::thread * threads[nthread];
     536                unsigned i = 1;
     537                for(auto & t : threads) {
     538                        t = new std::thread([&done, &list, &barrier, &global, slots, nslots](unsigned tid) {
     539                                Random rand(tid + rdtscl());
     540
     541                                local_stat_t local;
     542                                barrier.wait(tid);
     543
     544                                // EXPERIMENT START
     545
     546                                runProducer_body(done, rand, slots, nslots, local, list);
     547
     548                                // EXPERIMENT END
     549
     550                                barrier.wait(tid);
     551
     552                                tally_stats(global, local);
     553                        }, i++);
     554                }
     555
     556                waitfor(duration, barrier, done);
     557
     558                for(auto t : threads) {
     559                        t->join();
     560                        delete t;
     561                }
     562
     563                enable_stats = false;
     564        }
     565
     566        {
     567                while(Node * node = list.pop()) {
     568                        global.crc_out += node->value;
     569                        delete node;
     570                }
     571
     572                for(int i = 0; i < nslots; i++) {
     573                        delete slots[i].node;
     574                }
     575
     576                delete [] slots;
    397577        }
    398578
     
    521701        print_stats(duration, nthread, global);
    522702
    523         save_fairness(data_out.get(), 100, nthread, width, length, output);
     703        // save_fairness(data_out.get(), 100, nthread, width, length, output);
    524704}
    525705
     
    547727                Churn,
    548728                PingPong,
     729                Producer,
    549730                Fairness,
    550731                NONE
     
    577758                                case PingPong:
    578759                                        nnodes = 1;
    579                                         nslots = 1;
    580760                                        switch(argc - optind) {
    581761                                        case 0: break;
     
    591771                                                break;
    592772                                        default:
    593                                                 std::cerr << "'PingPong' benchmark doesn't accept more than 2 extra arguments" << std::endl;
     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;
    594793                                                goto usage;
    595794                                        }
     
    662861                                        break;
    663862                                }
     863                                if(iequals(arg, "producer")) {
     864                                        benchmark = Producer;
     865                                        break;
     866                                }
    664867                                if(iequals(arg, "fairness")) {
    665868                                        benchmark = Fairness;
     
    702905                                std::cerr << "Usage: " << argv[0] << ": [options] -b churn [NNODES] [NSLOTS = NNODES]" << std::endl;
    703906                                std::cerr << "  or:  " << argv[0] << ": [options] -b pingpong [NNODES]" << std::endl;
     907                                std::cerr << "  or:  " << argv[0] << ": [options] -b producer [NNODES]" << std::endl;
    704908                                std::cerr << std::endl;
    705909                                std::cerr << "  -d, --duration=DURATION  Duration of the experiment, in seconds" << std::endl;
     
    720924                case PingPong:
    721925                        runPingPong(nthreads, nqueues, duration, nnodes);
     926                        break;
     927                case Producer:
     928                        runProducer(nthreads, nqueues, duration, nnodes);
    722929                        break;
    723930                case Fairness:
     
    8011008}
    8021009
    803 void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output) {
    804         std::ofstream os(output);
    805         os << "<html>\n";
    806         os << "<head>\n";
    807         os << "<style>\n";
    808         os << "</style>\n";
    809         os << "</head>\n";
    810         os << "<body>\n";
    811         os << "<table style=\"width=100%\">\n";
    812 
    813         size_t idx = 0;
    814         for(size_t r = 0ul; r < rows; r++) {
    815                 os << "<tr>\n";
    816                 for(size_t c = 0ul; c < columns; c++) {
    817                         os << "<td class=\"custom custom" << data[idx] << "\"></td>\n";
    818                         idx++;
    819                 }
    820                 os << "</tr>\n";
    821         }
    822 
    823         os << "</table>\n";
    824         os << "</body>\n";
    825         os << "</html>\n";
    826         os << std::endl;
    827 }
    828 
    829 #include <png.h>
    830 #include <setjmp.h>
     1010// void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output) {
     1011//      std::ofstream os(output);
     1012//      os << "<html>\n";
     1013//      os << "<head>\n";
     1014//      os << "<style>\n";
     1015//      os << "</style>\n";
     1016//      os << "</head>\n";
     1017//      os << "<body>\n";
     1018//      os << "<table style=\"width=100%\">\n";
     1019
     1020//      size_t idx = 0;
     1021//      for(size_t r = 0ul; r < rows; r++) {
     1022//              os << "<tr>\n";
     1023//              for(size_t c = 0ul; c < columns; c++) {
     1024//                      os << "<td class=\"custom custom" << data[idx] << "\"></td>\n";
     1025//                      idx++;
     1026//              }
     1027//              os << "</tr>\n";
     1028//      }
     1029
     1030//      os << "</table>\n";
     1031//      os << "</body>\n";
     1032//      os << "</html>\n";
     1033//      os << std::endl;
     1034// }
     1035
     1036// #include <png.h>
     1037// #include <setjmp.h>
    8311038
    8321039/*
Note: See TracChangeset for help on using the changeset viewer.