From b59ce9d952dbf448ef6fa9c2ca0247853ca3b23b Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Sun, 15 Nov 2020 16:12:39 +0100 Subject: [PATCH 1/2] DPL: allow GUI to run with an empty workflow --- Framework/Core/src/DeviceSpecHelpers.cxx | 1 - Framework/Core/src/WorkflowHelpers.cxx | 5 +++-- Framework/Core/src/WorkflowHelpers.h | 7 ++++++- Framework/Core/src/runDataProcessing.cxx | 21 ++++++++++++++++++++- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Framework/Core/src/DeviceSpecHelpers.cxx b/Framework/Core/src/DeviceSpecHelpers.cxx index f1365407c088a..0cc4ea56c7dea 100644 --- a/Framework/Core/src/DeviceSpecHelpers.cxx +++ b/Framework/Core/src/DeviceSpecHelpers.cxx @@ -708,7 +708,6 @@ void DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(const WorkflowSpec& workf // them before assigning to a device. std::vector outputs; - WorkflowHelpers::verifyWorkflow(workflow); WorkflowHelpers::constructGraph(workflow, logicalEdges, outputs, availableForwardsInfo); // We need to instanciate one device per (me, timeIndex) in the diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index 8e517cd2bccd4..9ace1c786f61f 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -755,10 +755,10 @@ void WorkflowHelpers::sortEdges(std::vector& inEdgeIndex, std::sort(outEdgeIndex.begin(), outEdgeIndex.end(), outSorter); } -void WorkflowHelpers::verifyWorkflow(const o2::framework::WorkflowSpec& workflow) +WorkflowParsingState WorkflowHelpers::verifyWorkflow(const o2::framework::WorkflowSpec& workflow) { if (workflow.empty()) { - throw std::runtime_error("Empty workflow!"); + return WorkflowParsingState::Empty; } std::set validNames; std::vector availableOutputs; @@ -799,6 +799,7 @@ void WorkflowHelpers::verifyWorkflow(const o2::framework::WorkflowSpec& workflow } } } + return WorkflowParsingState::Valid; } using UnifiedDataSpecType = std::variant; diff --git a/Framework/Core/src/WorkflowHelpers.h b/Framework/Core/src/WorkflowHelpers.h index 9cb5c46829744..c673b1e9940b0 100644 --- a/Framework/Core/src/WorkflowHelpers.h +++ b/Framework/Core/src/WorkflowHelpers.h @@ -143,6 +143,11 @@ struct OutputObj { bool isdangling; }; +enum struct WorkflowParsingState : int { + Valid, + Empty, +}; + /// A set of internal helper classes to manipulate a Workflow struct WorkflowHelpers { /// Topological sort for a graph of @a nodeCount nodes. @@ -163,7 +168,7 @@ struct WorkflowHelpers { // Helper method to verify that a given workflow is actually valid e.g. that // it contains no empty labels. - static void verifyWorkflow(const WorkflowSpec& workflow); + [[nodiscard]] static WorkflowParsingState verifyWorkflow(const WorkflowSpec& workflow); // Depending on the workflow and the dangling inputs inside it, inject "fake" // devices to mark the fact we might need some extra action to make sure diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index 9ad45a114f2b7..cf0499ba7d351 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -928,6 +928,8 @@ int runStateMachine(DataProcessorSpecs const& workflow, std::vector preScheduleCallbacks; std::vector postScheduleCallbacks; + bool guiDeployedOnce = false; + while (true) { // If control forced some transition on us, we push it to the queue. if (driverControl.forcedTransitions.empty() == false) { @@ -1025,6 +1027,10 @@ int runStateMachine(DataProcessorSpecs const& workflow, break; case DriverState::MATERIALISE_WORKFLOW: try { + auto workflowState = WorkflowHelpers::verifyWorkflow(workflow); + if (driverInfo.batch == true && workflowState == WorkflowParsingState::Empty) { + throw runtime_error("Empty workflow provided while running in batch mode."); + } DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow, driverInfo.channelPolicies, driverInfo.completionPolicies, @@ -1063,6 +1069,13 @@ int runStateMachine(DataProcessorSpecs const& workflow, } catch (std::runtime_error& e) { std::cerr << "Invalid workflow: " << e.what() << std::endl; return 1; + } catch (o2::framework::RuntimeErrorRef ref) { + auto& e = o2::framework::error_from_ref(ref); +#ifdef DPL_ENABLE_BACKTRACE + backtrace_symbols_fd(err.backtrace, err.maxBacktrace, STDERR_FILENO); +#endif + std::cerr << "Invalid workflow: " << e.what << std::endl; + return 1; } catch (...) { std::cerr << "Unknown error while materialising workflow"; return 1; @@ -1107,6 +1120,7 @@ int runStateMachine(DataProcessorSpecs const& workflow, guiContext.window = window; gui_timer.data = &guiContext; uv_timer_start(&gui_timer, gui_callback, 0, 20); + guiDeployedOnce = true; } break; case DriverState::SCHEDULE: { @@ -1185,10 +1199,15 @@ int runStateMachine(DataProcessorSpecs const& workflow, driverInfo.states.push_back(DriverState::RUNNING); driverInfo.states.push_back(DriverState::REDEPLOY_GUI); driverInfo.states.push_back(DriverState::SCHEDULE); - } else if (deviceSpecs.size() == 0) { + } else if (deviceSpecs.empty() && driverInfo.batch == true) { LOG(INFO) << "No device resulting from the workflow. Quitting."; // If there are no deviceSpecs, we exit. driverInfo.states.push_back(DriverState::EXIT); + } else if (deviceSpecs.empty() && driverInfo.batch == false && !guiDeployedOnce) { + // In case of an empty workflow, we need to deploy the GUI at least once. + driverInfo.states.push_back(DriverState::RUNNING); + driverInfo.states.push_back(DriverState::REDEPLOY_GUI); + guiDeployedOnce += 1; } else { driverInfo.states.push_back(DriverState::RUNNING); } From c7c0d37edd7c37db3829171ab24121838d082547 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 16 Nov 2020 14:18:35 +0100 Subject: [PATCH 2/2] Update runDataProcessing.cxx --- Framework/Core/src/runDataProcessing.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index cf0499ba7d351..bdeed2f1a5e43 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -1207,7 +1207,6 @@ int runStateMachine(DataProcessorSpecs const& workflow, // In case of an empty workflow, we need to deploy the GUI at least once. driverInfo.states.push_back(DriverState::RUNNING); driverInfo.states.push_back(DriverState::REDEPLOY_GUI); - guiDeployedOnce += 1; } else { driverInfo.states.push_back(DriverState::RUNNING); }