diff --git a/src/lib/format-obj.cpp b/src/lib/format-obj.cpp index 5913f1f69..25eef525f 100644 --- a/src/lib/format-obj.cpp +++ b/src/lib/format-obj.cpp @@ -359,6 +359,17 @@ namespace util { { return FAILURE_INDICATOR; } + string + showSize (size_t val) noexcept + try { + ostringstream buffer; + buffer << val; + return buffer.str(); + } + catch(...) + { return FAILURE_INDICATOR; } + + /** @note show only the trailing X bytes of any address */ ostream& showAddr (ostream& stream, void const* addr) diff --git a/src/lib/format-obj.hpp b/src/lib/format-obj.hpp index 23486f000..562269e11 100644 --- a/src/lib/format-obj.hpp +++ b/src/lib/format-obj.hpp @@ -85,6 +85,7 @@ namespace util { std::string showDouble (double) noexcept; std::string showFloat (float) noexcept; + std::string showSize (size_t) noexcept; std::string showAddr (void const* addr) noexcept; /** preconfigured format for pretty-printing of addresses */ diff --git a/src/lib/typed-counter.hpp b/src/lib/typed-counter.hpp index fdd9100a7..12a9337e4 100644 --- a/src/lib/typed-counter.hpp +++ b/src/lib/typed-counter.hpp @@ -60,14 +60,19 @@ #include "lib/sync-classlock.hpp" #include +#include +namespace util { + std::string showSize (size_t) noexcept; +} namespace lib { typedef size_t IxID; //////////////////////TICKET #863 using std::vector; + using std::string; /** @@ -216,6 +221,23 @@ namespace lib { { return id_; } + + operator string() const + { + return util::showSize (this->id_); + } + + friend string + operator+ (string const& prefix, FamilyMember id) + { + return prefix+id; + } + + friend string + operator+ (const char* prefix, FamilyMember id) + { + return string(prefix)+id; + } }; /** allocate storage for the counter per type family */ diff --git a/tests/core/proc/control/session-command-function-test.cpp b/tests/core/proc/control/session-command-function-test.cpp index ca5dc936b..70d2b6a76 100644 --- a/tests/core/proc/control/session-command-function-test.cpp +++ b/tests/core/proc/control/session-command-function-test.cpp @@ -31,10 +31,14 @@ extern "C" { #include "proc/control/command-def.hpp" #include "gui/ctrl/command-handler.hpp" #include "gui/interact/invocation-trail.hpp" +#include "backend/thread-wrapper.hpp" +#include "lib/typed-counter.hpp" //#include "lib/format-cout.hpp" //////////TODO #include "lib/symbol.hpp" #include "lib/util.hpp" +#include +#include #include @@ -45,6 +49,7 @@ namespace test { // using std::function; // using std::rand; + using boost::lexical_cast; using lib::test::randTime; using gui::interact::InvocationTrail; using gui::ctrl::CommandHandler; @@ -54,13 +59,30 @@ namespace test { using lib::time::TimeVar; using lib::time::Duration; using lib::time::Offset; + using lib::time::FSecs; + using lib::FamilyMember; using lib::Symbol; using util::isnil; using std::string; + using std::vector; namespace { // test fixture... + /* === parameters for multi-threaded stress test === */ + + uint NUM_THREADS_DEFAULT = 20; ///< @note _not_ const, can be overridden by command line argument + uint NUM_INVOC_PER_THRED = 10; + uint MAX_RAND_DELAY_ms = 10; + + void + maybeOverride (uint& configSetting, Arg cmdline, uint paramNr) + { + if (paramNr < cmdline.size()) + configSetting = lexical_cast(cmdline[paramNr]); + } + + /* === mock operation to be dispatched as command === */ const Symbol COMMAND_ID{"test.dispatch.function.command"}; @@ -90,8 +112,7 @@ namespace test { }//(End) test fixture -// typedef shared_ptr PCommandImpl; -// typedef HandlingPattern const& HaPatt; + #define __DELAY__ usleep(10000); @@ -138,7 +159,7 @@ namespace test { virtual void - run (Arg) + run (Arg args_for_stresstest) { lumiera_interfaceregistry_init(); lumiera::throwOnError(); @@ -146,15 +167,15 @@ namespace test { startDispatcher(); perform_simpleInvocation(); perform_messageInvocation(); -// perform_massivelyParallel(); + perform_massivelyParallel(args_for_stresstest); stopDispatcher(); lumiera_interfaceregistry_destroy(); } - /** @test start the session loop thread, similar - * to what the »session subsystem« does + /** @test start the session loop thread, + * similar to what the »session subsystem« does * @note we are _not_ actually starting the subsystem * @see facade.cpp */ @@ -252,10 +273,79 @@ namespace test { * sequential calculation and summation */ void - perform_massivelyParallel() + perform_massivelyParallel(Arg args_for_stresstest) { - UNIMPLEMENTED ("verify sequentialisation by queue"); - } + maybeOverride(NUM_THREADS_DEFAULT, args_for_stresstest, 1); + maybeOverride(NUM_INVOC_PER_THRED, args_for_stresstest, 2); + maybeOverride(MAX_RAND_DELAY_ms, args_for_stresstest, 3); + + class InvocationProducer + : backend::ThreadJoinable + { + FamilyMember id_; + string id_buffer_{COMMAND_ID + ".thread-"+id_}; + Symbol cmdID_{cStr(id_buffer_)}; + + void + fabricateCommands() + { + syncPoint(); + InvocationTrail invoTrail{Command(cmdID_)}; + + for (uint i=0; isync(); + } + + ~InvocationProducer() + { + this->join().maybeThrow(); + Command::remove (cmdID_); + } + }; + + Time prevState = testCommandState; + + // fire up several threads to issue commands in parallel... + vector producerThreads{NUM_THREADS_DEFAULT}; + + + FSecs expectedOffset{0}; + for (uint i=0; i