<commit_before>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#include <boost/test/unit_test.hpp>

#include "Grappa.hpp"
#include "CompletionEvent.hpp"
#include "ParallelLoop.hpp"
#include "Collective.hpp"

#include <string>

DECLARE_uint64( num_starting_workers );
DEFINE_uint64( num_test_workers, 4, "Number of workers for the tests");
DEFINE_uint64( iters_per_task, 10000, "Iterations per task" );
DEFINE_string( test_type, "yields", "options: {yields,sequential_updates, sequential_updates16" );  
DEFINE_uint64( private_array_size, 1, "Size of private array of 8-bytes for each task" );

using namespace Grappa;

CompletionEvent * final;
CompletionEvent * task_barrier;

struct SixteenBytes {
  uint64_t val1;
  uint64_t val2;
};

struct Cacheline {
  uint64_t val;
  char padding[56];
};

uint64_t * values8;
SixteenBytes * values16;


BOOST_AUTO_TEST_SUITE( ContextSwitchRate_tests );

void user_main( void * args ) {
  srand((unsigned int)Grappa_walltime());

  // must have enough threads because they all join a barrier
  BOOST_CHECK( FLAGS_num_test_workers < FLAGS_num_starting_workers );

  if (FLAGS_test_type.compare("yields")==0) {
    BOOST_MESSAGE( "Test yields" );
    {
      struct runtimes_t {
        double runtime_avg, runtime_min, runtime_max;
      };
      runtimes_t r;
      
      on_all_cores( [&r] {
        // per core timing
        double start, end;
        bool started = false;

        final = new CompletionEvent(FLAGS_num_test_workers);
        task_barrier = new CompletionEvent(FLAGS_num_test_workers);

        for ( uint64_t t=0; t<FLAGS_num_test_workers; t++ ) {
          privateTask( [&started,&start] {
            // wait for all to start (to hack scheduler yield)
            task_barrier->complete();
            task_barrier->wait();

            // first task to exit the local barrier will start the timer
            if ( !started ) {
              start = Grappa_walltime();
              started = true;
            }

            // do the work
            for ( uint64_t i=0; i<FLAGS_iters_per_task; i++ ) { 
              Grappa_yield();
            }

            final->complete();
          });
        }
        
        BOOST_MESSAGE( "waiting" );
        final->wait();
        end = Grappa_walltime();
        double runtime = end-start;
        BOOST_MESSAGE( "took time " << runtime );

        Grappa::barrier();
        BOOST_MESSAGE( "all done" );

        // sort out timing 

        double r_sum = Grappa::allreduce<double, collective_add>( runtime );
        double r_min = Grappa::allreduce<double, collective_min>( runtime );
        double r_max = Grappa::allreduce<double, collective_max>( runtime );
        if ( Grappa::mycore()==0 ) {
          r.runtime_avg = r_sum / Grappa::cores();
          r.runtime_min = r_min;
          r.runtime_max = r_max;
        }
      });

      BOOST_MESSAGE( "cores_time_avg = " << r.runtime_avg
                      << ", cores_time_max = " << r.runtime_max
                      << ", cores_time_min = " << r.runtime_min);
    }
  } else if (FLAGS_test_type.compare("sequential_updates")==0) {
    BOOST_MESSAGE( "Test sequential_updates" );
    {

      final = new CompletionEvent(FLAGS_num_starting_workers);
      task_barrier = new CompletionEvent(FLAGS_num_starting_workers);
      values8 = new uint64_t[FLAGS_num_starting_workers];
<commit_msg>add a flag-based condition variable wake test<commit_after>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#include <boost/test/unit_test.hpp>

#include "Grappa.hpp"
#include "CompletionEvent.hpp"
#include "ParallelLoop.hpp"
#include "Collective.hpp"

#include <string>

DECLARE_uint64( num_starting_workers );
DEFINE_uint64( num_test_workers, 4, "Number of workers for the tests");
DEFINE_uint64( iters_per_task, 10000, "Iterations per task" );
DEFINE_string( test_type, "yields", "options: {yields,sequential_updates, sequential_updates16" );  
DEFINE_uint64( private_array_size, 1, "Size of private array of 8-bytes for each task" );

using namespace Grappa;

CompletionEvent * final;
CompletionEvent * task_barrier;

struct SixteenBytes {
  uint64_t val1;
  uint64_t val2;
};

struct Cacheline {
  uint64_t val;
  char padding[56];
};

uint64_t * values8;
SixteenBytes * values16;


// core-shared counter for counting progress
uint64_t numst;
uint64_t waitCount;
bool running;


BOOST_AUTO_TEST_SUITE( ContextSwitchRate_tests );

void user_main( void * args ) {
  srand((unsigned int)Grappa_walltime());

  // must have enough threads because they all join a barrier
  BOOST_CHECK( FLAGS_num_test_workers < FLAGS_num_starting_workers );

  if (FLAGS_test_type.compare("yields")==0) {
    BOOST_MESSAGE( "Test yields" );
    {
      struct runtimes_t {
        double runtime_avg, runtime_min, runtime_max;
      };
      runtimes_t r;
      
      on_all_cores( [&r] {
        // per core timing
        double start, end;
        bool started = false;

        final = new CompletionEvent(FLAGS_num_test_workers);
        task_barrier = new CompletionEvent(FLAGS_num_test_workers);

        for ( uint64_t t=0; t<FLAGS_num_test_workers; t++ ) {
          privateTask( [&started,&start] {
            // wait for all to start (to hack scheduler yield)
            task_barrier->complete();
            task_barrier->wait();

            // first task to exit the local barrier will start the timer
            if ( !started ) {
              start = Grappa_walltime();
              started = true;
            }

            // do the work
            for ( uint64_t i=0; i<FLAGS_iters_per_task; i++ ) { 
              Grappa_yield();
            }

            final->complete();
          });
        }
        
        BOOST_MESSAGE( "waiting" );
        final->wait();
        end = Grappa_walltime();
        double runtime = end-start;
        BOOST_MESSAGE( "took time " << runtime );

        Grappa::barrier();
        BOOST_MESSAGE( "all done" );

        // sort out timing 

        double r_sum = Grappa::allreduce<double, collective_add>( runtime );
        double r_min = Grappa::allreduce<double, collective_min>( runtime );
        double r_max = Grappa::allreduce<double, collective_max>( runtime );
        if ( Grappa::mycore()==0 ) {
          r.runtime_avg = r_sum / Grappa::cores();
          r.runtime_min = r_min;
          r.runtime_max = r_max;
        }
      });

      BOOST_MESSAGE( "cores_time_avg = " << r.runtime_avg
                      << ", cores_time_max = " << r.runtime_max
                      << ", cores_time_min = " << r.runtime_min);
    }
  } else if (FLAGS_test_type.compare("cvwakes")==0) {
    BOOST_MESSAGE( "Test cv wakes" );
    {
      struct runtimes_t {
        double runtime_avg, runtime_min, runtime_max;
      };
      runtimes_t r;

      on_all_cores( [&r] {
        // per core timing
        double start, end;

        ConditionVariable cvs[FLAGS_num_test_workers];
        bool asleep[FLAGS_num_test_workers];
        for( int i=0; i<FLAGS_num_test_workers; i++) { asleep[i] = false; }

        final = new CompletionEvent(1);
        task_barrier = new CompletionEvent(FLAGS_num_test_workers);

        running = false;
        waitCount = 0;
        numst = 0;

        for ( uint64_t t=0; t<FLAGS_num_test_workers; t++ ) {
          privateTask( [&asleep,&start,&cvs] {
            // wait for all to start (to hack scheduler yield)
            task_barrier->complete();
            task_barrier->wait();

            // first task to exit the local barrier will start the timer
            if ( !running ) {
              start = Grappa_walltime();
              running = true;
            }

            uint64_t tid = numst++;
              
            uint64_t partner = (tid + FLAGS_num_test_workers/2)%FLAGS_num_test_workers;
            uint64_t total_iters = FLAGS_iters_per_task*FLAGS_num_test_workers; 

            // do the work
            while( waitCount++ < total_iters ) {
              if ( asleep[partner] ) {   // TODO also test just wake up case
                Grappa::signal( &cvs[partner] );
              }
              asleep[tid] = true;
              Grappa::wait( &cvs[tid] );
              asleep[tid] = false;
            }

            // only first 
            if ( running ) {
              final->complete();  // signal to finish as soon as the parent task gets scheduled 
              running = false;
            }
          });
        }
        
        BOOST_MESSAGE( "waiting" );
        final->wait();
        end = Grappa_walltime();
        double runtime = end-start;
        BOOST_MESSAGE( "took time " << runtime );

        // wake all
        for (int i=0; i<FLAGS_num_test_workers; i++) { Grappa::signal(&cvs[i]); }
        BOOST_MESSAGE( "woke all" );

        Grappa::barrier();
        
        BOOST_MESSAGE( "all done" );

        // sort out timing 

        double r_sum = Grappa::allreduce<double, collective_add>( runtime );
        double r_min = Grappa::allreduce<double, collective_min>( runtime );
        double r_max = Grappa::allreduce<double, collective_max>( runtime );
        if ( Grappa::mycore()==0 ) {
          r.runtime_avg = r_sum / Grappa::cores();
          r.runtime_min = r_min;
          r.runtime_max = r_max;
        }
        BOOST_MESSAGE( "done reduce" );
      });

      BOOST_MESSAGE( "cores_time_avg = " << r.runtime_avg
                      << ", cores_time_max = " << r.runtime_max
                      << ", cores_time_min = " << r.runtime_min);
    }
  
  } else if (FLAGS_test_type.compare("sequential_updates")==0) {
    BOOST_MESSAGE( "Test sequential_updates" );
    {

      final = new CompletionEvent(FLAGS_num_starting_workers);
      task_barrier = new CompletionEvent(FLAGS_num_starting_workers);
      values8 = new uint64_t[FLAGS_num_starting_workers];

{'fraction_non_alphanumeric': 0.10689621632136952, 'fraction_numerical': 0.014103686411827644, 'mean_word_length': 2.359032995753022, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4209581', 'n_tokens_mistral': 3278, 'n_tokens_neox': 3068, 'n_words': 747}