From 3b1e71ee7d464ae9d8eda1ad2a517a877163c79c Mon Sep 17 00:00:00 2001 From: metlos Date: Tue, 18 Mar 2008 01:41:29 +0000 Subject: [PATCH] Revert "invocation_token now uses proper boost::recursive_mutex'es to lock access" This reverts commit eb3e5fdb48f1eb116f3130ef6517e682ec812e88. --- beacon.kdevelop | 32 +-- beacon.kdevelop.filelist | 2 - beacon/detail/signal_base.cpp | 6 +- beacon/event_queue.cpp | 3 +- beacon/fast_signal.hpp | 10 +- beacon/invokable.hpp | 32 +-- fast_signal_test.cpp | 580 +++++++++++++++++++-------------------- test/performance_test.hpp | 171 ------------ test/performance_test_output.hpp | 265 ------------------ 9 files changed, 327 insertions(+), 774 deletions(-) rewrite fast_signal_test.cpp (62%) delete mode 100644 test/performance_test.hpp delete mode 100644 test/performance_test_output.hpp diff --git a/beacon.kdevelop b/beacon.kdevelop index 588fa0f..0b504cf 100644 --- a/beacon.kdevelop +++ b/beacon.kdevelop @@ -14,7 +14,7 @@ beacon Thread safe signals and slots library inspired by boost::signals and Qt signals and slots. - + /home/metlos/projects/cpp/beacon @@ -22,11 +22,11 @@ /home/metlos/projects/cpp/beacon/fast-signal-test custom /home/metlos/projects/cpp/beacon - + false true - -i 10 -e 2 -s 10 -r 10 -l 1 -m 10 -o pmin,pavg,pmax + /home/metlos/projects/cpp/beacon false false @@ -40,14 +40,14 @@ false 1 false - + default 0 - - + + *.java @@ -71,9 +71,9 @@ 0 - - - + + + default @@ -82,7 +82,7 @@ - + @@ -148,7 +148,7 @@ - + set m_,_ theValue @@ -190,11 +190,11 @@ - - - - - + + + + + true false false diff --git a/beacon.kdevelop.filelist b/beacon.kdevelop.filelist index e345c24..3a3e707 100644 --- a/beacon.kdevelop.filelist +++ b/beacon.kdevelop.filelist @@ -36,5 +36,3 @@ test/fastsig test/fastsig/fastsig.hpp test/fastsig/fastsig_common.hpp test/fastsig/fastsig_iter.hpp -test/performance_test.hpp -test/performance_test_output.hpp diff --git a/beacon/detail/signal_base.cpp b/beacon/detail/signal_base.cpp index 480e8ff..df50011 100644 --- a/beacon/detail/signal_base.cpp +++ b/beacon/detail/signal_base.cpp @@ -13,9 +13,11 @@ namespace detail { //a helper function to signal_base::do_disconnect and signal_base::clear void invalidate_slot(signal_base::slot_list_type::iterator & pos) { - invokable::token_ptr token = pos->connection->token(); - token->invalidate(); if (pos->queue != 0) { + invokable::token_ptr token = pos->connection->token(); + token->lock(); + token->invalidate(); + token->unlock(); pos->queue->dequeue(token); } } diff --git a/beacon/event_queue.cpp b/beacon/event_queue.cpp index 5c82c5a..0e88fcd 100644 --- a/beacon/event_queue.cpp +++ b/beacon/event_queue.cpp @@ -21,12 +21,13 @@ void invoke_and_delete(event_queue::ev_ptr inv) { try { invokable::token_ptr const & token = inv->token(); - invokable::token_type::lock_t lock(token->guard()); + token->lock(); if (token->valid()) { inv->invoke(); } + token->unlock(); } catch (...) { //TODO figure out what to do here } diff --git a/beacon/fast_signal.hpp b/beacon/fast_signal.hpp index 59a88ed..4c07eee 100644 --- a/beacon/fast_signal.hpp +++ b/beacon/fast_signal.hpp @@ -98,9 +98,13 @@ class FAST_SIGNAL_IMPL_N : public detail::signal_impl::call(*(it->queue), *slot, con->token()) (BOOST_PP_ENUM_PARAMS(n, arg)); } else { - invokable::token_type::lock_t lock(con->token()->guard()); - - (*slot)(BOOST_PP_ENUM_PARAMS(n, arg)); + //no need to lock the token here because + //we just need to check whether it is valid. + //the slot cannot be destroyed by other threads + //because we hold a shared ptr to it (in iterator). + if (con->token()->valid()) { + (*slot)(BOOST_PP_ENUM_PARAMS(n, arg)); + } } } } diff --git a/beacon/invokable.hpp b/beacon/invokable.hpp index 6655fcb..f4007be 100644 --- a/beacon/invokable.hpp +++ b/beacon/invokable.hpp @@ -11,8 +11,6 @@ #include #include -#include - extern "C" { #include } @@ -22,18 +20,22 @@ namespace beacon { /** * This class represents the token that identifies an invokable in * \a event_loop::dequeue. + *

+ * There is a very quick and dirty support for locking the access to the + * token. Each pair (or more) of parties interested in having exclusive + * access to this token must enclose the "critical section" with calls + * to \a lock and \a unlock methods. */ class invocation_token : public reference_countable { public: - /** The type of the lock for the \a guard. */ - typedef boost::recursive_mutex::scoped_lock lock_t; - - invocation_token(bool valid = true) : _valid(valid) { + invocation_token(bool valid = true) : _valid(valid), _guard(AO_TS_INITIALIZER) { } ~invocation_token() { + //TODO is this safe? + detail::notify(_guard); } /** @@ -47,29 +49,28 @@ class invocation_token : public reference_countable { /** * This causes the \a valid method to return false, indicating that * the invokable accompanied by this token is no longer valid. - * The guard is locked during the method invocation. */ void invalidate() { - lock_t l(_guard); _valid = false; } /** - * The guard can be used to lock access to the token. + * Locks access to the token. See the class comment for further details. */ - boost::recursive_mutex const & guard() const { - return _guard; + void lock() { + detail::wait(_guard); } /** - * The guard can be used to lock access to the token. + * Unlocks the access to this token. See the class comment for further + * details. */ - boost::recursive_mutex & guard() { - return _guard; + void unlock() { + detail::notify(_guard); } private: bool _valid; - boost::recursive_mutex _guard; + AO_TS_t _guard; }; /** @@ -80,7 +81,6 @@ class invokable { public: typedef intrusive_ptr token_ptr; - typedef invocation_token token_type; /** * Creates new instance of an invokable object. diff --git a/fast_signal_test.cpp b/fast_signal_test.cpp dissimilarity index 62% index 82cf74a..583e3fc 100644 --- a/fast_signal_test.cpp +++ b/fast_signal_test.cpp @@ -1,298 +1,282 @@ -/** - * beacon - * Author: Lukas Krejci , (C) 2008 - * Copyright: See COPYING file that comes with this distribution - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include - -size_t nof_event_loops = 0; -size_t nof_signals = 0; -size_t min_threads = 1; -size_t max_threads = 1; -size_t nof_loops = 0; -size_t test_runs = 0; - -std::vector event_loops; -std::vector *> signals; - -//payload function -void fn() { - boost::thread cur_thread; - boost::xtime now; - boost::xtime_get(&now, boost::TIME_UTC); - - now.nsec += 1e4; - if (now.nsec < 0) { - now.sec += 1; - now.nsec -= 1e4; - } - - cur_thread.sleep(now); -} - -// -//intializers -// - -void connect_all_signals_no_event_loop() { - for(size_t i = 0; i < nof_signals; ++i) { - signals[i]->connect(&fn); - } -} - -void disconnect_all_signals() { - for(size_t i = 0; i < nof_signals; ++i) { - signals[i]->clear(); - } -} - -void connect_all_signals_first_event_loop() { - for(size_t i = 0; i < nof_signals; ++i) { - signals[i]->connect(&fn, *event_loops[0]); - } -} - -void connect_all_signals_event_loops() { - for(size_t i = 0; i < nof_signals; ++i) { - int el_idx = rand() % nof_event_loops; - signals[i]->connect(&fn, *event_loops[el_idx]); - } -} - -void start_first_event_loop_no_signals() { - event_loops[0]->start(); -} - -void stop_first_event_loop_no_signals() { - event_loops[0]->join(); -} - -void start_all_event_loops_no_signals() { - for(size_t i = 0; i < nof_event_loops; ++i) { - event_loops[i]->start(); - } -} - -void stop_all_event_loops_no_signals() { - for(size_t i = 0; i < nof_event_loops; ++i) { - event_loops[i]->join(); - } -} - -void start_first_event_loop() { - connect_all_signals_first_event_loop(); - event_loops[0]->start(); -} - -void stop_first_event_loop() { - event_loops[0]->join(); - disconnect_all_signals(); -} - -void start_all_event_loops() { - connect_all_signals_event_loops(); - for(size_t i = 0; i < nof_event_loops; ++i) { - event_loops[i]->start(); - } -} - -void stop_all_event_loops() { - for(size_t i = 0; i < nof_event_loops; ++i) { - event_loops[i]->join(); - } - disconnect_all_signals(); -} - -// -//tests -// - -void boost_signal() { - boost::signal sig; - - sig.connect(&fn); - - for(size_t i = 0; i < nof_loops; ++i) { - sig(); - } -} - -void fastsig_signal() { - fastsig::signal sig; - - sig.connect(&fn); - - for(size_t i = 0; i < nof_loops; ++i) { - sig(); - } -} - -void fast_signal_no_event_loop() { - beacon::fast_signal sig; - - sig.connect(&fn); - - for(size_t i = 0; i < nof_loops; ++i) { - sig(); - } -} - -void all_fast_signals() { - for(size_t i = 0; i < nof_loops; ++i) { - int sig_idx = rand() % nof_signals; - (*signals[sig_idx])(); - } -} - -void one_fast_signal() { - beacon::fast_signal & sig = *signals[0]; - for(size_t i = 0; i < nof_loops; ++i) { - sig(); - } -} - -void short_lived_fast_signal_one_event_loop() { - beacon::fast_signal sig; - - sig.connect(&fn, *event_loops[0]); - - for(size_t i = 0; i < nof_loops; ++i) { - sig(); - } -} - -void short_lived_fast_signal_event_loops() { - beacon::fast_signal sig; - - int el_i = rand() % nof_event_loops; - - sig.connect(&fn, *event_loops[el_i]); - - for(size_t i = 0; i < nof_loops; ++i) { - sig(); - } -} - -void usage() { - std::cout << "-h --help this text" << std::endl - << "-i --signal-invocations how many times to invoke a signal in each test" << std::endl - << "-e --event-loops how many event loops to start and use" << std::endl - << "-s --signals how many signals to define and use" << std::endl - << "-r --test-runs the number of test runs" << std::endl - << "-l --min-threads the minimum number of threads to run the tests in (>=1)" << std::endl - << "-m --max-threads the maximum number of threads to run the tests in" << std::endl - << "-o --output pmin, pavg, pmax, omin, oavg, omax" << std::endl; -} - -int main(int argc, char * argv[]) { - - const char * short_opts = "hi:e:s:r:l:m:o:"; - const struct option long_opts[] = { - {"help", 0, NULL, 'h'}, - {"signal-invocations", 1, NULL, 'i'}, - {"event-loops", 1, NULL, 'e'}, - {"signals", 1, NULL, 's'}, - {"test-runs", 1, NULL, 'r'}, - {"min-threads", 1, NULL, 'l'}, - {"max-threads", 1, NULL, 'm'}, - {"output", 1, NULL, 'o'} - }; - - int opt; - - bool pmin = false, pavg = false, pmax = false, omin = false, oavg = true, omax = false; - - do { - opt = getopt_long(argc, argv, short_opts, long_opts, NULL); - switch (opt) { - case 'h': - usage(); - return 0; - case 'i': - nof_loops = atoi(optarg); - break; - case 'e': - nof_event_loops = atoi(optarg); - break; - case 's': - nof_signals = atoi(optarg); - break; - case 'r': - test_runs = atoi(optarg); - break; - case 'l': - min_threads = atoi(optarg); - break; - case 'm': - max_threads = atoi(optarg); - break; - case 'o': - std::string arg(optarg); - pmin = arg.find("pmin") != std::string::npos; - pavg = arg.find("pavg") != std::string::npos; - pmax = arg.find("pmax") != std::string::npos; - omin = arg.find("omin") != std::string::npos; - oavg = arg.find("oavg") != std::string::npos; - omax = arg.find("omax") != std::string::npos; - break; - } - } while (opt != -1); - - for(size_t i = 0; i < nof_event_loops; ++i) { - event_loops.push_back(new beacon::event_loop); - } - - for(size_t i = 0; i < nof_signals; ++i) { - signals.push_back(new beacon::fast_signal); - } - - beacon::test::performance_test pt; - pt.runs(test_runs); - pt.min_threads(min_threads); - pt.max_threads(max_threads); - - pt.add_test("boost::signal", 0, boost_signal, 0); - pt.add_test("fastsig::signal", 0, fastsig_signal, 0); - pt.add_test("fast_signal no event loop", 0, fast_signal_no_event_loop, 0); - pt.add_test("fast_signal one event loop", start_first_event_loop, one_fast_signal, stop_first_event_loop); - pt.add_test("fast_signal all event loops", start_all_event_loops, all_fast_signals, stop_all_event_loops); -// pt.add_test("short lived fast_sginal one event loop", start_first_event_loop_no_signals, short_lived_fast_signal_one_event_loop, stop_first_event_loop_no_signals); -// pt.add_test("short lived fast_signal all event loops", start_all_event_loops_no_signals, short_lived_fast_signal_event_loops, stop_all_event_loops_no_signals); - - beacon::test::performance_test_csv_output out(pt.run()); - out.output_payload_min(pmin); - out.output_payload_avg(pavg); - out.output_payload_max(pmax); - out.output_overall_min(omin); - out.output_overall_avg(oavg); - out.output_overall_max(omax); - - std::cout << out; - - for(size_t i = 0; i < nof_event_loops; ++i) { - delete event_loops[i]; - } - - for(size_t i = 0; i < nof_signals; ++i) { - delete signals[i]; - } - - return 0; -} +/** + * beacon + * Author: Lukas Krejci , (C) 2008 + * Copyright: See COPYING file that comes with this distribution + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +size_t const nof_event_loops = 4; +size_t const nof_signals = 10; +size_t const nof_threads = 10; + +beacon::event_loop event_loops[nof_event_loops]; +beacon::fast_signal signals[nof_signals]; + +size_t nof_loops = 10000; +size_t test_runs = 10; + +//payload function +void fn() { + boost::thread cur_thread; + boost::xtime now; + boost::xtime_get(&now, boost::TIME_UTC); + + now.nsec += 1e4; + if (now.nsec < 0) { + now.sec += 1; + now.nsec -= 1e4; + } + + cur_thread.sleep(now); +} + +//test runner +void run_test(char const * name, size_t runs, size_t const nof_threads, void(* setup)(), void(* payload)(), void( * teardown)()) { + + double test_sum_time = 0; + double overall_sum_time = 0; + for(size_t run = 0; run < runs; ++run) { + boost::xtime overall_start, test_start, overall_end, test_end; + + boost::xtime_get(&overall_start, boost::TIME_UTC); + + if (setup != 0) { + setup(); + } + + boost::thread_group tg; + + boost::xtime_get(&test_start, boost::TIME_UTC); + + for(size_t i = 1; i < nof_threads; ++i) { + tg.create_thread(payload); + } + + payload(); + + tg.join_all(); + + boost::xtime_get(&test_end, boost::TIME_UTC); + + if (teardown != 0) { + teardown(); + } + + boost::xtime_get(&overall_end, boost::TIME_UTC); + + test_sum_time += test_end.sec - test_start.sec + (test_end.nsec - test_start.nsec) / 1e9; + overall_sum_time += overall_end.sec - overall_start.sec + (overall_end.nsec - overall_start.nsec) / 1e9; + } + std::cout << name << " (" << nof_threads << " threads) avg. time: " << + (test_sum_time / runs) << "/" << (overall_sum_time / runs) << " in " << runs << " runs." << std::endl; +} + +// +//intializers +// + +void connect_all_signals_no_event_loop() { + for(size_t i = 0; i < nof_signals; ++i) { + signals[i].connect(&fn); + } +} + +void disconnect_all_signals() { + for(size_t i = 0; i < nof_signals; ++i) { + signals[i].clear(); + } +} + +void connect_all_signals_first_event_loop() { + for(size_t i = 0; i < nof_signals; ++i) { + signals[i].connect(&fn, event_loops[0]); + } +} + +void connect_all_signals_event_loops() { + for(size_t i = 0; i < nof_signals; ++i) { + int el_idx = rand() % nof_event_loops; + signals[i].connect(&fn, event_loops[el_idx]); + } +} + +void start_first_event_loop_no_signals() { + event_loops[0].start(); +} + +void stop_first_event_loop_no_signals() { + event_loops[0].join(); +} + +void start_all_event_loops_no_signals() { + for(size_t i = 0; i < nof_event_loops; ++i) { + event_loops[i].start(); + } +} + +void stop_all_event_loops_no_signals() { + for(size_t i = 0; i < nof_event_loops; ++i) { + event_loops[i].join(); + } +} + +void start_first_event_loop() { + connect_all_signals_first_event_loop(); + event_loops[0].start(); +} + +void stop_first_event_loop() { + event_loops[0].join(); + disconnect_all_signals(); +} + +void start_all_event_loops() { + connect_all_signals_event_loops(); + for(size_t i = 0; i < nof_event_loops; ++i) { + event_loops[i].start(); + } +} + +void stop_all_event_loops() { + for(size_t i = 0; i < nof_event_loops; ++i) { + event_loops[i].join(); + } + disconnect_all_signals(); +} + +// +//tests +// + +void boost_signal() { + boost::signal sig; + + sig.connect(&fn); + + for(size_t i = 0; i < nof_loops; ++i) { + sig(); + } +} + +void fastsig_signal() { + fastsig::signal sig; + + sig.connect(&fn); + + for(size_t i = 0; i < nof_loops; ++i) { + sig(); + } +} + +void fast_signal_no_event_loop() { + beacon::fast_signal sig; + + sig.connect(&fn); + + for(size_t i = 0; i < nof_loops; ++i) { + sig(); + } +} + +void all_fast_signals() { + for(size_t i = 0; i < nof_loops; ++i) { + int sig_idx = rand() % nof_signals; + signals[sig_idx](); + } +} + +void one_fast_signal() { + beacon::fast_signal & sig = signals[0]; + for(size_t i = 0; i < nof_loops; ++i) { + sig(); + } +} + +void short_lived_fast_signal_one_event_loop() { + beacon::fast_signal sig; + + sig.connect(&fn, event_loops[0]); + + for(size_t i = 0; i < nof_loops; ++i) { + sig(); + } +} + +void short_lived_fast_signal_event_loops() { + beacon::fast_signal sig; + + int el_i = rand() % nof_event_loops; + + sig.connect(&fn, event_loops[el_i]); + + for(size_t i = 0; i < nof_loops; ++i) { + sig(); + } +} + +int main(int argc, char * argv[]) { + + for(size_t threads = 1; threads < nof_threads; ++threads) { + run_test("boost::signal", + test_runs, + threads, + 0, + boost_signal, + 0); + + run_test("fastsig::signal", + test_runs, + threads, + 0, + fastsig_signal, + 0); + + run_test("fast_signal no event loop", + test_runs, + threads, + 0, + fast_signal_no_event_loop, + 0); + + run_test("fast_signal one event loop", + test_runs, + threads, + start_first_event_loop, + one_fast_signal, + stop_first_event_loop); + + run_test("fast_signals all event loops", + test_runs, + threads, + start_all_event_loops, + all_fast_signals, + stop_all_event_loops); + + run_test("short lived fast_signal one event loop", + test_runs, + threads, + start_first_event_loop_no_signals, + short_lived_fast_signal_one_event_loop, + stop_first_event_loop_no_signals); + + run_test("short lived fast_signal all event loops", + test_runs, + threads, + start_all_event_loops_no_signals, + short_lived_fast_signal_event_loops, + stop_all_event_loops_no_signals); + } + + return 0; +} diff --git a/test/performance_test.hpp b/test/performance_test.hpp deleted file mode 100644 index aadd800..0000000 --- a/test/performance_test.hpp +++ /dev/null @@ -1,171 +0,0 @@ -/** - * beacon - * Author: Lukas Krejci , (C) 2008 - * Copyright: See COPYING file that comes with this distribution - */ - -#ifndef BEACON_performance_test_H -#define BEACON_performance_test_H - -#include -#include -#include -#include - -namespace beacon { - -namespace test { - -struct test_run_result { - double payload_min; - double payload_max; - double payload_avg; - double overall_min; - double overall_max; - double overall_avg; -}; - -struct test_result { - std::string name; - std::list > thread_results; -}; - -struct test_setup { - std::string name; - void (* setup_fn)(); - void (* payload_fn)(); - void (* teardown_fn)(); - - test_setup() : setup_fn(0), payload_fn(0), teardown_fn(0) {} -}; - -class performance_test { - - public: - - size_t runs() const { - return _runs; - } - - void runs(size_t const & val) { - _runs = val; - } - - size_t min_threads() const { - return _min_threads; - } - - void min_threads(size_t const & val) { - _min_threads = val; - } - - size_t max_threads() const { - return _max_threads; - } - - void max_threads(size_t const & val) { - _max_threads = val; - } - - void add_test(std::string name, void(* setup)(), void(* payload)(), void( * teardown)()) { - test_setup set; - set.name = name; - set.setup_fn = setup; - set.payload_fn = payload; - set.teardown_fn = teardown; - _tests.push_back(set); - } - - std::list run() { - std::list results; - - for(std::list::iterator it = _tests.begin(); it != _tests.end(); ++it) { - test_setup & test = *it; - - test_result result; - result.name = test.name; - - for(size_t nof_threads = _min_threads; nof_threads <= _max_threads; ++nof_threads) { - result.thread_results.push_back( - make_pair(nof_threads, run_test(test, _runs, nof_threads))); - } - - results.push_back(result); - } - - return results; - } - private: - - test_run_result run_test(test_setup & setup, size_t const & runs, size_t const & nof_threads) { - double test_sum_time = 0; - double test_min_time = 0; - double test_max_time = 0; - double overall_sum_time = 0; - double overall_min_time = 0; - double overall_max_time = 0; - - for(size_t run = 0; run < runs; ++run) { - boost::xtime overall_start, test_start, overall_end, test_end; - - boost::xtime_get(&overall_start, boost::TIME_UTC); - - if (setup.setup_fn != 0) { - setup.setup_fn(); - } - - boost::thread_group tg; - - boost::xtime_get(&test_start, boost::TIME_UTC); - - for(size_t i = 1; i < nof_threads; ++i) { - tg.create_thread(setup.payload_fn); - } - - setup.payload_fn(); - - tg.join_all(); - - boost::xtime_get(&test_end, boost::TIME_UTC); - - if (setup.teardown_fn != 0) { - setup.teardown_fn(); - } - - boost::xtime_get(&overall_end, boost::TIME_UTC); - - double test_time = test_end.sec - test_start.sec + (test_end.nsec - test_start.nsec) / 1e9; - double overall_time = overall_end.sec - overall_start.sec + (overall_end.nsec - overall_start.nsec) / 1e9; - - test_sum_time += test_time; - overall_sum_time += overall_time; - - test_min_time = test_min_time == 0 ? test_time : (test_min_time < test_time ? test_min_time : test_time); - test_max_time = test_max_time < test_time ? test_time : test_max_time; - - overall_min_time = overall_min_time == 0 ? overall_time : (overall_min_time < overall_time ? overall_min_time : overall_time); - overall_max_time = overall_max_time < overall_time ? overall_time : overall_max_time; - } - - test_run_result result; - result.payload_min = test_min_time; - result.payload_max = test_max_time; - result.payload_avg = test_sum_time / runs; - result.overall_min = overall_min_time; - result.overall_max = overall_max_time; - result.overall_avg = overall_sum_time / runs; - - return result; - } - - std::list _tests; - size_t _runs; - size_t _min_threads; - size_t _max_threads; -}; - -} //namespace test - -} //namespace beacon - -#endif diff --git a/test/performance_test_output.hpp b/test/performance_test_output.hpp deleted file mode 100644 index eeb23f7..0000000 --- a/test/performance_test_output.hpp +++ /dev/null @@ -1,265 +0,0 @@ -/** - * beacon - * Author: Lukas Krejci , (C) 2008 - * Copyright: See COPYING file that comes with this distribution - */ - -#ifndef BEACON_performance_test_output_H -#define BEACON_performance_test_output_H - -#include - -#include -#include - -namespace beacon { - -namespace test { - -class performance_test_csv_output { - template - friend std::basic_ostream & operator <<(std::basic_ostream &, performance_test_csv_output const &); - - public: - performance_test_csv_output(std::list const & results) : - _output_payload_min(true), - _output_payload_max(true), - _output_payload_avg(true), - _output_overall_min(true), - _output_overall_max(true), - _output_overall_avg(true), - _results(results) {} - - void output_payload_min(bool theValue) { - _output_payload_min = theValue; - } - - bool output_payload_min() const { - return _output_payload_min; - } - - void output_payload_max(bool theValue) { - _output_payload_max = theValue; - } - - bool output_payload_max() const { - return _output_payload_max; - } - - void output_payload_avg(bool theValue) { - _output_payload_avg = theValue; - } - - bool output_payload_avg() const { - return _output_payload_avg; - } - - void output_overall_min(bool theValue) { - _output_overall_min = theValue; - } - - bool output_overall_min() const { - return _output_overall_min; - } - - void output_overall_max(bool theValue) { - _output_overall_max = theValue; - } - - bool output_overall_max() const { - return _output_overall_max; - } - - void output_overall_avg(bool theValue) { - _output_overall_avg = theValue; - } - - bool output_overall_avg() const { - return _output_overall_avg; - } - - private: - bool _output_payload_min; - bool _output_payload_max; - bool _output_payload_avg; - bool _output_overall_min; - bool _output_overall_max; - bool _output_overall_avg; - std::list _results; -}; - -template -std::basic_ostream & operator <<(std::basic_ostream & str, performance_test_csv_output const & out) { - size_t nof_columns = 0; - if (out.output_payload_min()) nof_columns++; - if (out.output_payload_max()) nof_columns++; - if (out.output_payload_avg()) nof_columns++; - if (out.output_overall_min()) nof_columns++; - if (out.output_overall_max()) nof_columns++; - if (out.output_overall_avg()) nof_columns++; - - if (nof_columns == 0) return str; //nothing to show - - //the list of iterators over each test results - std::list >::const_iterator> result_iterators; - - std::list >::const_iterator last_result = out._results.front().thread_results.end(); - - //output the header - str << "\"Threads\","; - - std::list::const_iterator last_item = --out._results.end(); - for(std::list::const_iterator it = out._results.begin(); it != last_item; - ++it) { - str << "\"" << it->name << "\""; - for(size_t i = 0; i < nof_columns; ++i) { - str << ","; - } - - std::list >::const_iterator result_it = it->thread_results.begin(); - - result_iterators.push_back(result_it); - } - - str << "\"" << last_item->name << "\""; - for(size_t i = 0; i < nof_columns; ++i) { - str << ","; - } - str << std::endl; - - //output individual column headers - str << ","; - for(std::list::const_iterator it = out._results.begin(); it != last_item; - ++it) { - - if (out.output_payload_min()) { - str << "payload min,"; - } - if (out.output_payload_avg()) { - str << "payload avg,"; - } - if (out.output_payload_max()) { - str << "payload max,"; - } - if (out.output_overall_min()) { - str << "overall min,"; - } - if (out.output_overall_avg()) { - str << "overall avg,"; - } - if (out.output_overall_max()) { - str << "overall max,"; - } - } - - size_t left_to_do = nof_columns; - if (out.output_payload_min()) { - str << "payload min"; - if (--left_to_do > 0) str << ","; - } - if (out.output_payload_avg()) { - str << "payload avg"; - if (--left_to_do > 0) str << ","; - } - if (out.output_payload_max()) { - str << "payload max"; - if (--left_to_do > 0) str << ","; - } - if (out.output_overall_min()) { - str << "overall min"; - if (--left_to_do > 0) str << ","; - } - if (out.output_overall_avg()) { - str << "overall avg"; - if (--left_to_do > 0) str << ","; - } - if (out.output_overall_max()) { - str << "overall max"; - if (--left_to_do > 0) str << ","; - } - str << std::endl; - - std::list >::const_iterator result_it = last_item->thread_results.begin(); - result_iterators.push_back(result_it); - - //output the data - std::list >::const_iterator>::const_iterator last_result_item = --result_iterators.end(); - bool more_data = true; - while(more_data) { - //output the current number of threads - str << result_iterators.front()->first << ","; - - for(std::list >::const_iterator>::const_iterator it = result_iterators.begin(); - it != last_result_item; ++it) { - - test_run_result trr = (*it)->second; - - if (out.output_payload_min()) { - str << trr.payload_min << ","; - } - if (out.output_payload_avg()) { - str << trr.payload_avg << ","; - } - if (out.output_payload_max()) { - str << trr.payload_max << ","; - } - if (out.output_overall_min()) { - str << trr.overall_min << ","; - } - if (out.output_overall_avg()) { - str << trr.overall_avg << ","; - } - if (out.output_overall_max()) { - str << trr.overall_max << ","; - } - - //advance the current result iterator; - std::list >::const_iterator & res_it = - const_cast >::const_iterator &>(*it); - ++res_it; - } - - test_run_result trr = (*last_result_item)->second; - size_t left_to_do = nof_columns; - if (out.output_payload_min()) { - str << trr.payload_min; - if (--left_to_do > 0) str << ","; - } - if (out.output_payload_avg()) { - str << trr.payload_avg; - if (--left_to_do > 0) str << ","; - } - if (out.output_payload_max()) { - str << trr.payload_max; - if (--left_to_do > 0) str << ","; - } - if (out.output_overall_min()) { - str << trr.overall_min; - if (--left_to_do > 0) str << ","; - } - if (out.output_overall_avg()) { - str << trr.overall_avg; - if (--left_to_do > 0) str << ","; - } - if (out.output_overall_max()) { - str << trr.overall_max; - if (--left_to_do > 0) str << ","; - } - str << std::endl; - - std::list >::const_iterator & res_it = - const_cast >::const_iterator &>(*last_result_item); - ++res_it; - - //check if there's more data - more_data = result_iterators.front() != last_result; - } - - return str; -} - -} //namespace test - -} //namespace beacon - -#endif -- 2.11.4.GIT