patterns_test.cpp 2.77 KB
Newer Older
1 2 3
#include <catch.hpp>

#include <atomic>
4
#include <thread>
5 6 7 8 9 10

#include "pls/pls.h"

constexpr int MAX_NUM_TASKS = 32;
constexpr int MAX_STACK_SIZE = 1024 * 8;

11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
TEST_CASE("spawn/sync invoke calls correctly", "[algorithms/invoke.h]") {
  pls::scheduler scheduler{3, MAX_NUM_TASKS, MAX_STACK_SIZE};

  std::atomic<int> num_run{0};
  scheduler.perform_work([&] {
    pls::spawn([&] {
      num_run++;
      while (num_run < 3);
    });
    pls::spawn([&] {
      while (num_run < 1);
      num_run++;
      while (num_run < 3);
    });
    pls::spawn([&] {
      while (num_run < 2);
      num_run++;
    });
    pls::sync();
    REQUIRE(num_run == 3);
  });
}

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
TEST_CASE("parallel invoke calls correctly", "[algorithms/invoke.h]") {
  pls::scheduler scheduler{3, MAX_NUM_TASKS, MAX_STACK_SIZE};

  std::atomic<int> num_run{0};
  scheduler.perform_work([&] {
    pls::invoke([&] {
      num_run++;
      while (num_run < 3);
    }, [&] {
      while (num_run < 1);
      num_run++;
      while (num_run < 3);
    }, [&] {
      while (num_run < 2);
      num_run++;
    });
    REQUIRE(num_run == 3);
  });
}
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

TEST_CASE("parallel for calls correctly (might fail, timing based)", "[algorithms/for_each.h]") {
  pls::scheduler scheduler{8, MAX_NUM_TASKS, MAX_STACK_SIZE};

  auto start = std::chrono::steady_clock::now();
  std::atomic<int> work_done{0};
  scheduler.perform_work([&] {
    pls::for_each_range(0, 100, [&](const int) {
      work_done++;
      std::this_thread::sleep_for(std::chrono::milliseconds(1));
    });
  });
  auto end = std::chrono::steady_clock::now();
  auto elapsed =
      std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

  REQUIRE(work_done == 100);
  // It makes sense that 100 iterations on at least 4 threads take less than half the serial time.
  // We want to make sure that at least some work is distributed on multiple cores.
  REQUIRE(elapsed <= 50);
}

TEST_CASE("reduce calls correctly (might fail, timing based)", "[algorithms/for_each.h]") {
  pls::scheduler scheduler{8, MAX_NUM_TASKS, MAX_STACK_SIZE};

  auto start = std::chrono::steady_clock::now();
  int num_elements = 100;
  pls::range range{1, num_elements + 1};
  int result;
  scheduler.perform_work([&] {
    result = pls::reduce(range.begin(), range.end(), 0, [&](const int a, const int b) {
      std::this_thread::sleep_for(std::chrono::milliseconds(1));
      return a + b;
    });
  });
  auto end = std::chrono::steady_clock::now();
  auto elapsed =
      std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

  REQUIRE(result == (num_elements * (num_elements + 1)) / 2);
  // It makes sense that 100 iterations on at least 4 threads take less than half the serial time.
  // We want to make sure that at least some work is distributed on multiple cores.
  REQUIRE(elapsed <= 50);
}