From 29ca3a485feaf130f9e2bfa09be21122ab302ced Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 4 Dec 2023 16:29:57 +0100 Subject: [PATCH] Chain-Load: implement planning JobFunctor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - decided to abstract the scheduler invocations as λ - so this functor contains the bare loop logic Investigation regarding hash-framework: It turns out that boost::hash uses a different hash_combine, than what we have extracted/duplicated in lib/hash-value.hpp (either this was a mistake, or boost::hash did use this weaker function at that time and supplied a dedicated 64bit implementation later) Anyway, should use boost::hash for the time being maybe also fix the duplicated impl in lib/hash-value.hpp --- src/lib/hash-value.h | 31 ++++- src/vault/gear/job.h | 3 +- src/vault/gear/nop-job-functor.hpp | 5 +- tests/vault/gear/test-chain-load.hpp | 189 +++++++++++++++++++++------ wiki/thinkPad.ichthyo.mm | 103 ++++++++++++++- 5 files changed, 282 insertions(+), 49 deletions(-) diff --git a/src/lib/hash-value.h b/src/lib/hash-value.h index 57ea29d96..2e7e95f8a 100644 --- a/src/lib/hash-value.h +++ b/src/lib/hash-value.h @@ -75,7 +75,36 @@ namespace lib { + (combinedHash<<6) + (combinedHash>>2); } - + /////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #722 : Boost uses a stronger impl here on 64bit platforms + /// see: Boost 1.67 /boost/container_has/hash.hpp + /// + /* +// Don't define 64-bit hash combine on platforms without 64 bit integers, +// and also not for 32-bit gcc as it warns about the 64-bit constant. +#if !defined(BOOST_NO_INT64_T) && \ + !(defined(__GNUC__) && ULONG_MAX == 0xffffffff) + + inline void hash_combine_impl(boost::uint64_t& h, + boost::uint64_t k) + { + const boost::uint64_t m = UINT64_C(0xc6a4a7935bd1e995); + const int r = 47; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + + // Completely arbitrary number, to prevent 0's + // from hashing to 0. + h += 0xe6546b64; + } + +#endif // BOOST_NO_INT64_T + */ + // // WIP more utils to come here.... } diff --git a/src/vault/gear/job.h b/src/vault/gear/job.h index 2c7df501d..dde40cad4 100644 --- a/src/vault/gear/job.h +++ b/src/vault/gear/job.h @@ -72,7 +72,8 @@ enum JobKind { CALC_JOB, ///< calculating frame data, CPU bound LOAD_JOB, ///< accessing prerequisites, IO bound - META_JOB ///< render process self organisation + META_JOB, ///< render process self organisation + TEST_JOB ///< test and diagnostic and research }; enum JobPriority diff --git a/src/vault/gear/nop-job-functor.hpp b/src/vault/gear/nop-job-functor.hpp index d032c4768..98ac7c752 100644 --- a/src/vault/gear/nop-job-functor.hpp +++ b/src/vault/gear/nop-job-functor.hpp @@ -51,9 +51,8 @@ namespace gear { /** - * Stub implementation of the JobFunctor interface + * Stub/Test implementation of the JobFunctor interface * for a render job _to do nothing at all_ - * @todo WIP as of 4/2023 */ class NopJobFunctor : public JobClosure @@ -64,7 +63,7 @@ namespace gear { JobKind getJobKind() const { - return META_JOB; + return TEST_JOB; } std::string diff --git a/tests/vault/gear/test-chain-load.hpp b/tests/vault/gear/test-chain-load.hpp index 056605de2..764a5921a 100644 --- a/tests/vault/gear/test-chain-load.hpp +++ b/tests/vault/gear/test-chain-load.hpp @@ -27,7 +27,7 @@ ** characteristics of the implementation, a well-defined artificial computation load is ** necessary, comprised of the invocation of an extended number of Jobs, each configured ** to carry out a reproducible computation. Data dependencies between jobs can be established - ** to verify handling of dependent jobs and job completion messages within the scheduler. + ** to verify handling of dependent jobs and job completion messages within the scheduler. ** ** # Random computation structure ** A system of connected hash values is used as computation load, akin to a blockchain. @@ -83,9 +83,10 @@ #include "vault/common.hpp" #include "lib/test/transiently.hpp" +//#include "lib/hash-value.h" #include "vault/gear/job.h" //#include "vault/gear/activity.hpp" -#include "vault/gear/nop-job-functor.hpp" +//#include "vault/gear/nop-job-functor.hpp" #include "lib/time/timevalue.hpp" //#include "lib/meta/variadic-helper.hpp" //#include "lib/meta/function.hpp" @@ -114,9 +115,9 @@ namespace gear { namespace test { using std::string; -// using std::function; -// using lib::time::TimeValue; + using std::function; using lib::time::Time; + using lib::time::TimeValue; using lib::time::FrameRate; // using lib::time::FSecs; // using lib::time::Offset; @@ -132,11 +133,11 @@ namespace test { using lib::meta::_FunRet; using lib::test::Transiently; -// using std::forward; -// using std::string; + using std::forward; + using std::string; using std::swap; using std::move; - using boost::hash_combine; +// using boost::hash_combine; namespace dot = lib::dot_gen; @@ -241,9 +242,8 @@ namespace test { size_t calculate() { - for (Node*& entry: pred) - if (entry) - hash_combine (hash, entry->hash); + for (Node* entry: pred) + boost::hash_combine (hash, entry->hash); return hash; } @@ -735,7 +735,7 @@ namespace test { namespace { template inline auto - prepareEvaluaions() + prepareEvaluations() { return std::array, CAT> { [](NOD& ){ return 1; } @@ -893,7 +893,7 @@ namespace test { TestChainLoad::computeGraphStatistics() { auto totalLevels = uint(topLevel()); - auto classify = prepareEvaluaions(); + auto classify = prepareEvaluations(); Statistic stat(totalLevels); LevelSums particulars{0}; size_t level{0}, @@ -1009,46 +1009,46 @@ namespace test { /* ========= Render Job generation and Scheduling ========= */ - template - class RandomChainCalcFunctor - : public NopJobFunctor + /** + * Baseclass: JobFunctor to invoke TestChainLoad + */ + class ChainFunctor + : public JobClosure { - using Node = typename TestChainLoad::Node; - - Node* startNode_; static lib::time::Grid& - testGrid() ///< Meyer's Singleton : a fixed 1fps quantiser + testGrid() ///< Meyer's Singleton : a fixed 1-f/s quantiser { static lib::time::FixedFrameQuantiser gridOne{FrameRate::STEP}; return gridOne; } + /* === JobFunctor Interface === */ + + string diagnostic() const =0; + void invokeJobOperation (JobParameter) =0; + + JobKind + getJobKind() const + { + return TEST_JOB; + } + + InvocationInstanceID + buildInstanceID (HashVal) const override + { + return InvocationInstanceID(); + } + + size_t + hashOfInstance (InvocationInstanceID invoKey) const override + { + std::hash hashr; + HashVal res = hashr (invoKey.frameNumber); + return res; + } + public: - RandomChainCalcFunctor(Node& startNode) - : startNode_{&startNode} - { } - - - /** rigged special implementation of job invocation - */ - void - invokeJobOperation (JobParameter param) override - { - size_t nodeIdx = decodeNodeID (param.invoKey); - size_t level = decodeLevel (TimeValue{param.nominalTime}); - Node& target = startNode_[nodeIdx]; - ASSERT (target.level == level); - // invoke the »media calculation« - target.calculate(); - } - - string diagnostic() const override - { - return _Fmt{"ChainCalc(w:%d)▶%s"} - % maxFan - % util::showAddr(startNode_); - } /** package the node-index to invoke. * @note per convention for this test, this info will be @@ -1083,5 +1083,108 @@ namespace test { + /** + * Render JobFunctor to invoke the _calculation_ of a single Node. + * The existing Node connectivity is used to retrieve the hash values + * from predecessors — so these are expected to be calculated beforehand. + * For setup, the start of the ChainLoad's Node array is required. + * @tparam maxFan controls expected Node memory layout + */ + template + class RandomChainCalcFunctor + : public ChainFunctor + { + using Node = typename TestChainLoad::Node; + + Node* startNode_; + + public: + RandomChainCalcFunctor(Node& startNode) + : startNode_{&startNode} + { } + + + /** render job invocation to trigger one Node recalculation */ + void + invokeJobOperation (JobParameter param) override + { + size_t nodeIdx = decodeNodeID (param.invoKey); + size_t level = decodeLevel (TimeValue{param.nominalTime}); + Node& target = startNode_[nodeIdx]; + ASSERT (target.level == level); + // invoke the »media calculation« + target.calculate(); + } + + string diagnostic() const override + { + return _Fmt{"ChainCalc(w:%d)◀%s"} + % maxFan + % util::showAddr(startNode_); + } + }; + + + /** + * Render JobFunctor to perform chunk wise planning of Node jobs + * to calculate a complete Chain-Load graph step by step. + */ + template + class RandomChainPlanFunctor + : public ChainFunctor + { + using Node = typename TestChainLoad::Node; + + function scheduleCalcJob_; + function markDependency_; + function continuation_; + + size_t chunkSize_; + size_t maxCnt_; + + Node* nodes_; + size_t currIdx_{0}; + + public: + template + RandomChainPlanFunctor(size_t chunkSize, size_t maxLevel, + Node& nodeArray, + CAL&& schedule, DEP&& markDepend, + CON&& continuation) + : scheduleCalcJob_{forward (schedule)} + , markDependency_{forward (markDepend)} + , continuation_{continuation} + , chunkSize_{chunkSize} + , maxCnt_{maxLevel} + , nodes_{&nodeArray} + { } + + + /** render job invocation to trigger one Node recalculation */ + void + invokeJobOperation (JobParameter param) override + { + size_t targetLevel = decodeLevel (TimeValue{param.nominalTime}); + for ( ; currIdx_level > targetLevel) + break; + scheduleCalcJob_(currIdx_, n->level); + for (Node* pred: n.pred) + markDependency_(pred,n); + } + continuation_(targetLevel, currIdx_ < maxCnt_); + } + + + string diagnostic() const override + { + return "ChainPlan"; + } + }; + + + }}} // namespace vault::gear::test #endif /*VAULT_GEAR_TEST_TEST_CHAIN_LOAD_H*/ diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 60ea2d71a..2ae04b792 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -57667,6 +57667,70 @@ + + + + + + + + + + + + +

+ ein Grund ist: STDLIB ist umständlich und unvollständig... +

+
    +
  • + während Boost-functional-hash direkt per free-function (hash_value(x)) erweitert werden kann, muß man für die STDLIB-Variante immer den Namespace std aufmachen +
  • +
  • + Boost bietet automatisch bereits Hash-Spezialisierungen für alle erdenklichen Container, Tupel und sonstiges +
  • +
+ +
+ + + + + + + +

+ 12/2023  per Debugger verifiziert ⟶ TestChainLoad +

+ +
+
+
+
+ + + + + + + + + +

+ de-facto wird nur noch 64-bit entwickelt. Inzwischen habe ich einige Tests, bei denen ich Hash-Values direkt prüfe. Die würden auf 32bit alle brechen +

+ +
+ +
+
+ + + + + + @@ -100825,10 +100889,29 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + + + @@ -100852,10 +100935,28 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + + + + + + + + + + + + + + +