/* * Copyright 2015 Cloudius Systems */ #pragma once #include "core/print.hh" #include "core/future-util.hh" #include "core/distributed.hh" #include #include #include template static void time_it(Func func, int iterations = 5) { using clk = std::chrono::high_resolution_clock; for (int i = 0; i < iterations; i++) { auto start = clk::now(); auto end_at = start + std::chrono::seconds(1); uint64_t count = 0; while (clk::now() < end_at) { for (int i = 0; i < 10000; i++) { // amortize clock reading cost func(); count++; } } auto end = clk::now(); auto duration = std::chrono::duration(end - start).count(); std::cout << sprint("%.2f", (double)count / duration) << " tps\n"; } } template static future<> do_n_times(unsigned count, Func func) { struct wrapper { Func f; unsigned c; }; auto w = make_shared({std::move(func), count}); return do_until([w] { return w->c == 0; }, [w] { --w->c; return w->f(); }); } // Drives concurrent and continuous execution of given asynchronous action // until a deadline. Counts invocations. template class executor { const Func _func; const lowres_clock::time_point _end_at; const unsigned _n_workers; uint64_t _count; private: future<> run_worker() { return do_until([this] { return lowres_clock::now() >= _end_at; }, [this] () mutable { ++_count; return _func(); }); } public: executor(unsigned n_workers, Func func, lowres_clock::time_point end_at) : _func(std::move(func)) , _end_at(end_at) , _n_workers(n_workers) , _count(0) { } // Returns the number of invocations of @func future run() { auto idx = boost::irange(0, (int)_n_workers); return parallel_for_each(idx.begin(), idx.end(), [this] (auto idx) mutable { return this->run_worker(); }).then([this] { return _count; }); } future<> stop() { return make_ready_future<>(); } }; /** * Measures throughput of an asynchronous action. Executes the action on all cores * in parallel, with given number of concurrent executions per core. * * Runs many iterations. Prints partial total throughput after each iteraton. */ template static future<> time_parallel(Func func, unsigned concurrency_per_core, int iterations = 5) { using clk = std::chrono::high_resolution_clock; return do_n_times(iterations, [func, concurrency_per_core] { auto start = clk::now(); auto end_at = lowres_clock::now() + std::chrono::seconds(1); auto exec = ::make_shared>>(); return exec->start(concurrency_per_core, func, std::move(end_at)).then([exec] { return exec->map_reduce(adder(), [] (auto& oc) { return oc.run(); }); }).then([start] (auto total) { auto end = clk::now(); auto duration = std::chrono::duration(end - start).count(); std::cout << sprint("%.2f", (double)total / duration) << " tps\n"; }).then([exec] { return exec->stop().finally([exec] {}); }); }); }