14#define BOOST_BIND_GLOBAL_PLACEHOLDERS
89#include <Configuration/ConfigurationInterface.h>
90#include <Configuration/ConfigurationFactory.h>
91#include <Monitoring/MonitoringFactory.h>
94#include <fairmq/Device.h>
95#include <fairmq/DeviceRunner.h>
96#include <fairmq/shmem/Monitor.h>
97#include <fairmq/ProgOptions.h>
99#include <boost/program_options.hpp>
100#include <boost/program_options/options_description.hpp>
101#include <boost/program_options/variables_map.hpp>
102#include <boost/exception/diagnostic_information.hpp>
103#include <boost/property_tree/json_parser.hpp>
120#include <type_traits>
128#include <netinet/ip.h>
129#include <sys/resource.h>
130#include <sys/select.h>
131#include <sys/socket.h>
134#include <sys/types.h>
140#if defined(__linux__) && __has_include(<sched.h>)
142#elif __has_include(<linux/getcpu.h>)
143#include <linux/getcpu.h>
144#elif __has_include(<cpuid.h>) && (__x86_64__ || __i386__)
146#define CPUID(INFO, LEAF, SUBLEAF) __cpuid_count(LEAF, SUBLEAF, INFO[0], INFO[1], INFO[2], INFO[3])
149 uint32_t CPUInfo[4]; \
150 CPUID(CPUInfo, 1, 0); \
152 if ((CPUInfo[3] & (1 << 9)) == 0) { \
155 CPU = (unsigned)CPUInfo[1] >> 24; \
191 for (
int argi = 0; argi < argc; argi++) {
192 if (strcmp(argv[argi],
"--id") == 0 && argi + 1 < argc) {
193 return argv[argi + 1];
201 static bool noCatch = getenv(
"O2_NO_CATCHALL_EXCEPTIONS") && strcmp(getenv(
"O2_NO_CATCHALL_EXCEPTIONS"),
"0");
217 }
catch (boost::exception&
e) {
220 }
catch (std::exception
const&
error) {
249 bytes_read = read(infd,
buffer, 1024 * 16);
250 if (bytes_read == 0) {
256 if (bytes_read < 0) {
259 assert(bytes_read > 0);
273 for (
auto& info : infos) {
274 if (info.readyToQuit ==
false) {
285 for (
auto& info : infos) {
286 if (info.active ==
true) {
295 for (
auto& info : infos) {
296 if ((info.pid != 0) && info.active) {
308 std::regex regexp(R
"(^\[([\d+:]*)\]\[\w+\] )");
309 if (!driverInfo.lastError.empty()) {
310 LOGP(
error,
"SEVERE: DPL driver encountered an error while running.\n{}",
311 driverInfo.lastError);
314 for (
size_t di = 0;
di < deviceSpecs.size(); ++
di) {
316 auto& spec = deviceSpecs[
di];
317 if (
info.maxLogLevel >= driverInfo.minFailureLevel) {
318 LOGP(
error,
"SEVERE: Device {} ({}) had at least one message above severity {}: {}",
321 (
int)
info.minFailureLevel,
322 std::regex_replace(
info.firstSevereError, regexp,
""));
325 if (
info.exitStatus != 0) {
326 LOGP(
error,
"SEVERE: Device {} ({}) returned with {}",
330 return info.exitStatus;
339 auto p = pipe(pipes);
342 std::cerr <<
"Unable to create PIPE: ";
345 assert(
false &&
"EFAULT while reading from pipe");
348 std::cerr <<
"Too many active descriptors";
351 std::cerr <<
"System file table is full";
354 std::cerr <<
"Unknown PIPE" << std::endl;
357 kill(-1 * getpid(), SIGKILL);
369static void handle_sigint(
int)
389 fair::mq::shmem::Monitor::Cleanup(SessionId{
"dpl_" + uniqueWorkflowId},
false);
402 LOG(info) <<
"Starting " << spec.
id <<
" as remote device";
407 .maxLogLevel = LogParsingHelpers::LogLevel::Debug,
409 .readyToQuit =
false,
410 .inputChannelMetricsViewIndex =
Metric2DViewIndex{
"oldest_possible_timeslice", 0, 0, {}},
411 .outputChannelMetricsViewIndex =
Metric2DViewIndex{
"oldest_possible_output", 0, 0, {}},
412 .lastSignal = uv_hrtime() - 10000000};
414 deviceInfos.emplace_back(info);
416 clock_gettime(CLOCK_REALTIME, &now);
435 DeviceInfo& info = infos->at(logContext->index);
440 if (
events & UV_READABLE) {
443 if (
events & UV_DISCONNECT) {
446 O2_SIGNPOST_EVENT_EMIT(driver, sid,
"loop",
"log_callback invoked by poller for device %{xcode:pid}d which is %{public}s%{public}s",
447 info.pid, info.active ?
"active" :
"inactive",
448 info.active ?
" and still has data to read." :
".");
449 if (info.active ==
false) {
452 uv_async_send(logContext->serverContext->asyncLogProcessing);
470 if (nread == UV_EOF) {
480 LOG(
error) <<
"websocket_callback: Error while reading from websocket";
489 LOG(debug3) <<
"Parsing request with " << handler <<
" with " << nread <<
" bytes";
495 LOG(
error) <<
"Error while parsing request: " <<
e.message;
496 handler->error(
e.code,
e.message.c_str());
501static void my_alloc_cb(
uv_handle_t*,
size_t suggested_size, uv_buf_t*
buf)
503 buf->base = (
char*)
malloc(suggested_size);
504 buf->len = suggested_size;
514 LOGF(
error,
"New connection error %s\n", uv_strerror(status));
519 auto* client = (uv_tcp_t*)
malloc(
sizeof(uv_tcp_t));
520 uv_tcp_init(serverContext->loop, client);
521 if (uv_accept(server, (uv_stream_t*)client) == 0) {
522 client->data =
new WSDPLHandler((uv_stream_t*)client, serverContext);
537 size_t result = write(context->fd, context->configuration.data(), context->configuration.size());
538 if (
result != context->configuration.size()) {
539 LOG(
error) <<
"Unable to pass configuration to children";
542 auto error = fsync(context->fd);
545 LOGP(
error,
"EBADF while flushing child stdin");
548 LOGP(
error,
"EINVAL while flushing child stdin");
551 LOGP(
error,
"EINTR while flushing child stdin");
554 LOGP(
error,
"EIO while flushing child stdin");
560 auto error = close(context->fd);
563 LOGP(
error,
"EBADF while closing child stdin");
566 LOGP(
error,
"EINTR while closing child stdin");
569 LOGP(
error,
"EIO while closing child stdin");
587 struct sigaction sa_handle_int;
588 sa_handle_int.sa_handler = handle_sigint;
589 sigemptyset(&sa_handle_int.sa_mask);
590 sa_handle_int.sa_flags = SA_RESTART;
591 if (sigaction(SIGINT, &sa_handle_int,
nullptr) == -1) {
592 perror(
"Unable to install signal handler");
595 struct sigaction sa_handle_term;
596 sa_handle_term.sa_handler = handle_sigint;
597 sigemptyset(&sa_handle_term.sa_mask);
598 sa_handle_term.sa_flags = SA_RESTART;
599 if (sigaction(SIGTERM, &sa_handle_int,
nullptr) == -1) {
600 perror(
"Unable to install signal handler");
606 std::string
const& forwardedStdin,
607 std::vector<DeviceStdioContext>& childFds,
608 std::vector<uv_poll_t*>& handles)
610 for (
size_t i = 0;
i < childFds.size(); ++
i) {
611 auto& childstdin = childFds[
i].childstdin;
612 auto& childstdout = childFds[
i].childstdout;
614 auto* req = (uv_work_t*)
malloc(
sizeof(uv_work_t));
620 int resultCode = fcntl(childstdout[0], F_SETFL, O_NONBLOCK);
621 if (resultCode == -1) {
622 LOGP(
error,
"Error while setting the socket to non-blocking: {}", strerror(errno));
626 auto addPoller = [&handles, &serverContext](
int index,
int fd) {
630 context->serverContext = serverContext;
632 auto handle = handles.back();
634 uv_poll_init(serverContext->
loop,
handle, fd);
638 addPoller(
i, childstdout[0]);
650 char const*
msg =
"*** Program crashed (%s)\nBacktrace by DPL:\n";
651 snprintf(
buffer, 1024,
msg, strsignal(sig));
653 if (std::fetestexcept(FE_DIVBYZERO)) {
654 snprintf(
buffer, 1024,
msg,
"FLOATING POINT EXCEPTION - DIVISION BY ZERO");
655 }
else if (std::fetestexcept(FE_INVALID)) {
656 snprintf(
buffer, 1024,
msg,
"FLOATING POINT EXCEPTION - INVALID RESULT");
658 snprintf(
buffer, 1024,
msg,
"FLOATING POINT EXCEPTION - UNKNOWN REASON");
666 char const*
msg =
"Backtrace complete.\n";
671 fsync(STDERR_FILENO);
680 std::vector<DeviceSpec>
const& specs,
681 DriverInfo& driverInfo,
682 std::vector<DeviceControl>&,
683 std::vector<DeviceExecution>& executions,
684 std::vector<DeviceInfo>& deviceInfos,
685 std::vector<DataProcessingStates>& allStates,
687 boost::program_options::variables_map& varmap,
688 std::vector<DeviceStdioContext>& childFds,
695 auto& spec = specs[
ref.index];
696 auto& execution = executions[
ref.index];
698 for (
auto& service : spec.services) {
699 if (service.preFork !=
nullptr) {
711 signal(SIGTRAP, SIG_IGN);
716 signal(SIGUSR1, SIG_IGN);
717 signal(SIGUSR2, SIG_IGN);
726 getrlimit(RLIMIT_NOFILE, &rlim);
732 int rlim_cur = std::min((
int)rlim.rlim_cur, 10000);
733 for (
int i = 0;
i < rlim_cur; ++
i) {
734 if (childFds[
ref.index].childstdin[0] ==
i) {
737 if (childFds[
ref.index].childstdout[1] ==
i) {
742 dup2(childFds[
ref.index].childstdin[0], STDIN_FILENO);
743 dup2(childFds[
ref.index].childstdout[1], STDOUT_FILENO);
744 dup2(childFds[
ref.index].childstdout[1], STDERR_FILENO);
746 for (
auto& service : spec.services) {
747 if (service.postForkChild !=
nullptr) {
748 service.postForkChild(serviceRegistry);
751 for (
auto& env : execution.environ) {
754 int err = execvp(execution.args[0], execution.args.data());
756 perror(
"Unable to start child process");
763 close(childFds[
ref.index].childstdin[0]);
764 close(childFds[
ref.index].childstdout[1]);
765 if (varmap.count(
"post-fork-command")) {
766 auto templateCmd = varmap[
"post-fork-command"];
767 auto cmd = fmt::format(fmt::runtime(templateCmd.as<std::string>()),
769 fmt::arg(
"id", spec.id),
770 fmt::arg(
"cpu", parentCPU),
771 fmt::arg(
"node", parentNode),
772 fmt::arg(
"name", spec.name),
773 fmt::arg(
"timeslice0", spec.inputTimesliceId),
774 fmt::arg(
"timeslice1", spec.inputTimesliceId + 1),
775 fmt::arg(
"rank0", spec.rank),
776 fmt::arg(
"maxRank0", spec.nSlots));
777 int err = system(cmd.c_str());
779 LOG(
error) <<
"Post fork command `" << cmd <<
"` returned with status " << err;
781 LOG(
debug) <<
"Successfully executed `" << cmd;
786 for (
auto& service : spec.services) {
787 if (service.postForkParent !=
nullptr) {
788 service.postForkParent(serviceRegistry);
792 LOG(info) <<
"Starting " << spec.id <<
" on pid " <<
id;
793 deviceInfos.push_back({.pid =
id,
796 .maxLogLevel = LogParsingHelpers::LogLevel::Debug,
797 .minFailureLevel = driverInfo.minFailureLevel,
799 .readyToQuit =
false,
800 .inputChannelMetricsViewIndex =
Metric2DViewIndex{
"oldest_possible_timeslice", 0, 0, {}},
801 .outputChannelMetricsViewIndex =
Metric2DViewIndex{
"oldest_possible_output", 0, 0, {}},
802 .lastSignal = uv_hrtime() - 10000000});
805 clock_gettime(CLOCK_REALTIME, &now);
807 allStates.emplace_back(
812 .
name =
"data_queries",
813 .stateId = (short)ProcessingStateId::DATA_QUERIES,
814 .sendInitialValue =
true,
817 .
name =
"output_matchers",
818 .stateId = (short)ProcessingStateId::OUTPUT_MATCHERS,
819 .sendInitialValue =
true,
823 for (
size_t i = 0;
i < pipelineLength; ++
i) {
825 .
name = fmt::format(
"matcher_variables/{}",
i),
826 .stateId =
static_cast<short>((short)(ProcessingStateId::CONTEXT_VARIABLES_BASE) +
i),
827 .minPublishInterval = 200,
828 .sendInitialValue =
true,
832 for (
size_t i = 0;
i < pipelineLength; ++
i) {
834 .
name = fmt::format(
"data_relayer/{}",
i),
835 .stateId =
static_cast<short>((short)(ProcessingStateId::DATA_RELAYER_BASE) +
i),
836 .minPublishInterval = 200,
837 .sendInitialValue =
true,
846 DriverInfo& driverInfo,
858 assert(infos.size() == controls.size());
862 for (
size_t di = 0,
de = infos.size();
di <
de; ++
di) {
865 assert(specs.size() == infos.size());
868 if (info.unprinted.empty()) {
874 O2_SIGNPOST_START(driver, sid,
"bytes_processed",
"bytes processed by %{xcode:pid}d", info.pid);
876 std::string_view
s = info.unprinted;
878 info.history.resize(info.historySize);
879 info.historyLevel.resize(info.historySize);
881 while ((
pos =
s.find(
"\n")) != std::string::npos) {
882 std::string_view token{
s.substr(0,
pos)};
890 if (!control.
quiet && (token.find(control.
logFilter) != std::string::npos) && logLevel >= info.logLevel) {
891 assert(info.historyPos >= 0);
892 assert(info.historyPos < info.history.size());
893 info.history[info.historyPos] = token;
894 info.historyLevel[info.historyPos] = logLevel;
895 info.historyPos = (info.historyPos + 1) % info.history.size();
897 fmt::print(
"[{}:{}]: {}\n", info.pid, spec.
id, token);
901 bool maxLogLevelIncreased =
false;
902 if (logLevel > info.maxLogLevel && logLevel > LogParsingHelpers::LogLevel::Info &&
903 logLevel != LogParsingHelpers::LogLevel::Unknown) {
904 info.maxLogLevel = logLevel;
905 maxLogLevelIncreased =
true;
907 if (logLevel >= driverInfo.minFailureLevel) {
908 info.lastError = token;
909 if (info.firstSevereError.empty() || maxLogLevelIncreased) {
910 info.firstSevereError = token;
914 s.remove_prefix(
pos + 1);
916 size_t oldSize = info.unprinted.size();
917 info.unprinted = std::string(
s);
918 int64_t bytesProcessed = oldSize - info.unprinted.size();
919 O2_SIGNPOST_END(driver, sid,
"bytes_processed",
"bytes processed by %{xcode:network-size-in-bytes}" PRIi64, bytesProcessed);
931 bool hasError =
false;
934 pid_t
pid = waitpid((pid_t)(-1), &status, WNOHANG);
937 int es = WEXITSTATUS(status);
938 if (WIFEXITED(status) ==
false ||
es != 0) {
940 std::string
id =
"unknown";
941 assert(specs.size() == infos.size());
942 for (
size_t ii = 0; ii < infos.size(); ++ii) {
943 if (infos[ii].
pid ==
pid) {
951 LOGP(
error,
"pid {} ({}) was forcefully terminated after being requested to quit",
pid,
id);
953 if (WIFSIGNALED(status)) {
954 int exitSignal = WTERMSIG(status);
955 es = exitSignal + 128;
956 LOGP(
error,
"Workflow crashed - PID {} ({}) was killed abnormally with {} and exited code was set to {}.",
pid,
id, strsignal(exitSignal),
es);
959 LOGP(
error,
"Workflow crashed - PID {} ({}) did not exit correctly however it's not clear why. Exit code forced to {}.",
pid,
id,
es);
964 for (
auto& info : infos) {
965 if (info.pid ==
pid) {
967 info.exitStatus =
es;
981 if (err.maxBacktrace != 0) {
983 "Unhandled o2::framework::runtime_error reached the top of main of {}, device shutting down."
985 processName, err.what);
986 LOGP(
error,
"Backtrace follow:");
990 "Unhandled o2::framework::runtime_error reached the top of main of {}, device shutting down."
992 processName, err.what);
993 LOGP(
error,
"Recompile with DPL_ENABLE_BACKTRACE=1 to get more information.");
1000 LOGP(fatal,
"unknown error while setting up workflow in {}.", processName);
1002 LOGP(fatal,
"error while setting up workflow in {}: {}", processName,
s);
1010 LOG(info) <<
"Dry run enforced. Creating dummy messages to simulate computation happended";
1011 for (auto& route : routes) {
1012 auto concrete = DataSpecUtils::asConcreteDataMatcher(route.matcher);
1013 outputs.make<int>(Output{concrete.origin, concrete.description, concrete.subSpec}, 2);
1029 std::string
const& defaultDriverClient,
1032 fair::Logger::SetConsoleColor(
false);
1033 fair::Logger::OnFatal([]() {
throw runtime_error(
"Fatal error"); });
1035 LOG(info) <<
"Spawning new device " << spec.id <<
" in process with pid " << getpid();
1037 fair::mq::DeviceRunner runner{argc, argv};
1041 runner.AddHook<fair::mq::hooks::SetCustomCmdLineOptions>([&spec, driverConfig, defaultDriverClient](fair::mq::DeviceRunner&
r) {
1042 std::string defaultExitTransitionTimeout =
"0";
1043 std::string defaultDataProcessingTimeout =
"0";
1044 std::string defaultInfologgerMode =
"";
1047 defaultExitTransitionTimeout =
"40";
1048 defaultDataProcessingTimeout =
"20";
1049 defaultInfologgerMode =
"infoLoggerD";
1051 defaultExitTransitionTimeout =
"40";
1052 defaultDataProcessingTimeout =
"20";
1054 boost::program_options::options_description optsDesc;
1056 char const* defaultSignposts = getenv(
"DPL_SIGNPOSTS");
1057 optsDesc.add_options()(
"monitoring-backend", bpo::value<std::string>()->default_value(
"default"),
"monitoring backend info")
1058 (
"dpl-stats-min-online-publishing-interval", bpo::value<std::string>()->default_value(
"0"),
"minimum flushing interval for online metrics (in s)")
1059 (
"driver-client-backend", bpo::value<std::string>()->default_value(defaultDriverClient),
"backend for device -> driver communicataon: stdout://: use stdout, ws://: use websockets")
1060 (
"infologger-severity", bpo::value<std::string>()->default_value(
""),
"minimum FairLogger severity to send to InfoLogger")
1061 (
"dpl-tracing-flags", bpo::value<std::string>()->default_value(
""),
"pipe `|` separate list of events to be traced")
1062 (
"signposts", bpo::value<std::string>()->default_value(defaultSignposts ? defaultSignposts :
""),
"comma separated list of signposts to enable")
1063 (
"expected-region-callbacks", bpo::value<std::string>()->default_value(
"0"),
"how many region callbacks we are expecting")
1064 (
"exit-transition-timeout", bpo::value<std::string>()->default_value(defaultExitTransitionTimeout),
"how many second to wait before switching from RUN to READY")
1065 (
"error-on-exit-transition-timeout", bpo::value<bool>()->zero_tokens()->default_value(
false),
"print error instead of warning when exit transition timer expires")
1066 (
"data-processing-timeout", bpo::value<std::string>()->default_value(defaultDataProcessingTimeout),
"how many second to wait before stopping data processing and allowing data calibration")
1067 (
"timeframes-rate-limit", bpo::value<std::string>()->default_value(
"0"),
"how many timeframe can be in flight at the same moment (0 disables)")
1068 (
"configuration,cfg", bpo::value<std::string>()->default_value(
"command-line"),
"configuration backend")
1069 (
"infologger-mode", bpo::value<std::string>()->default_value(defaultInfologgerMode),
"O2_INFOLOGGER_MODE override")
1070 (
"log-timestamp-us", bpo::value<bool>()->zero_tokens()->default_value(
false),
"enable microsecond timestamps in log messages");
1071 r.fConfig.AddToCmdLineOptions(optsDesc,
true);
1076 std::unique_ptr<SimpleRawDeviceService> simpleRawDeviceService;
1077 std::unique_ptr<DeviceState> deviceState;
1078 std::unique_ptr<ComputingQuotaEvaluator> quotaEvaluator;
1079 std::unique_ptr<FairMQDeviceProxy> deviceProxy;
1080 std::unique_ptr<DeviceContext> deviceContext;
1082 auto afterConfigParsingCallback = [&simpleRawDeviceService,
1088 &danglingEdgesContext,
1091 &processingPolicies,
1094 &loop](fair::mq::DeviceRunner&
r) {
1096 simpleRawDeviceService = std::make_unique<SimpleRawDeviceService>(
nullptr, spec);
1097 serviceRef.
registerService(ServiceRegistryHelpers::handleForService<RawDeviceService>(simpleRawDeviceService.get()));
1099 deviceState = std::make_unique<DeviceState>();
1100 deviceState->loop = loop;
1102 serviceRef.
registerService(ServiceRegistryHelpers::handleForService<DeviceState>(deviceState.get()));
1104 quotaEvaluator = std::make_unique<ComputingQuotaEvaluator>(serviceRef);
1105 serviceRef.
registerService(ServiceRegistryHelpers::handleForService<ComputingQuotaEvaluator>(quotaEvaluator.get()));
1108 serviceRef.
registerService(ServiceRegistryHelpers::handleForService<DeviceSpec const>(&spec));
1109 serviceRef.
registerService(ServiceRegistryHelpers::handleForService<RunningWorkflowInfo const>(&runningWorkflow));
1110 serviceRef.
registerService(ServiceRegistryHelpers::handleForService<DeviceContext>(deviceContext.get()));
1111 serviceRef.
registerService(ServiceRegistryHelpers::handleForService<DriverConfig const>(&driverConfig));
1112 serviceRef.
registerService(ServiceRegistryHelpers::handleForService<DanglingEdgesContext>(&danglingEdgesContext));
1114 auto device = std::make_unique<DataProcessingDevice>(
ref, serviceRegistry);
1117 r.fDevice = std::move(
device);
1118 fair::Logger::SetConsoleColor(
false);
1119 if (
r.fConfig.GetProperty<
bool>(
"log-timestamp-us")) {
1120 fair::Logger::DefineVerbosity(fair::Verbosity::user1,
1121 fair::VerbositySpec::Make(fair::VerbositySpec::Info::timestamp_us,
1122 fair::VerbositySpec::Info::severity));
1123 fair::Logger::SetVerbosity(fair::Verbosity::user1);
1127 for (
auto& service : spec.services) {
1128 LOG(
debug) <<
"Declaring service " << service.name;
1129 serviceRegistry.
declareService(service, *deviceState.get(),
r.fConfig);
1132 serviceRef.
get<
Monitoring>().enableProcessMonitoring(spec.resourceMonitoringInterval, {PmMeasurement::Cpu, PmMeasurement::Mem, PmMeasurement::Smaps});
1136 runner.AddHook<fair::mq::hooks::InstantiateDevice>(afterConfigParsingCallback);
1138 auto result = runner.Run();
1154 if (gui->plugin ==
nullptr) {
1161 *gui->guiTimerExpired =
true;
1163 if ((
counter++ % 6000) == 0) {
1166 *gui->guiTimerExpired =
false;
1173 if (gui->plugin->supportsDeferredClose()) {
1176 if (*(gui->guiQuitRequested)) {
1180 void* draw_data =
nullptr;
1182 uint64_t frameLatency = frameStart - gui->frameLast;
1185 if (frameLatency / 1000000 <= 15) {
1186 draw_data = gui->lastFrame;
1193 if (!gui->plugin->pollGUIPreRender(gui->window, (
float)frameLatency / 1000000000.0f)) {
1194 *(gui->guiQuitRequested) =
true;
1196 draw_data = gui->plugin->pollGUIRender(gui->callback);
1197 gui->plugin->pollGUIPostRender(gui->window, draw_data);
1200 *(gui->frameCost) = (frameEnd - frameStart) / 1000000.f;
1201 *(gui->frameLatency) = frameLatency / 1000000.f;
1202 gui->frameLast = frameStart;
1204 void* draw_data =
nullptr;
1207 uint64_t frameLatency = frameStart - gui->frameLast;
1210 if (frameLatency / 1000000 > 15) {
1211 if (!gui->plugin->pollGUIPreRender(gui->window, (
float)frameLatency / 1000000000.0f)) {
1212 *(gui->guiQuitRequested) =
true;
1216 draw_data = gui->plugin->pollGUIRender(gui->callback);
1217 gui->plugin->pollGUIPostRender(gui->window, draw_data);
1219 draw_data = gui->lastFrame;
1222 if (frameLatency / 1000000 > 15) {
1224 *(gui->frameCost) = (frameEnd - frameStart) / 1000000.f;
1225 *(gui->frameLatency) = frameLatency / 1000000.f;
1226 gui->frameLast = frameStart;
1235 auto* infos =
reinterpret_cast<DeviceInfos*
>(ctx->data);
1241 auto* infos =
reinterpret_cast<DeviceInfos*
>(ctx->data);
1247 auto performanceMetrics = o2::monitoring::ProcessMonitor::getAvailableMetricsNames();
1248 auto dumpableMetrics = std::vector<std::regex>{};
1249 for (
const auto& metric : performanceMetrics) {
1250 dumpableMetrics.emplace_back(metric);
1252 dumpableMetrics.emplace_back(
"^arrow-bytes-delta$");
1253 dumpableMetrics.emplace_back(
"^aod-bytes-read-uncompressed$");
1254 dumpableMetrics.emplace_back(
"^aod-bytes-read-compressed$");
1255 dumpableMetrics.emplace_back(
"^aod-file-read-info$");
1256 dumpableMetrics.emplace_back(
"^aod-largest-object-written$");
1257 dumpableMetrics.emplace_back(
"^aod-invalid-read-skipped-timeframes$");
1258 dumpableMetrics.emplace_back(
"^aod-file-open-skipped-files$");
1259 dumpableMetrics.emplace_back(
"^table-bytes-.*");
1260 dumpableMetrics.emplace_back(
"^total-timeframes.*");
1261 dumpableMetrics.emplace_back(
"^device_state.*");
1262 dumpableMetrics.emplace_back(
"^total_wall_time_ms$");
1263 dumpableMetrics.emplace_back(
"^ccdb-.*$");
1264 return dumpableMetrics;
1272 std::ofstream
file(context->driver->resourcesMonitoringFilename, std::ios::out);
1274 context->driver->metrics, *(context->specs), performanceMetrics,
1280 if (infos.empty()) {
1283 LOGP(info,
"## Processes completed. Run summary:");
1284 LOGP(info,
"### Devices started: {}", infos.size());
1285 for (
size_t di = 0;
di < infos.size(); ++
di) {
1286 auto& info = infos[
di];
1287 auto& spec = specs[
di];
1288 if (info.exitStatus) {
1289 LOGP(
error,
" - Device {}: pid {} (exit {})", spec.name, info.pid, info.exitStatus);
1291 LOGP(info,
" - Device {}: pid {} (exit {})", spec.name, info.pid, info.exitStatus);
1293 if (info.exitStatus != 0 && info.firstSevereError.empty() ==
false) {
1294 LOGP(info,
" - First error: {}", info.firstSevereError);
1296 if (info.exitStatus != 0 && info.lastError != info.firstSevereError) {
1297 LOGP(info,
" - Last error: {}", info.lastError);
1306 uv_tcp_init(serverContext.loop, &serverContext.serverHandle);
1308 driverInfo.port = 8080 + (getpid() % 30000);
1310 if (getenv(
"DPL_REMOTE_GUI_PORT")) {
1312 driverInfo.port = stoi(std::string(getenv(
"DPL_REMOTE_GUI_PORT")));
1313 }
catch (std::invalid_argument) {
1314 LOG(
error) <<
"DPL_REMOTE_GUI_PORT not a valid integer";
1315 }
catch (std::out_of_range) {
1316 LOG(
error) <<
"DPL_REMOTE_GUI_PORT out of range (integer)";
1318 if (driverInfo.port < 1024 || driverInfo.port > 65535) {
1319 LOG(
error) <<
"DPL_REMOTE_GUI_PORT out of range (1024-65535)";
1324 struct sockaddr_in* serverAddr =
nullptr;
1331 if (serverContext.isDriver) {
1334 if (driverInfo.port > 64000) {
1335 throw runtime_error_f(
"Unable to find a free port for the driver. Last attempt returned %d",
result);
1337 serverAddr = (sockaddr_in*)
malloc(
sizeof(sockaddr_in));
1338 uv_ip4_addr(
"0.0.0.0", driverInfo.port, serverAddr);
1339 auto bindResult = uv_tcp_bind(&serverContext.serverHandle, (
const struct sockaddr*)serverAddr, 0);
1340 if (bindResult != 0) {
1352 }
else if (getenv(
"DPL_DEVICE_REMOTE_GUI") && !serverContext.isDriver) {
1355 if (driverInfo.port > 64000) {
1356 throw runtime_error_f(
"Unable to find a free port for the driver. Last attempt returned %d",
result);
1358 serverAddr = (sockaddr_in*)
malloc(
sizeof(sockaddr_in));
1359 uv_ip4_addr(
"0.0.0.0", driverInfo.port, serverAddr);
1360 auto bindResult = uv_tcp_bind(&serverContext.serverHandle, (
const struct sockaddr*)serverAddr, 0);
1361 if (bindResult != 0) {
1372 LOG(info) <<
"Device GUI port: " << driverInfo.port <<
" " << frameworkId;
1383 DriverInfo& driverInfo,
1385 std::vector<DeviceMetricsInfo>& metricsInfos,
1386 std::vector<ConfigParamSpec>
const& detectedParams,
1387 boost::program_options::variables_map& varmap,
1388 std::vector<ServiceSpec>& driverServices,
1389 std::string frameworkId)
1393 .shmSegmentId = (int16_t)atoi(varmap[
"shm-segment-id"].as<std::string>().c_str())};
1397 auto* devicesManager =
new DevicesManager{.
controls = controls, .infos = infos, .specs = runningWorkflow.devices, .messages = {}};
1401 std::vector<uv_poll_t*> pollHandles;
1402 std::vector<DeviceStdioContext> childFds;
1404 std::vector<ComputingResource> resources;
1406 if (driverInfo.resources !=
"") {
1412 auto resourceManager = std::make_unique<SimpleResourceManager>(resources);
1415 void* window =
nullptr;
1416 decltype(debugGUI->
getGUIDebugger(infos, runningWorkflow.devices, allStates, dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl)) debugGUICallback;
1419 auto initDebugGUI = []() ->
DebugGUI* {
1420 uv_lib_t supportLib;
1423 result = uv_dlopen(
"libO2FrameworkGUISupport.dylib", &supportLib);
1425 result = uv_dlopen(
"libO2FrameworkGUISupport.so", &supportLib);
1428 LOG(
error) << uv_dlerror(&supportLib);
1433 result = uv_dlsym(&supportLib,
"dpl_plugin_callback", (
void**)&dpl_plugin_callback);
1435 LOG(
error) << uv_dlerror(&supportLib);
1439 return PluginManager::getByName<DebugGUI>(pluginInstance,
"ImGUIDebugGUI");
1447 if ((driverConfig.
batch ==
false || getenv(
"DPL_DRIVER_REMOTE_GUI") !=
nullptr) && frameworkId.empty()) {
1448 debugGUI = initDebugGUI();
1450 if (driverConfig.
batch ==
false) {
1451 window = debugGUI->
initGUI(
"O2 Framework debug GUI", serviceRegistry);
1453 window = debugGUI->
initGUI(
nullptr, serviceRegistry);
1456 }
else if (getenv(
"DPL_DEVICE_REMOTE_GUI") && !frameworkId.empty()) {
1457 debugGUI = initDebugGUI();
1465 window = debugGUI->
initGUI(
nullptr, serviceRegistry);
1468 if (driverConfig.
batch ==
false && window ==
nullptr && frameworkId.empty()) {
1469 LOG(warn) <<
"Could not create GUI. Switching to batch mode. Do you have GLFW on your system?";
1470 driverConfig.
batch =
true;
1471 if (varmap[
"error-policy"].defaulted()) {
1472 driverInfo.processingPolicies.error = TerminationPolicy::QUIT;
1475 bool guiQuitRequested =
false;
1476 bool hasError =
false;
1480 DriverState current;
1481 DriverState previous;
1487 if (!driverConfig.
batch) {
1489 uv_timer_init(loop, gui_timer);
1492 std::vector<ServiceMetricHandling> metricProcessingCallbacks;
1493 std::vector<ServiceSummaryHandling> summaryCallbacks;
1494 std::vector<ServicePreSchedule> preScheduleCallbacks;
1495 std::vector<ServicePostSchedule> postScheduleCallbacks;
1496 std::vector<ServiceDriverInit> driverInitCallbacks;
1497 for (
auto& service : driverServices) {
1498 if (service.driverStartup ==
nullptr) {
1501 service.driverStartup(serviceRegistry,
DeviceConfig{varmap});
1505 ref.
registerService(ServiceRegistryHelpers::handleForService<DevicesManager>(devicesManager));
1507 bool guiTimerExpired =
false;
1509 guiContext.
plugin = debugGUI;
1512 guiContext.
frameCost = &driverInfo.frameCost;
1521 .controls = &controls,
1523 .states = &allStates,
1524 .specs = &runningWorkflow.devices,
1525 .metrics = &metricsInfos,
1526 .metricProcessingCallbacks = &metricProcessingCallbacks,
1527 .summaryCallbacks = &summaryCallbacks,
1528 .driver = &driverInfo,
1530 .isDriver = frameworkId.empty(),
1533 serverContext.serverHandle.data = &serverContext;
1536 uv_timer_init(loop, &force_step_timer);
1538 uv_timer_init(loop, &force_exit_timer);
1540 bool guiDeployedOnce =
false;
1544 metricDumpTimer.data = &serverContext;
1545 bool allChildrenGone =
false;
1552 serverContext.asyncLogProcessing->data = &serverContext;
1553 uv_async_init(loop, serverContext.asyncLogProcessing, [](
uv_async_t*
handle) {
1554 auto* context = (DriverServerContext*)handle->data;
1555 processChildrenOutput(context->loop, *context->driver, *context->infos, *context->specs, *context->controls);
1556 for (auto* statusHandler : context->statusHandlers) {
1557 for (size_t di = 0; di < context->infos->size(); ++di) {
1558 statusHandler->sendNewLogs(di);
1565 if (driverControl.forcedTransitions.empty() ==
false) {
1566 for (
auto transition : driverControl.forcedTransitions) {
1567 driverInfo.states.push_back(transition);
1569 driverControl.forcedTransitions.resize(0);
1574 auto currentTime = uv_hrtime();
1575 uint64_t diff = (currentTime - driverInfo.startTime) / 1000000000LL;
1576 if ((
graceful_exit ==
false) && (driverInfo.timeout > 0) && (diff > driverInfo.timeout)) {
1577 LOG(info) <<
"Timout ellapsed. Requesting to quit.";
1582 if (
graceful_exit ==
true && driverInfo.sigintRequested ==
false) {
1583 driverInfo.sigintRequested =
true;
1584 driverInfo.states.resize(0);
1585 driverInfo.states.push_back(DriverState::QUIT_REQUESTED);
1590 driverInfo.sigchldRequested =
true;
1591 driverInfo.states.push_back(DriverState::HANDLE_CHILDREN);
1593 if (driverInfo.states.empty() ==
false) {
1595 current = driverInfo.states.back();
1597 current = DriverState::UNKNOWN;
1599 driverInfo.states.pop_back();
1601 case DriverState::BIND_GUI_PORT:
1602 bindGUIPort(driverInfo, serverContext, frameworkId);
1604 case DriverState::INIT:
1605 LOGP(info,
"Initialising O2 Data Processing Layer. Driver PID: {}.", getpid());
1606 LOGP(info,
"Driver listening on port: {}", driverInfo.port);
1609 driverInfo.sa_handle_child.sa_handler = &handle_sigchld;
1610 sigemptyset(&driverInfo.sa_handle_child.sa_mask);
1611 driverInfo.sa_handle_child.sa_flags = SA_RESTART | SA_NOCLDSTOP;
1612 if (sigaction(SIGCHLD, &driverInfo.sa_handle_child,
nullptr) == -1) {
1619 if (driverInfo.noSHMCleanup) {
1620 LOGP(warning,
"Not cleaning up shared memory.");
1628 for (
auto& callback : driverInitCallbacks) {
1629 callback(serviceRegistry, {varmap});
1631 driverInfo.states.push_back(DriverState::RUNNING);
1633 LOG(info) <<
"O2 Data Processing Layer initialised. We brake for nobody.";
1635 LOGF(info,
"Optimised build. O2DEBUG / LOG(debug) / LOGF(debug) / assert statement will not be shown.");
1638 case DriverState::IMPORT_CURRENT_WORKFLOW:
1641 dataProcessorInfos = previousDataProcessorInfos;
1642 for (
auto const&
device : runningWorkflow.devices) {
1643 auto exists = std::find_if(dataProcessorInfos.begin(),
1644 dataProcessorInfos.end(),
1646 if (exists != dataProcessorInfos.end()) {
1650 for (
auto channel :
device.inputChannels) {
1653 for (
auto channel :
device.outputChannels) {
1656 dataProcessorInfos.push_back(
1659 workflowInfo.executable,
1661 workflowInfo.options,
1665 case DriverState::MATERIALISE_WORKFLOW:
1668 if (driverConfig.batch ==
true && varmap[
"dds"].as<std::string>().empty() && !varmap[
"dump-workflow"].as<
bool>() && workflowState == WorkflowParsingState::Empty) {
1669 LOGP(
error,
"Empty workflow provided while running in batch mode.");
1675 auto altered_workflow = workflow;
1677 auto controlParamFromName = [](std::string
const& paramName) {
1678 std::regex name_regex(R
"(^control:([\w-]+)\/(\w+))");
1679 auto match = std::sregex_token_iterator(paramName.begin(), paramName.end(), name_regex, 0);
1680 if (
match == std::sregex_token_iterator()) {
1681 throw runtime_error_f(
"Malformed process control spec: %s", paramName.c_str());
1683 std::string task = std::sregex_token_iterator(paramName.begin(), paramName.end(), name_regex, 1)->str();
1684 std::string conf = std::sregex_token_iterator(paramName.begin(), paramName.end(), name_regex, 2)->str();
1685 return std::pair{task, conf};
1687 bool altered =
false;
1689 std::unordered_map<std::string, std::string> ccdbPaths;
1690 for (
auto&
device : altered_workflow) {
1692 if (
device.name.find(
"internal") != std::string::npos) {
1696 if (
device.inputs.empty() ==
true) {
1700 auto hasMetadata = std::ranges::any_of(
device.inputs, [](
InputSpec const& spec) {
1701 return spec.metadata.empty() == false;
1707 auto hasControlsOrCcdbs = std::ranges::any_of(
device.inputs, [](
InputSpec const& spec) {
1708 return std::ranges::any_of(spec.metadata, [](ConfigParamSpec const& param) {
1709 return param.type == VariantType::Bool && (param.name.starts_with(
"control:") || param.name.starts_with(
"ccdb:"));
1712 if (!hasControlsOrCcdbs) {
1716 LOGP(
debug,
"Adjusting device {}",
device.name.c_str());
1719 if (configStore !=
nullptr) {
1720 auto reg = std::make_unique<ConfigParamRegistry>(std::move(configStore));
1721 for (
auto& input :
device.inputs) {
1722 for (
auto&
param : input.metadata) {
1723 if (
param.type == VariantType::Bool &&
param.name.starts_with(
"control:")) {
1725 if (
param.name !=
"control:default" &&
param.name !=
"control:spawn" &&
param.name !=
"control:build" &&
param.name !=
"control:define") {
1726 auto confName = controlParamFromName(
param.name).second;
1727 param.defaultValue = reg->get<
bool>(confName.c_str());
1729 }
else if (
param.type == VariantType::String &&
param.name.starts_with(
"ccdb:")) {
1731 param.defaultValue = reg->get<std::string>(
param.name.c_str());
1737 for (
auto& input :
device.inputs) {
1738 for (
auto&
param : input.metadata) {
1739 if (
param.type != VariantType::String || !
param.name.starts_with(
"ccdb:")) {
1742 if (ccdbPaths.contains(
param.name)) {
1743 if (ccdbPaths[
param.name] !=
param.defaultValue.get<std::string>()) {
1744 throw runtime_error_f(fmt::format(
"Task {} has a CCDB path inconsistent with another found in same workflow: {} vs {}",
1746 param.defaultValue.get<std::string>().c_str(),
1747 ccdbPaths[
param.name].c_str())
1751 ccdbPaths.emplace(
param.name,
param.defaultValue.get<std::string>());
1757 LOGP(
debug,
"Original inputs: ");
1758 for (
auto& input :
device.inputs) {
1759 LOGP(
debug,
"-> {}", input.binding);
1763 auto requested = false;
1764 auto hasControls = false;
1765 for (auto& param : input.metadata) {
1766 if (param.type != VariantType::Bool) {
1769 if (param.name.find(
"control:") != std::string::npos) {
1771 if (param.defaultValue.get<bool>() == true) {
1783 LOGP(
debug,
"Adjusted inputs: ");
1784 for (
auto& input :
device.inputs) {
1792 for (
auto& service : driverServices) {
1793 if (service.adjustTopology ==
nullptr) {
1796 service.adjustTopology(
node, *driverInfo.configContext);
1804 driverInfo.channelPolicies,
1805 driverInfo.completionPolicies,
1806 driverInfo.dispatchPolicies,
1807 driverInfo.resourcePolicies,
1808 driverInfo.callbacksPolicies,
1809 driverInfo.sendingPolicies,
1810 driverInfo.forwardingPolicies,
1811 runningWorkflow.devices,
1813 driverInfo.uniqueWorkflowId,
1814 *driverInfo.configContext,
1815 !varmap[
"no-IPC"].as<
bool>(),
1816 driverInfo.resourcesMonitoringInterval,
1817 varmap[
"channel-prefix"].as<std::string>(),
1819 metricProcessingCallbacks.clear();
1820 std::vector<std::string> matchingServices;
1823 matchingServices.clear();
1824 for (
auto&
device : runningWorkflow.devices) {
1825 for (
auto& service :
device.services) {
1827 if (std::find(matchingServices.begin(), matchingServices.end(), service.name) != matchingServices.end()) {
1830 if (service.metricHandling) {
1831 metricProcessingCallbacks.push_back(service.metricHandling);
1832 matchingServices.push_back(service.name);
1838 matchingServices.clear();
1839 for (
auto&
device : runningWorkflow.devices) {
1840 for (
auto& service :
device.services) {
1842 if (std::find(matchingServices.begin(), matchingServices.end(), service.name) != matchingServices.end()) {
1845 if (service.summaryHandling) {
1846 summaryCallbacks.push_back(service.summaryHandling);
1847 matchingServices.push_back(service.name);
1852 preScheduleCallbacks.clear();
1853 matchingServices.clear();
1854 for (
auto&
device : runningWorkflow.devices) {
1855 for (
auto& service :
device.services) {
1857 if (std::find(matchingServices.begin(), matchingServices.end(), service.name) != matchingServices.end()) {
1860 if (service.preSchedule) {
1861 preScheduleCallbacks.push_back(service.preSchedule);
1865 postScheduleCallbacks.clear();
1866 matchingServices.clear();
1867 for (
auto&
device : runningWorkflow.devices) {
1868 for (
auto& service :
device.services) {
1870 if (std::find(matchingServices.begin(), matchingServices.end(), service.name) != matchingServices.end()) {
1873 if (service.postSchedule) {
1874 postScheduleCallbacks.push_back(service.postSchedule);
1878 driverInitCallbacks.clear();
1879 matchingServices.clear();
1880 for (
auto&
device : runningWorkflow.devices) {
1881 for (
auto& service :
device.services) {
1883 if (std::find(matchingServices.begin(), matchingServices.end(), service.name) != matchingServices.end()) {
1886 if (service.driverInit) {
1887 driverInitCallbacks.push_back(service.driverInit);
1895 for (
auto&
device : runningWorkflow.devices) {
1897 if (
device.name.find(
"internal") != std::string::npos) {
1901 if (configStore !=
nullptr) {
1902 auto reg = std::make_unique<ConfigParamRegistry>(std::move(configStore));
1906 case VariantType::Int:
1909 case VariantType::Int8:
1912 case VariantType::Int16:
1913 option.defaultValue = reg->get<int16_t>(
name);
1915 case VariantType::UInt8:
1918 case VariantType::UInt16:
1921 case VariantType::UInt32:
1924 case VariantType::UInt64:
1927 case VariantType::Int64:
1930 case VariantType::Float:
1933 case VariantType::Double:
1934 option.defaultValue = reg->get<
double>(
name);
1936 case VariantType::String:
1937 option.defaultValue = reg->get<std::string>(
name);
1939 case VariantType::Bool:
1942 case VariantType::ArrayInt:
1943 option.defaultValue = reg->get<std::vector<int>>(
name);
1945 case VariantType::ArrayFloat:
1946 option.defaultValue = reg->get<std::vector<float>>(
name);
1948 case VariantType::ArrayDouble:
1949 option.defaultValue = reg->get<std::vector<double>>(
name);
1951 case VariantType::ArrayString:
1952 option.defaultValue = reg->get<std::vector<std::string>>(
name);
1954 case VariantType::Array2DInt:
1957 case VariantType::Array2DFloat:
1960 case VariantType::Array2DDouble:
1963 case VariantType::LabeledArrayInt:
1966 case VariantType::LabeledArrayFloat:
1969 case VariantType::LabeledArrayDouble:
1972 case VariantType::LabeledArrayString:
1981 }
catch (std::runtime_error&
e) {
1982 LOGP(
error,
"invalid workflow in {}: {}", driverInfo.argv[0],
e.what());
1986#ifdef DPL_ENABLE_BACKTRACE
1989 LOGP(
error,
"invalid workflow in {}: {}", driverInfo.argv[0], err.what);
1992 LOGP(
error,
"invalid workflow in {}: Unknown error while materialising workflow", driverInfo.argv[0]);
1996 case DriverState::DO_CHILD:
1998 if (driverControl.defaultStopped) {
1999 kill(getpid(), SIGSTOP);
2001 for (
size_t di = 0;
di < runningWorkflow.devices.size();
di++) {
2003 if (runningWorkflow.devices[
di].id == frameworkId) {
2004 return doChild(driverInfo.argc, driverInfo.argv,
2007 runningWorkflow,
ref,
2009 driverInfo.processingPolicies,
2010 driverInfo.defaultDriverClient,
2015 std::ostringstream ss;
2016 for (
auto& processor : workflow) {
2017 ss <<
" - " << processor.name <<
"\n";
2019 for (
auto& spec : runningWorkflow.devices) {
2020 ss <<
" - " << spec.name <<
"(" << spec.id <<
")"
2023 driverInfo.lastError = fmt::format(
2024 "Unable to find component with id {}."
2025 " Available options:\n{}",
2026 frameworkId, ss.str());
2027 driverInfo.states.push_back(DriverState::QUIT_REQUESTED);
2030 case DriverState::REDEPLOY_GUI:
2040 if (!driverConfig.batch || getenv(
"DPL_DRIVER_REMOTE_GUI")) {
2042 uv_timer_stop(gui_timer);
2045 auto callback = debugGUI->getGUIDebugger(infos, runningWorkflow.devices, allStates, dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl);
2046 guiContext.callback = [&serviceRegistry, &driverServices, &debugGUI, &infos, &runningWorkflow, &dataProcessorInfos, &metricsInfos, &driverInfo, &controls, &driverControl, callback]() {
2048 for (
auto& service : driverServices) {
2049 if (service.postRenderGUI) {
2050 service.postRenderGUI(serviceRegistry);
2054 guiContext.window = window;
2057 gui_timer->data = &guiContext;
2060 guiDeployedOnce =
true;
2063 case DriverState::MERGE_CONFIGS: {
2065 controls.resize(runningWorkflow.devices.size());
2068 if (varmap.count(
"dpl-tracing-flags")) {
2069 for (
auto& control : controls) {
2071 control.tracingFlags = tracingFlags;
2074 deviceExecutions.resize(runningWorkflow.devices.size());
2078 const auto uniformOptions = {
2080 "--aod-memory-rate-limit",
2081 "--aod-writer-json",
2082 "--aod-writer-ntfmerge",
2083 "--aod-writer-resdir",
2084 "--aod-writer-resfile",
2085 "--aod-writer-resmode",
2086 "--aod-writer-maxfilesize",
2087 "--aod-writer-keep",
2088 "--aod-max-io-rate",
2089 "--aod-reader-backend",
2090 "--aod-reader-threads",
2091 "--aod-reader-prefetch",
2092 "--aod-reader-local-io",
2093 "--aod-reader-buffer-mb",
2094 "--aod-parent-access-level",
2095 "--aod-parent-base-path-replacement",
2096 "--aod-origin-level-mapping",
2097 "--driver-client-backend",
2098 "--fairmq-ipc-prefix",
2101 "--resources-monitoring",
2102 "--resources-monitoring-file",
2103 "--resources-monitoring-dump-interval",
2107 for (
auto&
option : uniformOptions) {
2113 driverControl.defaultStopped,
2114 driverInfo.processingPolicies.termination == TerminationPolicy::WAIT,
2118 runningWorkflow.devices,
2122 driverInfo.uniqueWorkflowId);
2125 LOGP(
error,
"unable to merge configurations in {}: {}", driverInfo.argv[0], err.what);
2126#ifdef DPL_ENABLE_BACKTRACE
2127 std::cerr <<
"\nStacktrace follows:\n\n";
2133 case DriverState::SCHEDULE: {
2138 LOG(info) <<
"Redeployment of configuration asked.";
2139 std::ostringstream forwardedStdin;
2141 infos.reserve(runningWorkflow.devices.size());
2144 unsigned parentCPU = -1;
2145 unsigned parentNode = -1;
2146#if defined(__linux__) && __has_include(<sched.h>)
2147 parentCPU = sched_getcpu();
2148#elif __has_include(<linux/getcpu.h>)
2149 getcpu(&parentCPU, &parentNode,
nullptr);
2150#elif __has_include(<cpuid.h>) && (__x86_64__ || __i386__)
2155 for (
auto& callback : preScheduleCallbacks) {
2156 callback(serviceRegistry, {varmap});
2158 childFds.resize(runningWorkflow.devices.size());
2159 for (
int di = 0;
di < (
int)runningWorkflow.devices.size(); ++
di) {
2160 auto& context = childFds[
di];
2163 if (driverInfo.mode == DriverMode::EMBEDDED || runningWorkflow.devices[
di].resource.hostname != driverInfo.deployHostname) {
2165 runningWorkflow.devices[
di], controls[
di], deviceExecutions[
di], infos, allStates);
2170 runningWorkflow.devices, driverInfo,
2171 controls, deviceExecutions, infos,
2173 serviceRegistry, varmap,
2174 childFds, parentCPU, parentNode);
2179 for (
auto& callback : postScheduleCallbacks) {
2180 callback(serviceRegistry, {varmap});
2182 assert(infos.empty() ==
false);
2187 uv_timer_init(loop, &metricDumpTimer);
2189 driverInfo.resourcesMonitoringDumpInterval * 1000,
2190 driverInfo.resourcesMonitoringDumpInterval * 1000);
2193 for (
const auto& processorInfo : dataProcessorInfos) {
2194 const auto& cmdLineArgs = processorInfo.cmdLineArgs;
2195 if (std::find(cmdLineArgs.begin(), cmdLineArgs.end(),
"--severity") != cmdLineArgs.end()) {
2196 for (
size_t counter = 0;
const auto& spec : runningWorkflow.devices) {
2197 if (spec.name.compare(processorInfo.name) == 0) {
2199 const auto logLevelIt = std::find(cmdLineArgs.begin(), cmdLineArgs.end(),
"--severity") + 1;
2200 if ((*logLevelIt).compare(
"debug") == 0) {
2201 info.logLevel = LogParsingHelpers::LogLevel::Debug;
2202 }
else if ((*logLevelIt).compare(
"detail") == 0) {
2203 info.logLevel = LogParsingHelpers::LogLevel::Debug;
2204 }
else if ((*logLevelIt).compare(
"info") == 0) {
2205 info.logLevel = LogParsingHelpers::LogLevel::Info;
2206 }
else if ((*logLevelIt).compare(
"warning") == 0) {
2207 info.logLevel = LogParsingHelpers::LogLevel::Warning;
2208 }
else if ((*logLevelIt).compare(
"error") == 0) {
2209 info.logLevel = LogParsingHelpers::LogLevel::Error;
2210 }
else if ((*logLevelIt).compare(
"important") == 0) {
2211 info.logLevel = LogParsingHelpers::LogLevel::Info;
2212 }
else if ((*logLevelIt).compare(
"alarm") == 0) {
2213 info.logLevel = LogParsingHelpers::LogLevel::Alarm;
2214 }
else if ((*logLevelIt).compare(
"critical") == 0) {
2215 info.logLevel = LogParsingHelpers::LogLevel::Critical;
2216 }
else if ((*logLevelIt).compare(
"fatal") == 0) {
2217 info.logLevel = LogParsingHelpers::LogLevel::Fatal;
2225 LOG(info) <<
"Redeployment of configuration done.";
2227 case DriverState::RUNNING:
2231 devicesManager->flush();
2235 if (guiTimerExpired ==
false) {
2236 O2_SIGNPOST_EVENT_EMIT(driver, sid,
"mainloop",
"Entering event loop with %{public}s", once ?
"UV_RUN_ONCE" :
"UV_RUN_NOWAIT");
2238 uv_run(loop, once ? UV_RUN_ONCE : UV_RUN_NOWAIT);
2242 if (guiQuitRequested ||
2243 (driverInfo.processingPolicies.termination == TerminationPolicy::QUIT && (
checkIfCanExit(infos) ==
true))) {
2248 LOG(info) <<
"Quitting";
2249 driverInfo.states.push_back(DriverState::QUIT_REQUESTED);
2250 }
else if (infos.size() != runningWorkflow.devices.size()) {
2255 driverInfo.states.push_back(DriverState::RUNNING);
2256 driverInfo.states.push_back(DriverState::REDEPLOY_GUI);
2257 driverInfo.states.push_back(DriverState::SCHEDULE);
2258 driverInfo.states.push_back(DriverState::MERGE_CONFIGS);
2259 }
else if (runningWorkflow.devices.empty() && driverConfig.batch ==
true) {
2260 LOG(info) <<
"No device resulting from the workflow. Quitting.";
2262 driverInfo.states.push_back(DriverState::EXIT);
2263 }
else if (runningWorkflow.devices.empty() && driverConfig.batch ==
false && !guiDeployedOnce) {
2265 driverInfo.states.push_back(DriverState::RUNNING);
2266 driverInfo.states.push_back(DriverState::REDEPLOY_GUI);
2268 driverInfo.states.push_back(DriverState::RUNNING);
2271 case DriverState::QUIT_REQUESTED: {
2272 std::time_t
result = std::time(
nullptr);
2276 guiQuitRequested =
true;
2283 force_step_timer.data = &infos;
2285 driverInfo.states.push_back(DriverState::HANDLE_CHILDREN);
2288 case DriverState::HANDLE_CHILDREN: {
2292 uv_run(loop, once ? UV_RUN_ONCE : UV_RUN_NOWAIT);
2297 static bool forcefulExitMessage =
true;
2298 if (forcefulExitMessage) {
2299 LOG(info) <<
"Forceful exit requested.";
2300 forcefulExitMessage =
false;
2306 driverInfo.sigchldRequested =
false;
2311 bool supposedToQuit = (guiQuitRequested || canExit ||
graceful_exit);
2313 if (allChildrenGone && (supposedToQuit || driverInfo.processingPolicies.termination == TerminationPolicy::QUIT)) {
2315 driverInfo.states.resize(0);
2316 driverInfo.states.push_back(DriverState::EXIT);
2317 }
else if (hasError && driverInfo.processingPolicies.error == TerminationPolicy::QUIT && !supposedToQuit) {
2319 force_exit_timer.data = &infos;
2320 static bool forceful_timer_started =
false;
2321 if (forceful_timer_started ==
false) {
2322 forceful_timer_started =
true;
2325 driverInfo.states.push_back(DriverState::QUIT_REQUESTED);
2326 }
else if (allChildrenGone ==
false && supposedToQuit) {
2327 driverInfo.states.push_back(DriverState::HANDLE_CHILDREN);
2331 case DriverState::EXIT: {
2333 if (driverInfo.resourcesMonitoringDumpInterval) {
2334 uv_timer_stop(&metricDumpTimer);
2336 LOGP(info,
"Dumping performance metrics to {}.json file", driverInfo.resourcesMonitoringFilename);
2339 dumpRunSummary(serverContext, driverInfo, infos, runningWorkflow.devices);
2346 if (infos.empty()) {
2349 boost::property_tree::ptree finalConfig;
2350 assert(infos.size() == runningWorkflow.devices.size());
2351 for (
size_t di = 0;
di < infos.size(); ++
di) {
2353 auto& spec = runningWorkflow.devices[
di];
2354 finalConfig.put_child(spec.name,
info.currentConfig);
2356 LOG(info) <<
"Dumping used configuration in dpl-config.json";
2358 std::ofstream outDPLConfigFile(
"dpl-config.json", std::ios::out);
2359 if (outDPLConfigFile.is_open()) {
2360 boost::property_tree::write_json(outDPLConfigFile, finalConfig);
2362 LOGP(warning,
"Could not write out final configuration file. Read only run folder?");
2364 if (driverInfo.noSHMCleanup) {
2365 LOGP(warning,
"Not cleaning up shared memory.");
2369 return calculateExitCode(driverInfo, runningWorkflow.devices, infos);
2371 case DriverState::PERFORM_CALLBACKS:
2372 for (
auto& callback : driverControl.callbacks) {
2373 callback(workflow, runningWorkflow.devices, deviceExecutions, dataProcessorInfos, commandInfo);
2375 driverControl.callbacks.clear();
2378 LOG(
error) <<
"Driver transitioned in an unknown state("
2379 <<
"current: " << (
int)current
2380 <<
", previous: " << (
int)previous
2381 <<
"). Shutting down.";
2382 driverInfo.states.push_back(DriverState::QUIT_REQUESTED);
2390 bpo::options_description
const& executorOptions,
2391 std::vector<DataProcessorSpec>
const& physicalWorkflow,
2392 std::vector<ConfigParamSpec>
const& currentWorkflowOptions)
2394 auto mode = varmap[
"help"].as<std::string>();
2395 bpo::options_description helpOptions;
2396 if (
mode ==
"full" ||
mode ==
"short" ||
mode ==
"executor") {
2397 helpOptions.add(executorOptions);
2400 if (
mode ==
"executor") {
2402 }
else if (
mode ==
"workflow") {
2406 }
else if (
mode ==
"full" ||
mode ==
"short") {
2408 bpo::options_description(),
2412 bpo::options_description(),
2415 if (helpOptions.options().size() == 0) {
2417 mode +=
" is an invalid argument, please use correct argument for";
2418 helpOptions.add(executorOptions);
2420 std::cout <<
"ALICE O2 DPL workflow driver"
2421 <<
" (" <<
mode <<
" help)" << std::endl
2422 << helpOptions << std::endl;
2429 fstat(STDOUT_FILENO, &
s);
2430 return ((
s.st_mode & S_IFIFO) != 0);
2436 int r = fstat(STDIN_FILENO, &
s);
2443 return ((
s.st_mode & S_IFIFO) != 0 || (
s.st_mode & S_IFREG) != 0);
2448 struct CloningSpec {
2449 std::string templateMatcher;
2450 std::string cloneName;
2452 auto s = ctx.options().get<std::string>(
"clone");
2453 std::vector<CloningSpec> specs;
2454 std::string delimiter =
",";
2456 while (
s.empty() ==
false) {
2457 auto newPos =
s.find(delimiter);
2458 auto token =
s.substr(0, newPos);
2459 auto split = token.find(
":");
2460 if (
split == std::string::npos) {
2461 throw std::runtime_error(
"bad clone definition. Syntax <template-processor>:<clone-name>");
2464 token.erase(0,
split + 1);
2466 std::string
value =
"";
2468 auto numValue = std::stoll(token, &
error, 10);
2469 if (token[
error] !=
'\0') {
2470 throw std::runtime_error(
"bad name for clone:" + token);
2473 }
catch (std::invalid_argument&
e) {
2477 s.erase(0, newPos + (newPos == std::string::npos ? 0 : 1));
2479 if (
s.empty() ==
false && specs.empty() ==
true) {
2480 throw std::runtime_error(
"bad pipeline definition. Syntax <processor>:<pipeline>");
2483 std::vector<DataProcessorSpec> extraSpecs;
2484 for (
auto& spec : specs) {
2485 for (
auto& processor : workflow) {
2486 if (processor.name == spec.templateMatcher) {
2487 auto clone = processor;
2488 clone.name = spec.cloneName;
2489 extraSpecs.push_back(clone);
2493 workflow.insert(workflow.end(), extraSpecs.begin(), extraSpecs.end());
2498 struct PipelineSpec {
2499 std::string matcher;
2502 auto s = ctx.options().get<std::string>(
"pipeline");
2503 std::vector<PipelineSpec> specs;
2504 std::string delimiter =
",";
2506 while (
s.empty() ==
false) {
2507 auto newPos =
s.find(delimiter);
2508 auto token =
s.substr(0, newPos);
2509 auto split = token.find(
":");
2510 if (
split == std::string::npos) {
2511 throw std::runtime_error(
"bad pipeline definition. Syntax <processor>:<pipeline>");
2514 token.erase(0,
split + 1);
2517 if (token[
error] !=
'\0') {
2518 throw std::runtime_error(
"Bad pipeline definition. Expecting integer");
2521 s.erase(0, newPos + (newPos == std::string::npos ? 0 : 1));
2523 if (
s.empty() ==
false && specs.empty() ==
true) {
2524 throw std::runtime_error(
"bad pipeline definition. Syntax <processor>:<pipeline>");
2527 for (
auto& spec : specs) {
2528 for (
auto& processor : workflow) {
2529 if (processor.name == spec.matcher) {
2530 processor.maxInputTimeslices = spec.pipeline;
2539 std::string_view matcher;
2540 std::vector<std::string>
labels;
2542 std::vector<LabelsSpec> specs;
2544 auto labelsString = ctx.options().get<std::string>(
"labels");
2545 if (labelsString.empty()) {
2548 std::string_view sv{labelsString};
2550 size_t specStart = 0;
2552 constexpr char specDelim =
',';
2553 constexpr char labelDelim =
':';
2555 specEnd = sv.find(specDelim, specStart);
2556 auto token = sv.substr(specStart, specEnd == std::string_view::npos ? std::string_view::npos : specEnd - specStart);
2557 if (token.empty()) {
2558 throw std::runtime_error(
"bad labels definition. Syntax <processor>:<label>[:<label>][,<processor>:<label>[:<label>]");
2561 size_t labelDelimPos = token.find(labelDelim);
2562 if (labelDelimPos == 0 || labelDelimPos == std::string_view::npos) {
2563 throw std::runtime_error(
"bad labels definition. Syntax <processor>:<label>[:<label>][,<processor>:<label>[:<label>]");
2565 LabelsSpec spec{.matcher = token.substr(0, labelDelimPos), .labels = {}};
2567 size_t labelEnd = labelDelimPos + 1;
2569 size_t labelStart = labelDelimPos + 1;
2570 labelEnd = token.find(labelDelim, labelStart);
2571 auto label = labelEnd == std::string_view::npos ? token.substr(labelStart) : token.substr(labelStart, labelEnd - labelStart);
2572 if (
label.empty()) {
2573 throw std::runtime_error(
"bad labels definition. Syntax <processor>:<label>[:<label>][,<processor>:<label>[:<label>]");
2575 spec.labels.emplace_back(
label);
2576 labelDelimPos = labelEnd;
2577 }
while (labelEnd != std::string_view::npos);
2579 specs.push_back(spec);
2580 specStart = specEnd + 1;
2581 }
while (specEnd != std::string_view::npos);
2583 if (labelsString.empty() ==
false && specs.empty() ==
true) {
2584 throw std::runtime_error(
"bad labels definition. Syntax <processor>:<label>[:<label>][,<processor>:<label>[:<label>]");
2587 for (
auto& spec : specs) {
2588 for (
auto& processor : workflow) {
2589 if (processor.name == spec.matcher) {
2590 for (
const auto&
label : spec.labels) {
2591 if (std::find_if(processor.labels.begin(), processor.labels.end(),
2592 [
label](
const auto& procLabel) { return procLabel.value == label; }) == processor.labels.end()) {
2593 processor.labels.push_back({
label});
2603 DriverInfo& driverInfo,
2611 if (varmap[
"single-step"].as<bool>()) {
2612 control.
state = DriverControlState::STEP;
2614 control.
state = DriverControlState::PLAY;
2617 if (varmap[
"graphviz"].as<bool>()) {
2628 DriverState::PERFORM_CALLBACKS,
2629 DriverState::MERGE_CONFIGS,
2630 DriverState::IMPORT_CURRENT_WORKFLOW,
2631 DriverState::MATERIALISE_WORKFLOW
2633 }
else if (!varmap[
"dds"].as<std::string>().
empty()) {
2639 workflowSuffix = varmap[
"dds-workflow-suffix"],
2640 driverMode = driverInfo.mode](
WorkflowSpec const& workflow,
2654 DriverState::PERFORM_CALLBACKS,
2655 DriverState::MERGE_CONFIGS,
2656 DriverState::IMPORT_CURRENT_WORKFLOW,
2657 DriverState::MATERIALISE_WORKFLOW
2659 }
else if (!varmap[
"o2-control"].as<std::string>().
empty() or !varmap[
"mermaid"].as<std::string>().
empty()) {
2662 workflowName = varmap[
"o2-control"].as<std::string>()](
WorkflowSpec const&,
2667 if (!workflowName.empty()) {
2681 DriverState::PERFORM_CALLBACKS,
2682 DriverState::MERGE_CONFIGS,
2683 DriverState::IMPORT_CURRENT_WORKFLOW,
2684 DriverState::MATERIALISE_WORKFLOW
2687 }
else if (varmap.count(
"id")) {
2689 if (getenv(
"O2_NO_CATCHALL_EXCEPTIONS") !=
nullptr && strcmp(getenv(
"O2_NO_CATCHALL_EXCEPTIONS"),
"0") != 0) {
2690 LOGP(info,
"Not instrumenting crash signals because O2_NO_CATCHALL_EXCEPTIONS is set");
2691 gEnv->SetValue(
"Root.Stacktrace",
"no");
2692 gSystem->ResetSignal(kSigSegmentationViolation, kTRUE);
2694 if (getrlimit(RLIMIT_CORE, &limit) == 0) {
2695 LOGP(info,
"Core limit: {} {}", limit.rlim_cur, limit.rlim_max);
2698 if (varmap[
"stacktrace-on-signal"].as<std::string>() ==
"simple" && (getenv(
"O2_NO_CATCHALL_EXCEPTIONS") ==
nullptr || strcmp(getenv(
"O2_NO_CATCHALL_EXCEPTIONS"),
"0") == 0)) {
2699 LOGP(info,
"Instrumenting crash signals");
2711 DriverState::DO_CHILD,
2712 DriverState::BIND_GUI_PORT,
2713 DriverState::MERGE_CONFIGS,
2714 DriverState::IMPORT_CURRENT_WORKFLOW,
2715 DriverState::MATERIALISE_WORKFLOW
2717 }
else if ((varmap[
"dump-workflow"].as<bool>() ==
true) || (varmap[
"run"].as<bool>() ==
false && varmap.count(
"id") == 0 &&
isOutputToPipe())) {
2734 DriverState::PERFORM_CALLBACKS,
2735 DriverState::MERGE_CONFIGS,
2736 DriverState::IMPORT_CURRENT_WORKFLOW,
2737 DriverState::MATERIALISE_WORKFLOW
2743 DriverState::BIND_GUI_PORT,
2744 DriverState::IMPORT_CURRENT_WORKFLOW,
2745 DriverState::MATERIALISE_WORKFLOW
2752 const std::string& opt1,
const std::string& opt2)
2754 if (vm.count(opt1) && !vm[opt1].defaulted() &&
2755 vm.count(opt2) && !vm[opt2].defaulted()) {
2756 throw std::logic_error(std::string(
"Conflicting options '") +
2757 opt1 +
"' and '" + opt2 +
"'.");
2761template <
typename T>
2767 for (
int i = 0;
i < (int)
indices.size();
i++) {
2771 swap(
v[current],
v[next]);
2781 std::vector<std::pair<int, int>>
const&
edges)
2784 return label.value ==
"expendable";
2787 return label.value ==
"resilient" ||
label.value ==
"expendable";
2790 for (
auto& edge :
edges) {
2791 auto&
src = specs[edge.first];
2792 auto&
dst = specs[edge.second];
2793 if (std::none_of(
src.labels.begin(),
src.labels.end(), checkExpendable)) {
2796 if (std::any_of(
dst.labels.begin(),
dst.labels.end(), checkResilient)) {
2799 throw std::runtime_error(
"Workflow is not resiliant to failures. Processor " +
dst.name +
" gets inputs from expendable devices, but is not marked as expendable or resilient itself.");
2804 std::vector<TopoIndexInfo>
const& infos,
2805 std::vector<std::pair<int, int>>
const&
edges)
2807 std::ostringstream out;
2809 out <<
"\nTopological info:\n";
2810 for (
auto& ti : infos) {
2811 out << specs[ti.index].name <<
" (index: " << ti.index <<
", layer: " << ti.layer <<
")\n";
2812 out <<
" Inputs:\n";
2813 for (
auto& ii : specs[ti.index].inputs) {
2816 out <<
"\n Outputs:\n";
2817 for (
auto& ii : specs[ti.index].outputs) {
2821 out <<
"\nEdges values:\n";
2823 out << specs[
e.second].name <<
" depends on " << specs[
e.first].name <<
"\n";
2825 for (
auto&
d : specs) {
2826 out <<
"- " <<
d.name << std::endl;
2834 static pid_t
pid = getpid();
2835 if (signpostsToEnable.empty() ==
true) {
2836 auto printAllSignposts = [](
char const*
name,
void* l,
void* context) {
2838 LOGP(detail,
"Signpost stream {} disabled. Enable it with o2-log -p {} -a {}",
name,
pid, (
void*)&log->stacktrace);
2844 auto matchingLogEnabler = [](
char const*
name,
void* l,
void* context) {
2846 auto* selectedName = (
char const*)context;
2847 std::string prefix =
"ch.cern.aliceo2.";
2848 auto* last = strchr(selectedName,
':');
2852 maxDepth = strtol(last + 1, &err, 10);
2853 if (*(last + 1) ==
'\0' || *err !=
'\0') {
2858 auto fullName = prefix + std::string{selectedName, last ? last - selectedName : strlen(selectedName)};
2859 if (fullName ==
name) {
2860 LOGP(info,
"Enabling signposts for stream \"{}\" with depth {}.", fullName,
maxDepth);
2864 LOGP(info,
"Signpost stream \"{}\" disabled. Enable it with o2-log -p {} -a {}",
name,
pid, (
void*)&log->stacktrace);
2870 char*
src =
const_cast<char*
>(signpostsToEnable.data());
2871 auto* token = strtok_r(
src,
",", &saveptr);
2874 token = strtok_r(
nullptr,
",", &saveptr);
2887 std::vector<o2::framework::ConfigParamSpec>& workflowOptions,
2888 std::vector<o2::framework::ConfigParamSpec>& extraOptions,
int argc,
char** argv)
2890 std::vector<std::unique_ptr<o2::framework::ParamRetriever>> retrievers;
2892 retrievers.emplace_back(std::move(retriever));
2893 auto workflowOptionsStore = std::make_unique<o2::framework::ConfigParamStore>(workflowOptions, std::move(retrievers));
2894 workflowOptionsStore->preload();
2895 workflowOptionsStore->activate();
2896 workflowOptionsRegistry = std::make_unique<ConfigParamRegistry>(std::move(workflowOptionsStore));
2898 for (
auto& extra : extraOptions) {
2899 workflowOptions.push_back(extra);
2907 return std::make_unique<o2::framework::ServiceRegistry>();
2920 std::vector<ChannelConfigurationPolicy>
const& channelPolicies,
2921 std::vector<CompletionPolicy>
const& completionPolicies,
2922 std::vector<DispatchPolicy>
const& dispatchPolicies,
2923 std::vector<ResourcePolicy>
const& resourcePolicies,
2924 std::vector<CallbacksPolicy>
const& callbacksPolicies,
2925 std::vector<SendingPolicy>
const& sendingPolicies,
2926 std::vector<ConfigParamSpec>
const& currentWorkflowOptions,
2927 std::vector<ConfigParamSpec>
const& detectedParams,
2932 if (getenv(
"DPL_DRIVER_SIGNPOSTS")) {
2936 std::vector<std::string> currentArgs;
2937 std::vector<PluginInfo> plugins;
2940 for (
int ai = 1; ai < argc; ++ai) {
2941 currentArgs.emplace_back(argv[ai]);
2947 currentWorkflowOptions};
2951 bpo::options_description executorOptions(
"Executor options");
2952 const char* helpDescription =
"print help: short, full, executor, or processor name";
2954 executorOptions.add_options()
2955 (
"help,h", bpo::value<std::string>()->implicit_value(
"short"), helpDescription)
2956 (
"quiet,q", bpo::value<bool>()->zero_tokens()->default_value(
false),
"quiet operation")
2957 (
"stop,s", bpo::value<bool>()->zero_tokens()->default_value(
false),
"stop before device start")
2958 (
"single-step", bpo::value<bool>()->zero_tokens()->default_value(
false),
"start in single step mode")
2959 (
"batch,b", bpo::value<std::vector<std::string>>()->zero_tokens()->composing(),
"batch processing mode")
2960 (
"no-batch", bpo::value<bool>()->zero_tokens(),
"force gui processing mode")
2961 (
"no-cleanup", bpo::value<bool>()->zero_tokens()->default_value(
false),
"do not cleanup the shm segment")
2962 (
"hostname", bpo::value<std::string>()->default_value(
"localhost"),
"hostname to deploy")
2963 (
"resources", bpo::value<std::string>()->default_value(
""),
"resources allocated for the workflow")
2964 (
"start-port,p", bpo::value<unsigned short>()->default_value(22000),
"start port to allocate")
2965 (
"port-range,pr", bpo::value<unsigned short>()->default_value(1000),
"ports in range")
2966 (
"completion-policy,c", bpo::value<TerminationPolicy>(&processingPolicies.
termination)->default_value(TerminationPolicy::QUIT),
2967 "what to do when processing is finished: quit, wait")
2968 (
"error-policy", bpo::value<TerminationPolicy>(&processingPolicies.
error)->default_value(TerminationPolicy::QUIT),
2969 "what to do when a device has an error: quit, wait")
2970 (
"min-failure-level", bpo::value<LogParsingHelpers::LogLevel>(&minFailureLevel)->default_value(LogParsingHelpers::LogLevel::Fatal),
2971 "minimum message level which will be considered as fatal and exit with 1")
2972 (
"graphviz,g", bpo::value<bool>()->zero_tokens()->default_value(
false),
"produce graphviz output")
2973 (
"mermaid", bpo::value<std::string>()->default_value(
""),
"produce graph output in mermaid format in file under specified name or on stdout if argument is \"-\"")
2974 (
"timeout,t", bpo::value<uint64_t>()->default_value(0),
"forced exit timeout (in seconds)")
2975 (
"dds,D", bpo::value<std::string>()->default_value(
""),
"create DDS configuration")
2976 (
"dds-workflow-suffix,D", bpo::value<std::string>()->default_value(
""),
"suffix for DDS names")
2977 (
"dump-workflow,dump", bpo::value<bool>()->zero_tokens()->default_value(
false),
"dump workflow as JSON")
2978 (
"dump-workflow-file", bpo::value<std::string>()->default_value(
"-"),
"file to which do the dump")
2979 (
"driver-mode", bpo::value<DriverMode>(&driverMode)->default_value(DriverMode::STANDALONE), R
"(how to run the driver. default: "standalone". Valid: "embedded")")
2980 (
"run", bpo::value<bool>()->zero_tokens()->default_value(
false),
"run workflow merged so far. It implies --batch. Use --no-batch to see the GUI")
2981 (
"no-IPC", bpo::value<bool>()->zero_tokens()->default_value(
false),
"disable IPC topology optimization")
2982 (
"o2-control,o2", bpo::value<std::string>()->default_value(
""),
"dump O2 Control workflow configuration under the specified name")
2983 (
"resources-monitoring", bpo::value<unsigned short>()->default_value(0),
"enable cpu/memory monitoring for provided interval in seconds")
2984 (
"resources-monitoring-file", bpo::value<std::string>()->default_value(
"performanceMetrics.json"),
"file where to dump the metrics")
2985 (
"resources-monitoring-dump-interval", bpo::value<unsigned short>()->default_value(0),
"dump monitoring information to disk every provided seconds");
2990 (
"id,i", bpo::value<std::string>(),
"device id for child spawning")
2991 (
"channel-config", bpo::value<std::vector<std::string>>(),
"channel configuration")
2992 (
"control",
"control plugin")
2993 (
"log-color",
"logging color scheme")(
"color",
"logging color scheme");
2995 bpo::options_description visibleOptions;
2996 visibleOptions.add(executorOptions);
2998 auto physicalWorkflow = workflow;
2999 std::map<std::string, size_t> rankIndex;
3006 size_t workflowHashA = 0;
3007 std::hash<std::string> hash_fn;
3009 for (
auto& dp : workflow) {
3010 workflowHashA += hash_fn(dp.name);
3013 for (
auto& dp : workflow) {
3014 rankIndex.insert(std::make_pair(dp.name, workflowHashA));
3017 std::vector<DataProcessorInfo> dataProcessorInfos;
3021 std::vector<DataProcessorSpec> importedWorkflow;
3023 if (previousWorked ==
false) {
3027 size_t workflowHashB = 0;
3028 for (
auto& dp : importedWorkflow) {
3029 workflowHashB += hash_fn(dp.name);
3036 for (
auto& dp : importedWorkflow) {
3037 auto found = std::find_if(physicalWorkflow.begin(), physicalWorkflow.end(),
3039 if (found == physicalWorkflow.end()) {
3040 physicalWorkflow.push_back(dp);
3041 rankIndex.insert(std::make_pair(dp.name, workflowHashB));
3043 auto algorithm = std::move(found->algorithm);
3045 found->algorithm = std::move(algorithm);
3049 for (
auto& dp : physicalWorkflow) {
3051 LOGP(fatal,
"{} was not built, but the driver did not pass its spec.", dp.name);
3059 for (
auto& dp : physicalWorkflow) {
3061 if (std::find_if(dp.labels.begin(), dp.labels.end(), isExpendable) != dp.labels.end()) {
3062 for (
auto&
output : dp.outputs) {
3063 if (
output.lifetime == Lifetime::Timeframe) {
3064 output.lifetime = Lifetime::Sporadic;
3076 if (!(dec.requestedAODs.empty() && dec.requestedDYNs.empty() && dec.requestedIDXs.empty() && dec.requestedTIMs.empty())) {
3079 for (
auto& service : driverServices) {
3080 if (service.injectTopology ==
nullptr) {
3084 service.injectTopology(
node, configContext);
3086 for (
auto& dp : physicalWorkflow) {
3087 if (dp.name.rfind(
"internal-", 0) == 0) {
3088 rankIndex.insert(std::make_pair(dp.name, hash_fn(
"internal")));
3095 return a.name < b.name;
3098 for (
auto& dp : physicalWorkflow) {
3099 std::stable_sort(dp.inputs.begin(), dp.inputs.end(),
3100 [](
InputSpec const&
a,
InputSpec const&
b) { return DataSpecUtils::describe(a) < DataSpecUtils::describe(b); });
3101 std::stable_sort(dp.outputs.begin(), dp.outputs.end(),
3102 [](
OutputSpec const&
a,
OutputSpec const&
b) { return DataSpecUtils::describe(a) < DataSpecUtils::describe(b); });
3107 std::vector<std::pair<int, int>>
edges;
3109 if (physicalWorkflow.size() > 1) {
3113 if (topoInfos.size() != physicalWorkflow.size()) {
3116 throw std::runtime_error(
"Unable to do topological sort of the resulting workflow. Do you have loops?\n" +
debugTopoInfo(physicalWorkflow, topoInfos,
edges));
3120 auto aRank = std::make_tuple(a.layer, -workflow.at(a.index).outputs.size(), workflow.at(a.index).name);
3121 auto bRank = std::make_tuple(b.layer, -workflow.at(b.index).outputs.size(), workflow.at(b.index).name);
3122 return aRank < bRank;
3125 std::vector<int> dataProcessorOrder;
3126 dataProcessorOrder.resize(topoInfos.size());
3127 for (
size_t i = 0;
i < topoInfos.size(); ++
i) {
3128 dataProcessorOrder[topoInfos[
i].index] =
i;
3130 std::vector<int> newLocations;
3131 newLocations.resize(dataProcessorOrder.size());
3132 for (
size_t i = 0;
i < dataProcessorOrder.size(); ++
i) {
3133 newLocations[dataProcessorOrder[
i]] =
i;
3143 bpo::options_description od;
3144 od.add(visibleOptions);
3149 using namespace bpo::command_line_style;
3150 auto style = (allow_short | short_allow_adjacent | short_allow_next | allow_long | long_allow_adjacent | long_allow_next | allow_sticky | allow_dash_for_short);
3151 bpo::variables_map varmap;
3154 bpo::command_line_parser(argc, argv)
3159 }
catch (std::exception
const&
e) {
3160 LOGP(
error,
"error parsing options of {}: {}", argv[0],
e.what());
3176 if (varmap.count(
"help")) {
3177 printHelp(varmap, executorOptions, physicalWorkflow, currentWorkflowOptions);
3183 if (varmap.count(
"severity")) {
3184 auto logLevel = varmap[
"severity"].as<std::string>();
3185 if (logLevel ==
"debug") {
3186 fair::Logger::SetConsoleSeverity(fair::Severity::debug);
3187 }
else if (logLevel ==
"detail") {
3188 fair::Logger::SetConsoleSeverity(fair::Severity::detail);
3189 }
else if (logLevel ==
"info") {
3190 fair::Logger::SetConsoleSeverity(fair::Severity::info);
3191 }
else if (logLevel ==
"warning") {
3192 fair::Logger::SetConsoleSeverity(fair::Severity::warning);
3193 }
else if (logLevel ==
"error") {
3194 fair::Logger::SetConsoleSeverity(fair::Severity::error);
3195 }
else if (logLevel ==
"important") {
3196 fair::Logger::SetConsoleSeverity(fair::Severity::important);
3197 }
else if (logLevel ==
"alarm") {
3198 fair::Logger::SetConsoleSeverity(fair::Severity::alarm);
3199 }
else if (logLevel ==
"critical") {
3200 fair::Logger::SetConsoleSeverity(fair::Severity::critical);
3201 }
else if (logLevel ==
"fatal") {
3202 fair::Logger::SetConsoleSeverity(fair::Severity::fatal);
3204 LOGP(
error,
"Invalid log level '{}'", logLevel);
3209 if (varmap[
"log-timestamp-us"].as<bool>()) {
3210 fair::Logger::DefineVerbosity(fair::Verbosity::user1,
3211 fair::VerbositySpec::Make(fair::VerbositySpec::Info::timestamp_us,
3212 fair::VerbositySpec::Info::severity));
3213 fair::Logger::SetVerbosity(fair::Verbosity::user1);
3218 auto evaluateBatchOption = [&varmap]() ->
bool {
3219 if (varmap.count(
"no-batch") > 0) {
3222 if (varmap.count(
"batch") == 0) {
3224 return isatty(fileno(stdout)) == 0;
3233 DriverInfo driverInfo{
3234 .sendingPolicies = sendingPolicies,
3235 .forwardingPolicies = forwardingPolicies,
3236 .callbacksPolicies = callbacksPolicies};
3237 driverInfo.states.reserve(10);
3238 driverInfo.sigintRequested =
false;
3239 driverInfo.sigchldRequested =
false;
3240 driverInfo.channelPolicies = channelPolicies;
3241 driverInfo.completionPolicies = completionPolicies;
3242 driverInfo.dispatchPolicies = dispatchPolicies;
3243 driverInfo.resourcePolicies = resourcePolicies;
3244 driverInfo.argc = argc;
3245 driverInfo.argv = argv;
3246 driverInfo.noSHMCleanup = varmap[
"no-cleanup"].as<
bool>();
3247 driverInfo.processingPolicies.termination = varmap[
"completion-policy"].as<
TerminationPolicy>();
3248 driverInfo.processingPolicies.earlyForward = varmap[
"early-forward-policy"].as<
EarlyForwardPolicy>();
3249 driverInfo.mode = varmap[
"driver-mode"].as<
DriverMode>();
3251 auto batch = evaluateBatchOption();
3254 .driverHasGUI = (batch ==
false) || getenv(
"DPL_DRIVER_REMOTE_GUI") !=
nullptr,
3257 if (varmap[
"error-policy"].defaulted() && driverConfig.batch ==
false) {
3258 driverInfo.processingPolicies.error = TerminationPolicy::WAIT;
3260 driverInfo.processingPolicies.error = varmap[
"error-policy"].as<
TerminationPolicy>();
3263 driverInfo.startTime = uv_hrtime();
3264 driverInfo.startTimeMsFromEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(
3265 std::chrono::system_clock::now().time_since_epoch())
3267 driverInfo.timeout = varmap[
"timeout"].as<
uint64_t>();
3268 driverInfo.deployHostname = varmap[
"hostname"].as<std::string>();
3269 driverInfo.resources = varmap[
"resources"].as<std::string>();
3270 driverInfo.resourcesMonitoringInterval = varmap[
"resources-monitoring"].as<
unsigned short>();
3271 driverInfo.resourcesMonitoringFilename = varmap[
"resources-monitoring-file"].as<std::string>();
3272 driverInfo.resourcesMonitoringDumpInterval = varmap[
"resources-monitoring-dump-interval"].as<
unsigned short>();
3275 driverInfo.processorInfo = dataProcessorInfos;
3276 driverInfo.configContext = &configContext;
3283 std::string frameworkId;
3286 if (varmap.count(
"id")) {
3290 frameworkId = std::regex_replace(varmap[
"id"].as<std::string>(), std::regex{
"_dds.*"},
"");
3291 driverInfo.uniqueWorkflowId = fmt::format(
"{}", getppid());
3292 driverInfo.defaultDriverClient =
"stdout://";
3294 driverInfo.uniqueWorkflowId = fmt::format(
"{}", getpid());
3295 driverInfo.defaultDriverClient =
"ws://";
3313 LOGP(
error,
"error while setting up workflow in {}: {}",
3314 processName, boost::current_exception_diagnostic_information(
true));
3316#pragma GCC diagnostic push
struct uv_timer_s uv_timer_t
struct uv_async_s uv_async_t
struct uv_handle_s uv_handle_t
struct uv_poll_s uv_poll_t
struct uv_loop_s uv_loop_t
std::vector< OutputRoute > routes
std::unique_ptr< expressions::Node > node
unsigned short int uint16_t
configStandalone Light OpenGL display display_light Apply smoothing to points Enable Z buffer Highlight links Highlight seeds Highlight sector tracks Highlight final tracks Show individual Show related Highlight grid Show only individual collision Color clusters belonging to track objects Set line Enable drawing TPC data Enable drawing TOF data Enable drawing magnetic field Set field line step count Invert colors configStandalone Heavy OpenGL display display_heavy Show tracks with ITS contribution Show tracks with TOF contribution Enable propagation of loopers Show clusters at nominal x of pad row for early transformed data Split CE tracks when they cross the central Mark clusters Mark adjacent clusters Hide rejected tracks Apply filter on tracks to be displayed Separate increase X h configStandalone Camera window renderer OpenGL display display_camera Orient the camera such that the y axis is always upwards Full Screen MultiSample Anti Downsampling Anti Enable Vertical Sync Target frame or if the backend cannot limit to the refresh Use OpenGL indirect draws to reduce number of draw calls Display h configStandalone Vulkan display display_vulkan Have uniform buffers in host accessible device memory h configStandalone Internal display display_internal Number of updates the Qt GUI may send ahead of the last one the display has processed
configStandalone Light OpenGL display display_light Apply smoothing to points Enable Z buffer Highlight links Highlight seeds Highlight sector tracks Highlight final tracks Show individual Show related Highlight grid Show only individual collision Color clusters belonging to track objects Set line Enable drawing TPC data Enable drawing TOF data Enable drawing magnetic field Set field line step count Invert colors configStandalone Heavy OpenGL display display_heavy Show tracks with ITS contribution Show tracks with TOF contribution Enable propagation of loopers Show clusters at nominal x of pad row for early transformed data Split CE tracks when they cross the central Mark clusters Mark adjacent clusters Hide rejected tracks Apply filter on tracks to be displayed Separate increase X h configStandalone Camera window renderer OpenGL display display_camera Orient the camera such that the y axis is always upwards Full Screen MultiSample Anti Downsampling Anti Enable Vertical Sync Target frame or if the backend cannot limit to the refresh Use OpenGL indirect draws to reduce number of draw calls Display h configStandalone Vulkan display display_vulkan Have uniform buffers in host accessible device memory h configStandalone Internal display display_internal Number of updates the Qt GUI may send ahead of the last one the display has before it waits for the display Opacity of the console background Number of console lines the history is shortened to this when it reaches twice the size Time in seconds an info message fades out after setInfoTime h OpenGL display display Font size Do not use Freetype for font Renderer for event Frontend to use for event ROOT macros used as track filter Console script file
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char events
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events Show standalone event Run event generator maximum time bin of continuous for triggered for automatic continuous for automatic continuous triggered uint64_t
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char e
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events d
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder int32_t
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder Print launch bounds used for RTC code as debugging for exit after Allow RTC with slave GPUReconstruction instances with optConstexpr and optSpecialcode Maximum number of RTC cache files per backend in the cache the oldest are Prepend RTC compilation commands by this string Load a parameter object containing the launch bounds from a file h configStandalone Processing proc_param TPC Cluster Z Error Parameterization h configStandalone Processing settings for neural network proc_nn std::string Specify inference device(cpu(default), rocm, cuda)") AddOption(nnInferenceDeviceId
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder Print launch bounds used for RTC code as debugging option
char error[CURL_ERROR_SIZE]
std::vector< o2::MCCompLabel > labels
std::vector< SidecarEdge > edges
o2::phos::PHOSEnergySlot es
#define O2_SIGNPOST_EVENT_EMIT_ERROR(log, id, name, format,...)
o2_log_handle_t * o2_walk_logs(bool(*callback)(char const *name, void *log, void *context), void *context=nullptr)
#define O2_DECLARE_DYNAMIC_LOG(name)
#define O2_SIGNPOST_ID_FROM_POINTER(name, log, pointer)
#define O2_SIGNPOST_EVENT_EMIT_INFO(log, id, name, format,...)
#define O2_SIGNPOST_END(log, id, name, format,...)
void _o2_log_set_stacktrace(_o2_log_t *log, int stacktrace)
#define O2_SIGNPOST_ID_GENERATE(name, log)
#define O2_SIGNPOST_EVENT_EMIT(log, id, name, format,...)
#define O2_SIGNPOST_START(log, id, name, format,...)
o2::monitoring::Monitoring Monitoring
ServiceRegistryRef services() const
static ServiceRegistryRef * globalDeviceRef(ServiceRegistryRef *ref=nullptr)
void registerService(ServiceTypeHash typeHash, void *service, ServiceKind kind, char const *name=nullptr) const
bool match(const std::vector< std::string > &queries, const char *pattern)
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * value
GLuint GLsizei const GLchar * label
GLsizei GLenum const void * indices
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLenum GLenum GLsizei len
GLboolean GLboolean GLboolean GLboolean a
GLenum GLuint GLenum GLsizei const GLchar * buf
uint8_t int statusCode int
Defining ITS Vertex explicitly as messageable.
std::vector< ServiceSpec > ServiceSpecs
RuntimeErrorRef runtime_error(const char *)
EarlyForwardPolicy
When to enable the early forwarding optimization:
std::vector< OverrideServiceSpec > OverrideServiceSpecs
void parse_http_request(char *start, size_t size, HTTPParser *parser)
RuntimeError & error_from_ref(RuntimeErrorRef)
std::vector< DataProcessorSpec > WorkflowSpec
AlgorithmSpec::ProcessCallback adaptStateless(LAMBDA l)
RuntimeErrorRef runtime_error_f(const char *,...)
void dumpDeviceSpec2O2Control(std::string workflowName, std::vector< DeviceSpec > const &specs, std::vector< DeviceExecution > const &executions, CommandInfo const &commandInfo)
Dumps the AliECS compatible workflow and task templates for a DPL workflow.
if(!okForPhiMin(phi0, phi1))
std::string to_string(gsl::span< T, Size > span)
std::vector< std::string > split(const std::string &str, char delimiter=',')
int runStateMachine(DataProcessorSpecs const &workflow, WorkflowInfo const &workflowInfo, DataProcessorInfos const &previousDataProcessorInfos, CommandInfo const &commandInfo, DriverControl &driverControl, DriverInfo &driverInfo, DriverConfig &driverConfig, std::vector< DeviceMetricsInfo > &metricsInfos, std::vector< ConfigParamSpec > const &detectedParams, boost::program_options::variables_map &varmap, std::vector< ServiceSpec > &driverServices, std::string frameworkId)
AlgorithmSpec dryRun(DeviceSpec const &spec)
void getChildData(int infd, DeviceInfo &outinfo)
void overrideLabels(ConfigContext &ctx, WorkflowSpec &workflow)
void apply_permutation(std::vector< T > &v, std::vector< int > &indices)
int doMain(int argc, char **argv, o2::framework::WorkflowSpec const &workflow, std::vector< ChannelConfigurationPolicy > const &channelPolicies, std::vector< CompletionPolicy > const &completionPolicies, std::vector< DispatchPolicy > const &dispatchPolicies, std::vector< ResourcePolicy > const &resourcePolicies, std::vector< CallbacksPolicy > const &callbacksPolicies, std::vector< SendingPolicy > const &sendingPolicies, std::vector< ConfigParamSpec > const ¤tWorkflowOptions, std::vector< ConfigParamSpec > const &detectedParams, o2::framework::ConfigContext &configContext)
void overridePipeline(ConfigContext &ctx, WorkflowSpec &workflow)
void enableSignposts(std::string const &signpostsToEnable)
void spawnDevice(uv_loop_t *loop, DeviceRef ref, std::vector< DeviceSpec > const &specs, DriverInfo &driverInfo, std::vector< DeviceControl > &, std::vector< DeviceExecution > &executions, std::vector< DeviceInfo > &deviceInfos, std::vector< DataProcessingStates > &allStates, ServiceRegistryRef serviceRegistry, boost::program_options::variables_map &varmap, std::vector< DeviceStdioContext > &childFds, unsigned parentCPU, unsigned parentNode)
void killChildren(std::vector< DeviceInfo > &infos, int sig)
void ws_connect_callback(uv_stream_t *server, int status)
A callback for the rest engine.
std::vector< DataProcessingStates > DataProcessingStatesInfos
void createPipes(int *pipes)
void doDPLException(o2::framework::RuntimeErrorRef &ref, char const *)
std::vector< DeviceExecution > DeviceExecutions
void overrideAll(o2::framework::ConfigContext &ctx, std::vector< o2::framework::DataProcessorSpec > &workflow)
std::vector< DeviceMetricsInfo > gDeviceMetricsInfos
void force_exit_callback(uv_timer_s *ctx)
std::string debugTopoInfo(std::vector< DataProcessorSpec > const &specs, std::vector< TopoIndexInfo > const &infos, std::vector< std::pair< int, int > > const &edges)
void overrideCloning(ConfigContext &ctx, WorkflowSpec &workflow)
void doBoostException(boost::exception &e, const char *)
bool processSigChild(DeviceInfos &infos, DeviceSpecs &specs)
void checkNonResiliency(std::vector< DataProcessorSpec > const &specs, std::vector< std::pair< int, int > > const &edges)
std::vector< std::regex > getDumpableMetrics()
void stream_config(uv_work_t *req)
std::vector< DataProcessorSpec > DataProcessorSpecs
void dumpRunSummary(DriverServerContext &context, DriverInfo const &driverInfo, DeviceInfos const &infos, DeviceSpecs const &specs)
void conflicting_options(const boost::program_options::variables_map &vm, const std::string &opt1, const std::string &opt2)
Helper to to detect conflicting options.
void doDefaultWorkflowTerminationHook()
bool checkIfCanExit(std::vector< DeviceInfo > const &infos)
volatile sig_atomic_t sigchld_requested
std::vector< DeviceSpec > DeviceSpecs
std::vector< DataProcessorInfo > DataProcessorInfos
volatile sig_atomic_t forceful_exit
bool areAllChildrenGone(std::vector< DeviceInfo > &infos)
Check the state of the children.
std::vector< DeviceControl > DeviceControls
volatile sig_atomic_t double_sigint
void close_websocket(uv_handle_t *handle)
void handleChildrenStdio(DriverServerContext *serverContext, std::string const &forwardedStdin, std::vector< DeviceStdioContext > &childFds, std::vector< uv_poll_t * > &handles)
char * getIdString(int argc, char **argv)
std::unique_ptr< o2::framework::ServiceRegistry > createRegistry()
void log_callback(uv_poll_t *handle, int status, int events)
void processChildrenOutput(uv_loop_t *loop, DriverInfo &driverInfo, DeviceInfos &infos, DeviceSpecs const &specs, DeviceControls &controls)
volatile sig_atomic_t graceful_exit
void single_step_callback(uv_timer_s *ctx)
Force single stepping of the children.
bpo::options_description gHiddenDeviceOptions("Hidden child options")
void doUnknownException(std::string const &s, char const *)
int doChild(int argc, char **argv, ServiceRegistry &serviceRegistry, DanglingEdgesContext &danglingEdgesContext, RunningWorkflowInfo const &runningWorkflow, RunningDeviceRef ref, DriverConfig const &driverConfig, ProcessingPolicies processingPolicies, std::string const &defaultDriverClient, uv_loop_t *loop)
o2::framework::ConfigContext createConfigContext(std::unique_ptr< ConfigParamRegistry > &workflowOptionsRegistry, o2::framework::ServiceRegistry &configRegistry, std::vector< o2::framework::ConfigParamSpec > &workflowOptions, std::vector< o2::framework::ConfigParamSpec > &extraOptions, int argc, char **argv)
int callMain(int argc, char **argv, int(*mainNoCatch)(int, char **))
void handle_crash(int sig)
void dumpMetricsCallback(uv_timer_t *handle)
void cleanupSHM(std::string const &uniqueWorkflowId)
Helper to invoke shared memory cleanup.
void initialiseDriverControl(bpo::variables_map const &varmap, DriverInfo &driverInfo, DriverControl &control)
Helper function to initialise the controller from the command line options.
void gui_callback(uv_timer_s *ctx)
std::vector< DeviceInfo > DeviceInfos
void printHelp(bpo::variables_map const &varmap, bpo::options_description const &executorOptions, std::vector< DataProcessorSpec > const &physicalWorkflow, std::vector< ConfigParamSpec > const ¤tWorkflowOptions)
void spawnRemoteDevice(uv_loop_t *loop, std::string const &, DeviceSpec const &spec, DeviceControl &, DeviceExecution &, DeviceInfos &deviceInfos, DataProcessingStatesInfos &allStates)
void websocket_callback(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
int mainNoCatch(int argc, char **argv)
DriverServerContext * serverContext
std::string configuration
std::vector< ConfigParamSpec > options
std::vector< std::string > args
static ServiceSpec arrowBackendSpec()
static void demangled_backtrace_symbols(void **backtrace, unsigned int total, int fd)
static std::vector< ServiceSpec > defaultServices()
static std::vector< ComputingResource > parseResources(std::string const &resourceString)
static ComputingResource getLocalhostResource()
static std::vector< ConfigParamSpec > discover(ConfigParamRegistry &, int, char **)
static boost::program_options::options_description prepareOptionDescriptions(ContainerType const &workflow, std::vector< ConfigParamSpec > const ¤tWorkflowOptions, options_description vetos=options_description(), std::string mode="full")
populate boost program options for a complete workflow
static void populateBoostProgramOptions(options_description &options, const std::vector< ConfigParamSpec > &specs, options_description vetos=options_description())
static void dumpDeviceSpec2DDS(std::ostream &out, DriverMode mode, std::string const &workflowSuffix, std::vector< DataProcessorSpec > const &workflow, std::vector< DataProcessorInfo > const &metadata, std::vector< DeviceSpec > const &specs, std::vector< DeviceExecution > const &executions, CommandInfo const &commandInfo)
static void preExitCallbacks(std::vector< ServiceExitHandle >, ServiceRegistryRef)
Invoke callback to be executed on exit, in reverse order.
A label that can be associated to a DataProcessorSpec.
static bool isPlaceholder(DataProcessorSpec const &spec)
static std::string describe(InputSpec const &spec)
Plugin interface for DPL GUIs.
virtual void * initGUI(char const *windowTitle, ServiceRegistry ®istry)=0
virtual std::function< void(void)> getGUIDebugger(std::vector< o2::framework::DeviceInfo > const &infos, std::vector< o2::framework::DeviceSpec > const &devices, std::vector< o2::framework::DataProcessingStates > const &allStates, std::vector< o2::framework::DataProcessorInfo > const &metadata, std::vector< o2::framework::DeviceMetricsInfo > const &metricsInfos, o2::framework::DriverInfo const &driverInfo, std::vector< o2::framework::DeviceControl > &controls, o2::framework::DriverControl &driverControl)=0
static DeploymentMode deploymentMode()
static unsigned int pipelineLength(unsigned int minLength)
get max number of timeslices in the queue
static std::unique_ptr< ConfigParamStore > getConfiguration(ServiceRegistryRef registry, const char *name, std::vector< ConfigParamSpec > const &options)
ProcessingPolicies & processingPolicies
char logFilter[MAX_USER_FILTER_SIZE]
Lines in the log should match this to be displayed.
bool quiet
wether we should be capturing device output.
std::string unprinted
An unterminated string which is not ready to be printed yet.
static void validate(WorkflowSpec const &workflow)
static boost::program_options::options_description getForwardedDeviceOptions()
define the options which are forwarded to every child
static std::string reworkTimeslicePlaceholder(std::string const &str, DeviceSpec const &spec)
static void prepareArguments(bool defaultQuiet, bool defaultStopped, bool intereactive, unsigned short driverPort, DriverConfig const &driverConfig, std::vector< DataProcessorInfo > const &processorInfos, std::vector< DeviceSpec > const &deviceSpecs, std::vector< DeviceExecution > &deviceExecutions, std::vector< DeviceControl > &deviceControls, std::vector< ConfigParamSpec > const &detectedOptions, std::string const &uniqueWorkflowId)
static void reworkShmSegmentSize(std::vector< DataProcessorInfo > &infos)
static void reworkHomogeneousOption(std::vector< DataProcessorInfo > &infos, char const *name, char const *defaultValue)
static void dataProcessorSpecs2DeviceSpecs(const WorkflowSpec &workflow, std::vector< ChannelConfigurationPolicy > const &channelPolicies, std::vector< CompletionPolicy > const &completionPolicies, std::vector< DispatchPolicy > const &dispatchPolicies, std::vector< ResourcePolicy > const &resourcePolicies, std::vector< CallbacksPolicy > const &callbacksPolicies, std::vector< SendingPolicy > const &sendingPolicy, std::vector< ForwardingPolicy > const &forwardingPolicies, std::vector< DeviceSpec > &devices, ResourceManager &resourceManager, std::string const &uniqueWorkflowId, ConfigContext const &configContext, bool optimizeTopology=false, unsigned short resourcesMonitoringInterval=0, std::string const &channelPrefix="", OverrideServiceSpecs const &overrideServices={})
std::vector< OutputRoute > outputs
std::string id
The id of the device, including time-pipelining and suffix.
static int parseTracingFlags(std::string const &events)
std::vector< DeviceControl > & controls
bool batch
Whether the driver was started in batch mode or not.
std::vector< DriverState > forcedTransitions
std::vector< Callback > callbacks
DriverControlState state
Current state of the state machine player.
std::vector< DeviceSpec > * specs
std::vector< ServiceSummaryHandling > * summaryCallbacks
std::vector< DeviceMetricsInfo > * metrics
std::vector< DeviceInfo > * infos
ServiceRegistryRef registry
static std::vector< ForwardingPolicy > createDefaultPolicies()
static void dumpDeviceSpec2Graphviz(std::ostream &, const Devices &specs)
Helper to dump a set of devices as a graphviz file.
static void dumpDataProcessorSpec2Graphviz(std::ostream &, const WorkflowSpec &specs, std::vector< std::pair< int, int > > const &edges={})
Helper to dump a workflow as a graphviz file.
LogLevel
Possible log levels for device log entries.
static LogLevel parseTokenLevel(std::string_view const s)
static void dumpDeviceSpec2Mermaid(std::ostream &, const Devices &specs)
Helper to dump a set of devices as a mermaid file.
Temporary struct to hold a metric after it has been parsed.
enum TerminationPolicy termination
enum TerminationPolicy error
static bool dumpMetricsToJSON(std::vector< DeviceMetricsInfo > const &metrics, DeviceMetricsInfo const &driverMetrics, std::vector< DeviceSpec > const &specs, std::vector< std::regex > const &metricsToDump, std::ostream &out) noexcept
static bool isResourcesMonitoringEnabled(unsigned short interval) noexcept
Information about the running workflow.
std::vector< DeviceSpec > devices
std::string uniqueWorkflowId
void declareService(ServiceSpec const &spec, DeviceState &state, fair::mq::ProgOptions &options, ServiceRegistry::Salt salt=ServiceRegistry::globalDeviceSalt())
void registerService(ServiceTypeHash typeHash, void *service, ServiceKind kind, Salt salt, char const *name=nullptr, ServiceRegistry::SpecIndex specIndex=SpecIndex{-1}) const
static Salt globalDeviceSalt()
static OverrideServiceSpecs parseOverrides(char const *overrideString)
static ServiceSpecs filterDisabled(ServiceSpecs originals, OverrideServiceSpecs const &overrides)
static std::function< int64_t(int64_t base, int64_t offset)> defaultCPUTimeConfigurator(uv_loop_t *loop)
static std::function< void(int64_t &base, int64_t &offset)> defaultRealtimeBaseConfigurator(uint64_t offset, uv_loop_t *loop)
Helper struct to keep track of the results of the topological sort.
static auto buildEdges(WorkflowSpec &physicalWorkflow) -> std::vector< std::pair< int, int > >
static void adjustTopology(WorkflowSpec &workflow, ConfigContext const &ctx)
static void injectServiceDevices(WorkflowSpec &workflow, ConfigContext &ctx)
static WorkflowParsingState verifyWorkflow(const WorkflowSpec &workflow)
static std::vector< TopoIndexInfo > topologicalSort(size_t nodeCount, int const *edgeIn, int const *edgeOut, size_t byteStride, size_t edgesCount)
static void dump(std::ostream &o, std::vector< DataProcessorSpec > const &workflow, std::vector< DataProcessorInfo > const &metadata, CommandInfo const &commandInfo)
static bool import(std::istream &s, std::vector< DataProcessorSpec > &workflow, std::vector< DataProcessorInfo > &metadata, CommandInfo &command)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< ChannelData > channels
uint64_t const void const *restrict const msg