diff options
Diffstat (limited to 'libbuild2/scheduler.test.cxx')
-rw-r--r-- | libbuild2/scheduler.test.cxx | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/libbuild2/scheduler.test.cxx b/libbuild2/scheduler.test.cxx new file mode 100644 index 0000000..1252575 --- /dev/null +++ b/libbuild2/scheduler.test.cxx @@ -0,0 +1,187 @@ +// file : libbuild2/scheduler.test.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <chrono> +#include <thread> + +#include <cassert> +#include <iostream> + +#include <libbuild2/types.hxx> +#include <libbuild2/utility.hxx> + +#include <libbuild2/scheduler.hxx> + +using namespace std; + +namespace build2 +{ + // Usage argv[0] [-v <volume>] [-d <difficulty>] [-c <concurrency>] + // [-q <queue-depth>] + // + // -v task tree volume (affects both depth and width), for example 100 + // -d computational difficulty of each task, for example 10 + // -c max active threads, if unspecified or 0, then hardware concurrency + // -q task queue depth, if unspecified or 0, then appropriate default used + // + // Specifying any option also turns on the verbose mode. + // + // Notes on testing: + // + // 1. Ideally you would want to test things on an SMP machine. + // + // 2. When need to compare performance, disable turbo boost since its + // availability depends on CPU utilization/temperature: + // + // # echo '1' >/sys/devices/system/cpu/intel_pstate/no_turbo + // + // 3. Use turbostat(1) to see per-CPU details (utlization, frequency): + // + // $ sudo turbostat --interval 1 ./driver -d 8 -v 300 + // + static bool + prime (uint64_t); + + // Find # of primes in the [x, y) range. + // + static void + inner (uint64_t x, uint64_t y, uint64_t& r) + { + for (; x != y; ++x) + if (prime (x)) + r++; + }; + + int + main (int argc, char* argv[]) + { + bool verb (false); + + // Adjust assert() below if changing these defaults. + // + size_t volume (100); + uint32_t difficulty (10); + + size_t max_active (0); + size_t queue_depth (0); + + for (int i (1); i != argc; ++i) + { + string a (argv[i]); + + if (a == "-v") + volume = stoul (argv[++i]); + else if (a == "-d") + difficulty = stoul (argv[++i]); + else if (a == "-c") + max_active = stoul (argv[++i]); + else if (a == "-q") + queue_depth = stoul (argv[++i]); + else + assert (false); + + verb = true; + } + + if (max_active == 0) + max_active = scheduler::hardware_concurrency (); + + scheduler s (max_active, 1, 0, queue_depth); + + // Find # prime counts of primes in [i, d*i*i) ranges for i in (0, n]. + // + auto outer = [difficulty, &s] (size_t n, vector<uint64_t>& o, uint64_t& r) + { + scheduler::atomic_count task_count (0); + + for (size_t i (1); i <= n; ++i) + { + o[i - 1] = 0; + s.async (task_count, + inner, + i, + i * i * difficulty, + ref (o[i - 1])); + } + + s.wait (task_count); + assert (task_count == 0); + + for (uint64_t v: o) + r += prime (v) ? 1 : 0; + }; + + vector<uint64_t> r (volume, 0); + vector<vector<uint64_t>> o (volume, vector<uint64_t> ()); + + scheduler::atomic_count task_count (0); + + for (size_t i (0); i != volume; ++i) + { + o[i].resize (i); + s.async (task_count, + outer, + i, + ref (o[i]), + ref (r[i])); + } + + s.wait (task_count); + assert (task_count == 0); + + uint64_t n (0); + for (uint64_t v: r) + n += v; + + if (volume == 100 && difficulty == 10) + assert (n == 580); + + scheduler::stat st (s.shutdown ()); + + if (verb) + { + cerr << "result " << n << endl + << endl; + + cerr << "thread_max_active " << st.thread_max_active << endl + << "thread_max_total " << st.thread_max_total << endl + << "thread_helpers " << st.thread_helpers << endl + << "thread_max_waiting " << st.thread_max_waiting << endl + << endl + << "task_queue_depth " << st.task_queue_depth << endl + << "task_queue_full " << st.task_queue_full << endl + << endl + << "wait_queue_slots " << st.wait_queue_slots << endl + << "wait_queue_collisions " << st.wait_queue_collisions << endl; + } + + return 0; + } + + static bool + prime (uint64_t x) + { + if (x == 2 || x == 3) + return true; + + if (x < 2 || x % 2 == 0 || x % 3 == 0) + return false; + + // Test divisors starting from 5 and incrementing alternatively by 2/4. + // + for (uint64_t d (5), i (2); d * d <= x; d += i, i = 6 - i) + { + if (x % d == 0) + return false; + } + + return true; + } +} + +int +main (int argc, char* argv[]) +{ + return build2::main (argc, argv); +} |