main.cc 7.22 KB
Newer Older
1 2 3 4
/* 
 * Main script that applies the linearizability tester on embb data structures.
 */

5 6 7 8 9 10
// Enable assertions even in Release mode
#ifdef NDEBUG
#undef NDEBUG
#include <assert.h>
#endif

11
#include <linearizability_tester.h>
12
#include <sequential_data_structures.h>
13 14 15 16 17 18
#include <tests.h>

#include <embb/base/thread.h>
#include <embb/containers/lock_free_stack.h>
#include <embb/containers/lock_free_mpmc_queue.h>

19 20
// Each thread executes quasi randomly operations (TryEqneueu, TryDequeue)
// on the concurrent data structure and construct the history.
21 22
template<std::size_t N, class S>
static void embb_worker_stack(
lucapegolotti committed
23 24 25
  const WorkerConfiguration& worker_configuration,
  ConcurrentLog<state::Stack<N>>& concurrent_log,
  S& concurrent_stack)
26
{
lucapegolotti committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<> value_dist('\0', worker_configuration.max_value);
  std::uniform_int_distribution<> percentage_dist(0, 100);

  bool ret;

  char value;
  unsigned percentage;
  EntryPtr<state::Stack<N>> call_entry_ptr;
  for (unsigned number_of_ops{ 0U };
  number_of_ops < worker_configuration.number_of_ops;
    ++number_of_ops)
  {
    value = value_dist(rd);
    percentage = percentage_dist(rd);
43 44
    // Note: this threshold affects considerably the running time of the test
    // increasing threshold -> increasing running time
lucapegolotti committed
45 46 47 48 49 50 51 52 53 54 55 56 57
    if (percentage < 30)
    {
      call_entry_ptr = concurrent_log.push_back(state::Stack<N>::make_try_push_call(value));
      ret = concurrent_stack.TryPush(value);
      concurrent_log.push_back(call_entry_ptr, state::Stack<N>::make_try_push_ret(ret));
    }
    else
    {
      call_entry_ptr = concurrent_log.push_back(state::Stack<N>::make_try_pop_call());
      ret = concurrent_stack.TryPop(value);
      concurrent_log.push_back(call_entry_ptr, state::Stack<N>::make_try_pop_ret(ret, value));
    }
  }
58 59
}

60
// Each thread executes quasi randomly operations (TryEnqueue, TryDequeue)
61
// on the concurrent data structure and construct the history.
62 63
template<std::size_t N, class S>
static void embb_worker_queue(
lucapegolotti committed
64 65 66
  const WorkerConfiguration& worker_configuration,
  ConcurrentLog<state::Queue<N>>& concurrent_log,
  S& concurrent_queue)
67
{
lucapegolotti committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<> value_dist('\0', worker_configuration.max_value);
  std::uniform_int_distribution<> percentage_dist(0, 100);

  bool ret;

  char value;
  unsigned percentage;
  EntryPtr<state::Queue<N>> call_entry_ptr;
  for (unsigned number_of_ops{ 0U };
  number_of_ops < worker_configuration.number_of_ops;
    ++number_of_ops)
  {
    value = value_dist(rd);
    percentage = percentage_dist(rd);
84 85
    // Note: this threshold affects considerably the running time of the test
    // increasing threshold -> increasing running time
lucapegolotti committed
86 87 88 89 90 91 92 93 94 95 96 97 98
    if (percentage < 20)
    {
      call_entry_ptr = concurrent_log.push_back(state::Queue<N>::make_try_enqueue_call(value));
      ret = concurrent_queue.TryEnqueue(value);
      concurrent_log.push_back(call_entry_ptr, state::Queue<N>::make_try_enqueue_ret(ret));
    }
    else
    {
      call_entry_ptr = concurrent_log.push_back(state::Queue<N>::make_try_dequeue_call());
      ret = concurrent_queue.TryDequeue(value);
      concurrent_log.push_back(call_entry_ptr, state::Queue<N>::make_try_dequeue_ret(ret, value));
    }
  }
99 100
}

101
// Creates the history and apply the tester on it
102
template <class S>
103
static void embb_experiment_stack()
104
{
lucapegolotti committed
105 106 107 108 109 110 111 112 113 114
  constexpr std::chrono::hours max_duration{ 1 };
  constexpr std::size_t N = 560000U;
  constexpr unsigned number_of_threads = 4U;
  constexpr WorkerConfiguration worker_configuration = { '\24', 70000U };
  constexpr unsigned log_size = number_of_threads * worker_configuration.number_of_ops;

  Result<state::Stack<N>> result;
  ConcurrentLog<state::Stack<N>> concurrent_log{ 2U * log_size };
  S concurrent_stack(N);

115 116 117 118 119
  // Check if push and pop operations are possible
  char value;
  assert(concurrent_stack.TryPush(5));
  assert(concurrent_stack.TryPop(value));
  
lucapegolotti committed
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
  // create history
  start_threads(number_of_threads, embb_worker_stack<N, S>, std::cref(worker_configuration),
    std::ref(concurrent_log), std::ref(concurrent_stack));

  const std::size_t number_of_entries{ concurrent_log.number_of_entries() };
  const LogInfo<state::Stack<N>> log_info{ concurrent_log.info() };

  auto start = std::chrono::system_clock::now();
  auto end = std::chrono::system_clock::now();
  std::chrono::seconds seconds;

  start = std::chrono::system_clock::now();
  {
    Log<state::Stack<N>> log_copy{ log_info };
    assert(log_copy.number_of_entries() == number_of_entries);

    LinearizabilityTester<state::Stack<N>, Option::LRU_CACHE> tester{ log_copy.info(), max_duration };
    tester.check(result);
138 139
    // If structure is not linearizabile break run using assertion
    assert(result.is_timeout() || result.is_linearizable());
lucapegolotti committed
140 141 142 143 144 145
  }
  end = std::chrono::system_clock::now();
  seconds = std::chrono::duration_cast<std::chrono::seconds>(end - start);
  std::cout << "History length: " << number_of_entries
    << ", elapsed time: "
    << seconds.count() << " s " << std::endl;
146 147
}

148
// Creates the history and apply the tester on it
149
template <class S>
150
static void embb_experiment_queue()
151
{
lucapegolotti committed
152 153 154 155 156 157 158 159 160 161 162
  constexpr std::chrono::hours max_duration{ 1 };
  constexpr std::size_t N = 560000U;
  constexpr unsigned number_of_threads = 4U;
  constexpr WorkerConfiguration worker_configuration = { '\24', 70000U };
  constexpr unsigned log_size = number_of_threads * worker_configuration.number_of_ops;


  Result<state::Queue<N>> result;
  ConcurrentLog<state::Queue<N>> concurrent_log{ 2U * log_size };
  S concurrent_queue(N);

163 164 165 166
  // check if enqueue and dequeue operations are possible
  char value;
  assert(concurrent_queue.TryEnqueue(5));
  assert(concurrent_queue.TryDequeue(value));
lucapegolotti committed
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

  // create history
  start_threads(number_of_threads, embb_worker_queue<N, S>, std::cref(worker_configuration),
    std::ref(concurrent_log), std::ref(concurrent_queue));
  const std::size_t number_of_entries{ concurrent_log.number_of_entries() };
  const LogInfo<state::Queue<N>> log_info{ concurrent_log.info() };

  auto start = std::chrono::system_clock::now();
  auto end = std::chrono::system_clock::now();
  std::chrono::seconds seconds;

  start = std::chrono::system_clock::now();
  {
    Log<state::Queue<N>> log_copy{ log_info };
    assert(log_copy.number_of_entries() == number_of_entries);
    LinearizabilityTester<state::Queue<N>, Option::LRU_CACHE> tester{ log_copy.info(), max_duration };
    tester.check(result);
184 185
    // If structure is not linearizabile break run using assertion
    assert(result.is_timeout() || result.is_linearizable());
lucapegolotti committed
186 187 188 189 190 191
  }
  end = std::chrono::system_clock::now();
  seconds = std::chrono::duration_cast<std::chrono::seconds>(end - start);
  std::cout << "History length: " << number_of_entries
    << ", elapsed time:  "
    << seconds.count() << " s " << std::endl;
192 193 194 195
}


int main()
lucapegolotti committed
196
{  
197

198
  // Test functions and structures in linearizability_tester.h and sequential_data_structures.h
199 200 201 202
  run_tests();
  embb::base::Thread::SetThreadsMaxCount(255);
  
  std::cout << "Linearizability test on LockFreeMPMCQueue" << std::endl;
203
  embb_experiment_queue<embb::containers::LockFreeMPMCQueue<char>>();
204 205

  std::cout << "Linearizability test on LockFreeStack" << std::endl;
206
  embb_experiment_stack<embb::containers::LockFreeStack<char>>();
207 208 209
  return 0;
}