Skip to content

Commit b59ce9d

Browse files
committed
DPL: allow GUI to run with an empty workflow
1 parent 9ccc8ff commit b59ce9d

4 files changed

Lines changed: 29 additions & 5 deletions

File tree

Framework/Core/src/DeviceSpecHelpers.cxx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,6 @@ void DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(const WorkflowSpec& workf
708708
// them before assigning to a device.
709709
std::vector<OutputSpec> outputs;
710710

711-
WorkflowHelpers::verifyWorkflow(workflow);
712711
WorkflowHelpers::constructGraph(workflow, logicalEdges, outputs, availableForwardsInfo);
713712

714713
// We need to instanciate one device per (me, timeIndex) in the

Framework/Core/src/WorkflowHelpers.cxx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -755,10 +755,10 @@ void WorkflowHelpers::sortEdges(std::vector<size_t>& inEdgeIndex,
755755
std::sort(outEdgeIndex.begin(), outEdgeIndex.end(), outSorter);
756756
}
757757

758-
void WorkflowHelpers::verifyWorkflow(const o2::framework::WorkflowSpec& workflow)
758+
WorkflowParsingState WorkflowHelpers::verifyWorkflow(const o2::framework::WorkflowSpec& workflow)
759759
{
760760
if (workflow.empty()) {
761-
throw std::runtime_error("Empty workflow!");
761+
return WorkflowParsingState::Empty;
762762
}
763763
std::set<std::string> validNames;
764764
std::vector<OutputSpec> availableOutputs;
@@ -799,6 +799,7 @@ void WorkflowHelpers::verifyWorkflow(const o2::framework::WorkflowSpec& workflow
799799
}
800800
}
801801
}
802+
return WorkflowParsingState::Valid;
802803
}
803804

804805
using UnifiedDataSpecType = std::variant<InputSpec, OutputSpec>;

Framework/Core/src/WorkflowHelpers.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ struct OutputObj {
143143
bool isdangling;
144144
};
145145

146+
enum struct WorkflowParsingState : int {
147+
Valid,
148+
Empty,
149+
};
150+
146151
/// A set of internal helper classes to manipulate a Workflow
147152
struct WorkflowHelpers {
148153
/// Topological sort for a graph of @a nodeCount nodes.
@@ -163,7 +168,7 @@ struct WorkflowHelpers {
163168

164169
// Helper method to verify that a given workflow is actually valid e.g. that
165170
// it contains no empty labels.
166-
static void verifyWorkflow(const WorkflowSpec& workflow);
171+
[[nodiscard]] static WorkflowParsingState verifyWorkflow(const WorkflowSpec& workflow);
167172

168173
// Depending on the workflow and the dangling inputs inside it, inject "fake"
169174
// devices to mark the fact we might need some extra action to make sure

Framework/Core/src/runDataProcessing.cxx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,8 @@ int runStateMachine(DataProcessorSpecs const& workflow,
928928
std::vector<ServicePreSchedule> preScheduleCallbacks;
929929
std::vector<ServicePostSchedule> postScheduleCallbacks;
930930

931+
bool guiDeployedOnce = false;
932+
931933
while (true) {
932934
// If control forced some transition on us, we push it to the queue.
933935
if (driverControl.forcedTransitions.empty() == false) {
@@ -1025,6 +1027,10 @@ int runStateMachine(DataProcessorSpecs const& workflow,
10251027
break;
10261028
case DriverState::MATERIALISE_WORKFLOW:
10271029
try {
1030+
auto workflowState = WorkflowHelpers::verifyWorkflow(workflow);
1031+
if (driverInfo.batch == true && workflowState == WorkflowParsingState::Empty) {
1032+
throw runtime_error("Empty workflow provided while running in batch mode.");
1033+
}
10281034
DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow,
10291035
driverInfo.channelPolicies,
10301036
driverInfo.completionPolicies,
@@ -1063,6 +1069,13 @@ int runStateMachine(DataProcessorSpecs const& workflow,
10631069
} catch (std::runtime_error& e) {
10641070
std::cerr << "Invalid workflow: " << e.what() << std::endl;
10651071
return 1;
1072+
} catch (o2::framework::RuntimeErrorRef ref) {
1073+
auto& e = o2::framework::error_from_ref(ref);
1074+
#ifdef DPL_ENABLE_BACKTRACE
1075+
backtrace_symbols_fd(err.backtrace, err.maxBacktrace, STDERR_FILENO);
1076+
#endif
1077+
std::cerr << "Invalid workflow: " << e.what << std::endl;
1078+
return 1;
10661079
} catch (...) {
10671080
std::cerr << "Unknown error while materialising workflow";
10681081
return 1;
@@ -1107,6 +1120,7 @@ int runStateMachine(DataProcessorSpecs const& workflow,
11071120
guiContext.window = window;
11081121
gui_timer.data = &guiContext;
11091122
uv_timer_start(&gui_timer, gui_callback, 0, 20);
1123+
guiDeployedOnce = true;
11101124
}
11111125
break;
11121126
case DriverState::SCHEDULE: {
@@ -1185,10 +1199,15 @@ int runStateMachine(DataProcessorSpecs const& workflow,
11851199
driverInfo.states.push_back(DriverState::RUNNING);
11861200
driverInfo.states.push_back(DriverState::REDEPLOY_GUI);
11871201
driverInfo.states.push_back(DriverState::SCHEDULE);
1188-
} else if (deviceSpecs.size() == 0) {
1202+
} else if (deviceSpecs.empty() && driverInfo.batch == true) {
11891203
LOG(INFO) << "No device resulting from the workflow. Quitting.";
11901204
// If there are no deviceSpecs, we exit.
11911205
driverInfo.states.push_back(DriverState::EXIT);
1206+
} else if (deviceSpecs.empty() && driverInfo.batch == false && !guiDeployedOnce) {
1207+
// In case of an empty workflow, we need to deploy the GUI at least once.
1208+
driverInfo.states.push_back(DriverState::RUNNING);
1209+
driverInfo.states.push_back(DriverState::REDEPLOY_GUI);
1210+
guiDeployedOnce += 1;
11921211
} else {
11931212
driverInfo.states.push_back(DriverState::RUNNING);
11941213
}

0 commit comments

Comments
 (0)