Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Framework/Core/src/DeviceSpecHelpers.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,6 @@ void DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(const WorkflowSpec& workf
// them before assigning to a device.
std::vector<OutputSpec> outputs;

WorkflowHelpers::verifyWorkflow(workflow);
WorkflowHelpers::constructGraph(workflow, logicalEdges, outputs, availableForwardsInfo);

// We need to instanciate one device per (me, timeIndex) in the
Expand Down
5 changes: 3 additions & 2 deletions Framework/Core/src/WorkflowHelpers.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -755,10 +755,10 @@ void WorkflowHelpers::sortEdges(std::vector<size_t>& 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<std::string> validNames;
std::vector<OutputSpec> availableOutputs;
Expand Down Expand Up @@ -799,6 +799,7 @@ void WorkflowHelpers::verifyWorkflow(const o2::framework::WorkflowSpec& workflow
}
}
}
return WorkflowParsingState::Valid;
}

using UnifiedDataSpecType = std::variant<InputSpec, OutputSpec>;
Expand Down
7 changes: 6 additions & 1 deletion Framework/Core/src/WorkflowHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
20 changes: 19 additions & 1 deletion Framework/Core/src/runDataProcessing.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,8 @@ int runStateMachine(DataProcessorSpecs const& workflow,
std::vector<ServicePreSchedule> preScheduleCallbacks;
std::vector<ServicePostSchedule> postScheduleCallbacks;

bool guiDeployedOnce = false;

while (true) {
// If control forced some transition on us, we push it to the queue.
if (driverControl.forcedTransitions.empty() == false) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -1185,10 +1199,14 @@ 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);
} else {
driverInfo.states.push_back(DriverState::RUNNING);
}
Expand Down