From 4871965358716b0a64b721e48eb47a9f7a24cea2 Mon Sep 17 00:00:00 2001 From: "Ralph J. Steinhagen" Date: Sun, 19 May 2024 10:32:58 +0200 Subject: [PATCH] bump Emscripten to 3.1.56 * ioThreadPool is not default-initialised any more as it is injected by the Graph/Scheduler and anyway needed by custom BlockinIO declared blocks that need a default thread pool * added optional sleep as workaround for incomplete std::atomic implementation (at least it seems for nodejs) * extra diagnostics for qa_Messages unit-test * some minor fixes of conversion warnings Signed-off-by: Ralph J. Steinhagen --- CMakeLists.txt | 19 ++++++++------- .../gnuradio-4.0/basic/clock_source.hpp | 7 +++--- .../gnuradio-4.0/basic/common_blocks.hpp | 2 +- core/include/gnuradio-4.0/Block.hpp | 11 ++++++--- core/include/gnuradio-4.0/Scheduler.hpp | 3 +++ core/test/qa_Messages.cpp | 24 +++++++++++++++---- docker/Dockerfile | 2 +- 7 files changed, 47 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff9a9476..50a3ba1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,19 +98,20 @@ if (EMSCRIPTEN) ) add_link_options( "SHELL:-s ALLOW_MEMORY_GROWTH=1" + "SHELL:-s ASSERTIONS=1" "SHELL:-s INITIAL_MEMORY=256MB" - "SHELL:-s MAXIMUM_MEMORY=1GB" - "SHELL:-s SAFE_HEAP=1" - "SHELL:-s ASSERTIONS=2" - "SHELL:-s STACK_OVERFLOW_CHECK=2" - "SHELL:-g" # enable debugging information - "SHELL:-gsource-map" - "SHELL:--profiling-funcs" - "SHELL:--emit-symbol-map" + # "SHELL:-s SAFE_HEAP=1" # additional for debug + # "SHELL:-s ASSERTIONS=2" # additional for debug + # "SHELL:-s STACK_OVERFLOW_CHECK=2" # additional for debug + # "SHELL:-g" # additional for debug + # "SHELL:-gsource-map" # additional for debug + # "SHELL:--profiling-funcs" # additional for debug + # "SHELL:--emit-symbol-map" # additional for debug -fwasm-exceptions -pthread - "SHELL:-s PTHREAD_POOL_SIZE=30" + "SHELL:-s PTHREAD_POOL_SIZE=60" "SHELL:-s FETCH=1" + "SHELL:-s WASM=1" # output as web-assembly ) endif () diff --git a/blocks/basic/include/gnuradio-4.0/basic/clock_source.hpp b/blocks/basic/include/gnuradio-4.0/basic/clock_source.hpp index f6c62db7..c20e9540 100644 --- a/blocks/basic/include/gnuradio-4.0/basic/clock_source.hpp +++ b/blocks/basic/include/gnuradio-4.0/basic/clock_source.hpp @@ -138,9 +138,10 @@ ClockSource Documentation -- add here if (samplesToNextTag < samplesToNextTimeTag) { if (next_tag < tags.size() && samplesToNextTag <= samplesToProduce) { - const auto tagDeltaIndex = tags[next_tag].index - static_cast(n_samples_produced); // position w.r.t. start of this chunk + const auto signedSamplesProduced = static_cast(n_samples_produced); + const auto tagDeltaIndex = tags[next_tag].index - signedSamplesProduced; // position w.r.t. start of this chunk if (verbose_console) { - gr::testing::print_tag(tags[next_tag], fmt::format("{}::processBulk(...)\t publish tag at {:6}", this->name, n_samples_produced + tagDeltaIndex)); + gr::testing::print_tag(tags[next_tag], fmt::format("{}::processBulk(...)\t publish tag at {:6}", this->name, signedSamplesProduced + tagDeltaIndex)); } out.publishTag(tags[next_tag].map, tagDeltaIndex); samplesToProduce = samplesToNextTag; @@ -154,7 +155,7 @@ ClockSource Documentation -- add here if (verbose_console) { fmt::println("{}::processBulk(...)\t publish tag-time at {:6}, time:{}ns", this->name, samplesToNextTimeTag, tag_times[next_time_tag]); } - out.publishTag(metaInfo, samplesToNextTimeTag); + out.publishTag(metaInfo, static_cast(samplesToNextTimeTag)); samplesToProduce = samplesToNextTimeTag; next_time_tag++; } diff --git a/blocks/basic/include/gnuradio-4.0/basic/common_blocks.hpp b/blocks/basic/include/gnuradio-4.0/basic/common_blocks.hpp index 16829510..105cc47c 100644 --- a/blocks/basic/include/gnuradio-4.0/basic/common_blocks.hpp +++ b/blocks/basic/include/gnuradio-4.0/basic/common_blocks.hpp @@ -63,7 +63,7 @@ struct MultiAdder : public gr::Block> { std::vector> inputs; gr::PortOut out; - gr::Annotated, gr::Limits<1U, 32U>> n_inputs = 0U; + gr::Annotated, gr::Limits<1U, 32U>> n_inputs{ 0U }; void settingsChanged(const gr::property_map &old_settings, const gr::property_map &new_settings) { diff --git a/core/include/gnuradio-4.0/Block.hpp b/core/include/gnuradio-4.0/Block.hpp index 0b970c94..a42ece07 100644 --- a/core/include/gnuradio-4.0/Block.hpp +++ b/core/include/gnuradio-4.0/Block.hpp @@ -422,9 +422,8 @@ class Block : public lifecycle::StateMachine, // alignas(hardware_destructive_interference_size) std::atomic ioRequestedWork{ std::numeric_limits::max() }; alignas(hardware_destructive_interference_size) work::Counter ioWorkDone{}; alignas(hardware_destructive_interference_size) std::atomic ioLastWorkStatus{ work::Status::OK }; - alignas(hardware_destructive_interference_size) std::shared_ptr progress = std::make_shared(); - alignas(hardware_destructive_interference_size) std::shared_ptr ioThreadPool = std::make_shared( - "block_thread_pool", gr::thread_pool::TaskType::IO_BOUND, 2UZ, std::numeric_limits::max()); + alignas(hardware_destructive_interference_size) std::shared_ptr progress = std::make_shared(); + alignas(hardware_destructive_interference_size) std::shared_ptr ioThreadPool; alignas(hardware_destructive_interference_size) std::atomic ioThreadRunning{ false }; constexpr static TagPropagationPolicy tag_policy = TagPropagationPolicy::TPP_ALL_TO_ALL; @@ -453,7 +452,9 @@ class Block : public lifecycle::StateMachine, // return "please add a public 'using Description = Doc<\"...\">' documentation annotation to your block definition"; } }(); +#ifndef __EMSCRIPTEN__ static_assert(std::atomic::is_always_lock_free, "std::atomic is not lock-free"); +#endif // static property_map @@ -1697,6 +1698,10 @@ class Block : public lifecycle::StateMachine, // bool expectedThreadState = false; if (lifecycle::isActive(this->state()) && this->ioThreadRunning.compare_exchange_strong(expectedThreadState, true, std::memory_order_acq_rel)) { if constexpr (useIoThread) { // use graph-provided ioThreadPool + if (!ioThreadPool) { + emitErrorMessage("work(..)", "blockingIO with useIoThread - no ioThreadPool being set"); + return { requested_work, 0UZ, work::Status::ERROR }; + } ioThreadPool->execute([this]() { assert(lifecycle::isActive(this->state())); diff --git a/core/include/gnuradio-4.0/Scheduler.hpp b/core/include/gnuradio-4.0/Scheduler.hpp index a77173ea..fd53e1ec 100644 --- a/core/include/gnuradio-4.0/Scheduler.hpp +++ b/core/include/gnuradio-4.0/Scheduler.hpp @@ -217,6 +217,9 @@ class SchedulerBase : public Block { something_happened = true; } } +#ifdef __EMSCRIPTEN__ + std::this_thread::sleep_for(std::chrono::microseconds(10u)); // workaround for incomplete std::atomic implementation (at least it seems for nodejs) +#endif return { requestedWorkAllBlocks, performedWorkAllBlocks, something_happened ? work::Status::OK : work::Status::DONE }; } diff --git a/core/test/qa_Messages.cpp b/core/test/qa_Messages.cpp index 74fbf9bf..332b5010 100644 --- a/core/test/qa_Messages.cpp +++ b/core/test/qa_Messages.cpp @@ -497,7 +497,7 @@ const boost::ut::suite MessagesTests = [] { using ResultCheck = std::function()>; SendCommand cmd = [] {}; ResultCheck check = [] { return true; }; - std::chrono::milliseconds delay = 0ms; // delay after 'cmd' which the reply is being checked + std::chrono::milliseconds delay = 1ms; // delay after 'cmd' which the reply is being checked std::chrono::milliseconds timeout = 1s; // time-out for the 'check' test }; @@ -517,9 +517,18 @@ const boost::ut::suite MessagesTests = [] { fmt::println("##### starting test for scheduler {}", gr::meta::type_name()); std::fflush(stdout); - std::thread testWorker([&commands] { - std::this_thread::sleep_for(1s); + std::thread testWorker([&scheduler, &commands] { + fmt::println("starting testWorker."); + std::fflush(stdout); + while (scheduler.state() != gr::lifecycle::State::RUNNING) { // wait until scheduler is running + std::this_thread::sleep_for(40ms); + } + fmt::println("scheduler is running."); + std::fflush(stdout); + for (auto &[command, resultCheck, delay, timeout] : commands) { + fmt::print("executing command: "); + std::fflush(stdout); command(); // execute the command std::this_thread::sleep_for(delay); // wait for approximate time when command should be expected to be applied @@ -548,8 +557,15 @@ const boost::ut::suite MessagesTests = [] { } } }); + + fmt::println("starting scheduler {}", gr::meta::type_name()); + std::fflush(stdout); expect(scheduler.runAndWait().has_value()); - testWorker.join(); + fmt::println("stopped scheduler {}", gr::meta::type_name()); + + if (testWorker.joinable()) { + testWorker.join(); + } fmt::println("##### finished test for scheduler {} - produced {} samples", gr::meta::type_name(), sink.n_samples_produced); } | std::tuple, std::integral_constant>{}; diff --git a/docker/Dockerfile b/docker/Dockerfile index b3f89311..db293e50 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,7 +16,7 @@ ENV JAVA_HOME=/opt/java/openjdk \ LC_ALL=en_US.UTF-8 \ CMAKE_MAKE_PROGRAM=ninja \ EMSDK_HOME=/opt/emsdk \ - EMSDK_VERSION=3.1.52 + EMSDK_VERSION=3.1.56 # Install compilers, package managers and build-tools # As we are using the the ubuntu prerelease llvm and cmake are fresh enough, readd these if the version is not sufficient anymore