53#include "../src/DataProcessingStatus.h"
61#include <Configuration/ConfigurationInterface.h>
62#include <Configuration/ConfigurationFactory.h>
63#include <Monitoring/MonitoringFactory.h>
64#include <Monitoring/ProcessMonitor.h>
67#include <fairmq/Device.h>
68#include <fairmq/shmem/Monitor.h>
69#include <fairmq/shmem/Common.h>
70#include <fairmq/ProgOptions.h>
76using o2::configuration::ConfigurationFactory;
77using o2::configuration::ConfigurationInterface;
78using o2::monitoring::Monitoring;
79using o2::monitoring::MonitoringFactory;
80using Metric = o2::monitoring::Metric;
81using Key = o2::monitoring::tags::Key;
82using Value = o2::monitoring::tags::Value;
92#define MONITORING_QUEUE_SIZE 100
98 void* service =
nullptr;
99 bool isWebsocket = strncmp(options.GetPropertyAsString(
"driver-client-backend").c_str(),
"ws://", 4) == 0;
100 bool isDefault = options.GetPropertyAsString(
"monitoring-backend") ==
"default";
101 bool useDPL = (isWebsocket && isDefault) || options.GetPropertyAsString(
"monitoring-backend") ==
"dpl://";
102 o2::monitoring::Monitoring* monitoring;
105 auto dplBackend = std::make_unique<DPLMonitoringBackend>(registry);
107 monitoring->addBackend(std::move(dplBackend));
109 auto backend = isDefault ?
"infologger://" : options.GetPropertyAsString(
"monitoring-backend");
110 monitoring = MonitoringFactory::Get(backend).release();
112 service = monitoring;
116 monitoring->addGlobalTag(
"dataprocessor_name", registry.
get<
DeviceSpec const>().
name);
117 monitoring->addGlobalTag(
"dpl_instance", options.GetPropertyAsString(
"shm-segment-id"));
118 return ServiceHandle{TypeIdHelpers::uniqueId<Monitoring>(), service};
122 auto* monitoring = (o2::monitoring::Monitoring*)service;
127 auto interval = services.
get<
DeviceSpec const>().resourceMonitoringInterval;
129 using o2::monitoring::PmMeasurement;
130 monitoring->enableProcessMonitoring(interval, {PmMeasurement::Cpu, PmMeasurement::Mem, PmMeasurement::Smaps});
133 auto extRunNumber = services.
get<
RawDeviceService>().device()->fConfig->GetProperty<std::string>(
"runNumber",
"unspecified");
134 if (extRunNumber ==
"unspecified") {
138 monitoring->setRunNumber(std::stoul(extRunNumber));
145 auto* monitoring =
reinterpret_cast<Monitoring*
>(service);
146 monitoring->finalizeProcessMonitoring(); },
148 auto* monitoring =
reinterpret_cast<Monitoring*
>(service);
149 monitoring->flushBuffer();
150 delete monitoring; },
158 .
name =
"async-queue",
159 .init = simpleServiceInit<AsyncQueue, AsyncQueue>(),
174 .
name =
"timing-info",
175 .uniqueId = simpleServiceId<TimingInfo>(),
176 .init = simpleServiceInit<TimingInfo, TimingInfo, ServiceKind::Stream>(),
184 .
name =
"stream-context",
185 .uniqueId = simpleServiceId<StreamContext>(),
186 .init = simpleServiceInit<StreamContext, StreamContext, ServiceKind::Stream>(),
198 std::fill(
stream->routeDPLCreated.begin(),
stream->routeDPLCreated.end(),
false);
199 std::fill(
stream->routeCreated.begin(),
stream->routeCreated.end(),
false); },
205 auto dispatchState = messageContext.dispatchState();
215 bool userDidCreate =
false;
216 for (
size_t ri = 0; ri <
routes.size(); ++ri) {
217 if (
stream->routeCreated[ri] ==
true &&
stream->routeDPLCreated[ri] ==
false) {
218 userDidCreate =
true;
222 O2_SIGNPOST_EVENT_EMIT(stream_context, cid,
"postProcessingCallbacks",
"userDidCreate == %d && didDispatch == %d",
226 O2_SIGNPOST_EVENT_EMIT(stream_context, cid,
"postProcessingCallbacks",
"Data created out of band userDidCreate == %d && messageContext.didDispatch == %d",
236 for (
size_t ri = 0; ri <
routes.size(); ++ri) {
238 auto &matcher = route.matcher;
239 if (
stream->routeDPLCreated[ri] ==
true) {
240 O2_SIGNPOST_EVENT_EMIT(stream_context, cid,
"postProcessingCallbacks",
"Data created by DPL. ri = %" PRIu64
", %{public}s",
244 if (
stream->routeCreated[ri] ==
true) {
246 }
if ((timeslice % route.maxTimeslices) != route.timeslice) {
247 O2_SIGNPOST_EVENT_EMIT(stream_context, cid,
"postProcessingCallbacks",
"Route ri = %" PRIu64
", skipped because of pipelining.",
251 if (matcher.lifetime == Lifetime::Timeframe) {
253 "Expected Lifetime::Timeframe data %{public}s was not created for timeslice %" PRIu64
" and might result in dropped timeframes",
255 LOGP(error,
"Expected Lifetime::Timeframe data {} was not created for timeslice {} and might result in dropped timeframes",
DataSpecUtils::describe(matcher), timeslice);
272 std::fill(
stream->routeCreated.begin(),
stream->routeCreated.end(),
false);
273 std::fill(
stream->routeDPLCreated.begin(),
stream->routeDPLCreated.end(),
false); },
280 .
name =
"datataking-contex",
281 .uniqueId = simpleServiceId<DataTakingContext>(),
282 .init = simpleServiceInit<DataTakingContext, DataTakingContext, ServiceKind::Stream>(),
286 for (
auto const&
ref : processingContext.
inputs()) {
288 const auto* dh = o2::header::get<o2::header::DataHeader*>(
ref.header);
292 context.runNumber = fmt::format(
"{}", dh->runNumber);
301 auto extRunNumber = services.
get<
RawDeviceService>().device()->fConfig->GetProperty<std::string>(
"runNumber",
"unspecified");
302 if (extRunNumber !=
"unspecified" || context.runNumber ==
"0") {
303 context.runNumber = extRunNumber;
305 auto extLHCPeriod = services.
get<
RawDeviceService>().device()->fConfig->GetProperty<std::string>(
"lhc_period",
"unspecified");
306 if (extLHCPeriod !=
"unspecified") {
307 context.lhcPeriod = extLHCPeriod;
309 static const char* months[12] = {
"JAN",
"FEB",
"MAR",
"APR",
"MAY",
"JUN",
"JUL",
"AUG",
"SEP",
"OCT",
"NOV",
"DEC"};
310 time_t now =
time(
nullptr);
311 auto ltm = gmtime(&now);
312 context.lhcPeriod = months[ltm->tm_mon];
313 LOG(info) <<
"LHCPeriod is not available, using current month " << context.lhcPeriod;
316 auto extRunType = services.
get<
RawDeviceService>().device()->fConfig->GetProperty<std::string>(
"run_type",
"unspecified");
317 if (extRunType !=
"unspecified") {
318 context.runType = extRunType;
320 auto extEnvId = services.
get<
RawDeviceService>().device()->fConfig->GetProperty<std::string>(
"environment_id",
"unspecified");
321 if (extEnvId !=
"unspecified") {
322 context.envId = extEnvId;
324 auto extDetectors = services.
get<
RawDeviceService>().device()->fConfig->GetProperty<std::string>(
"detectors",
"unspecified");
325 if (extDetectors !=
"unspecified") {
326 context.detectors = extDetectors;
328 auto forcedRaw = services.
get<
RawDeviceService>().device()->fConfig->GetProperty<std::string>(
"force_run_as_raw",
"false");
329 context.forcedRaw = forcedRaw ==
"true"; },
339 .
name =
"configuration",
341 auto backend = options.GetPropertyAsString(
"configuration");
342 if (backend ==
"command-line") {
345 return ServiceHandle{TypeIdHelpers::uniqueId<ConfigurationInterface>(),
346 ConfigurationFactory::getConfiguration(backend).release()};
350 if (dc.options.count(
"configuration") == 0) {
354 auto backend = dc.options[
"configuration"].as<std::string>();
356 ConfigurationFactory::getConfiguration(backend).release()}); },
363 .
name =
"driverClient",
365 auto backend = options.GetPropertyAsString(
"driver-client-backend");
366 if (backend ==
"stdout://") {
367 return ServiceHandle{TypeIdHelpers::uniqueId<DriverClient>(),
371 return ServiceHandle{TypeIdHelpers::uniqueId<DriverClient>(),
383 return ServiceHandle{TypeIdHelpers::uniqueId<ControlService>(),
393 .
name =
"localrootfile",
394 .init = simpleServiceInit<LocalRootFileService, LocalRootFileService>(),
405 return ServiceHandle{TypeIdHelpers::uniqueId<ParallelContext>(),
415 .
name =
"timesliceindex",
418 return ServiceHandle{TypeIdHelpers::uniqueId<TimesliceIndex>(),
429 .init = simpleServiceInit<CallbackService, CallbackService>(),
437 .
name =
"datarelayer",
455 .
name =
"datasender",
468 if (ctx.services().get<
DeviceState>().quitRequested ==
false) {
504 .
name =
"ccdb-support",
508 for (
auto&
output : spec.outputs) {
510 LOGP(
debug,
"Optional inputs support enabled");
522 LOGP(
debug,
"We are w/o outputs, do not automatically add DISTSUBTIMEFRAME to outgoing messages");
538 if (concrete.subSpec == 0) {
542 stfDist.
id = timingInfo.timeslice;
543 stfDist.firstOrbit = timingInfo.firstTForbit;
544 stfDist.runNumber = timingInfo.runNumber;
548 O2_SIGNPOST_EVENT_EMIT(stream_context, sid,
"finaliseOutputs",
"Route %" PRIu64
" (%{public}s) was created by DPL.", (uint64_t)oi,
550 streamContext.routeDPLCreated[oi] =
true;
569 if (decongestion.lastTimeslice >= oldestPossibleOutput.timeslice.value) {
570 O2_SIGNPOST_EVENT_EMIT(async_queue, cid,
"oldest_possible_timeslice",
"Not sending already sent value: %" PRIu64
"> %" PRIu64,
571 decongestion.lastTimeslice, (uint64_t)oldestPossibleOutput.timeslice.value);
574 O2_SIGNPOST_EVENT_EMIT(async_queue, cid,
"oldest_possible_timeslice",
"Running oldest possible timeslice %" PRIu64
" propagation.",
575 (uint64_t)oldestPossibleOutput.timeslice.value);
578 for (
int fi = 0; fi < proxy.getNumForwardChannels(); fi++) {
579 auto& info = proxy.getForwardChannelInfo(
ChannelIndex{fi});
582 if (info.channelType != ChannelAccountingType::DPL) {
583 O2_SIGNPOST_EVENT_EMIT(async_queue, cid,
"oldest_possible_timeslice",
"Skipping channel %{public}s", info.name.c_str());
588 "Forwarding to channel %{public}s oldest possible timeslice %" PRIu64
", priority %d",
589 info.name.c_str(), (uint64_t)oldestPossibleOutput.timeslice.value, 20);
592 decongestion.lastTimeslice = oldestPossibleOutput.timeslice.value;
603 int64_t oldNextTimeslice = decongestion.nextTimeslice;
604 decongestion.nextTimeslice = std::max(decongestion.nextTimeslice, (int64_t)oldestPossibleOutput.timeslice.value);
605 if (oldNextTimeslice != decongestion.nextTimeslice) {
607 O2_SIGNPOST_EVENT_EMIT_WARN(async_queue, cid,
"oldest_possible_timeslice",
"Stop transition requested. Some Lifetime::Timeframe data got dropped starting at %" PRIi64, oldNextTimeslice);
609 O2_SIGNPOST_EVENT_EMIT_CRITICAL(async_queue, cid,
"oldest_possible_timeslice",
"Some Lifetime::Timeframe data got dropped starting at %" PRIi64, oldNextTimeslice);
611 timesliceIndex.rescan();
629 timesliceIndex.rescan();
630 timesliceIndex.updateOldestPossibleOutput(decongestion.nextEnumerationTimesliceRewinded);
633 if (oldestPossibleOutput.timeslice.value <= decongestion.lastTimeslice) {
635 "consumeWhenPastOldestPossibleTimeframe: not forwarding already sent value %" PRIu64,
636 (uint64_t)oldestPossibleOutput.timeslice.value);
640 "consumeWhenPastOldestPossibleTimeframe: forwarding oldest possible timeslice %" PRIu64,
641 (uint64_t)oldestPossibleOutput.timeslice.value);
644 for (
int fi = 0; fi < proxy.getNumForwardChannels(); fi++) {
645 auto& info = proxy.getForwardChannelInfo(
ChannelIndex{fi});
647 if (info.channelType != ChannelAccountingType::DPL) {
652 decongestion.lastTimeslice = oldestPossibleOutput.timeslice.value;
663 .
name =
"decongestion",
666 for (
auto& input : services.
get<
DeviceSpec const>().inputs) {
667 if (input.matcher.lifetime == Lifetime::Timeframe || input.matcher.lifetime == Lifetime::QA || input.matcher.lifetime == Lifetime::Sporadic || input.matcher.lifetime == Lifetime::Optional) {
668 LOGP(detail,
"Found a real data input, we cannot update the oldest possible timeslice when sending messages");
669 decongestion->isFirstInTopology =
false;
675 decongestion->suppressDomainInfo =
true;
680 decongestion->oldestPossibleTimesliceTask =
AsyncQueueHelpers::create(queue, {.name =
"oldest-possible-timeslice", .score = 100});
689 O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid,
"postForwardingCallbacks",
"We are the first one in the topology, we need to update the oldest possible timeslice");
692 timesliceIndex.updateOldestPossibleOutput(decongestion->nextEnumerationTimesliceRewinded);
695 if (decongestion->nextEnumerationTimesliceRewinded && decongestion->nextEnumerationTimeslice < oldestPossibleOutput.timeslice.value) {
696 LOGP(detail,
"Not sending oldestPossible if nextEnumerationTimeslice was rewinded");
700 if (decongestion->lastTimeslice && oldestPossibleOutput.timeslice.value == decongestion->lastTimeslice) {
702 "Not sending already sent value for oldest possible timeslice: %" PRIu64,
703 (uint64_t)oldestPossibleOutput.timeslice.value);
706 if (oldestPossibleOutput.timeslice.value < decongestion->lastTimeslice) {
707 LOGP(error,
"We are trying to send an oldest possible timeslice {} that is older than the last one we already sent {}",
708 oldestPossibleOutput.timeslice.value, decongestion->lastTimeslice);
712 O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid,
"oldest_possible_timeslice",
"Broadcasting oldest posssible output %" PRIu64
" due to %{public}s (%" PRIu64
")",
713 (uint64_t)oldestPossibleOutput.timeslice.value,
714 oldestPossibleOutput.slot.index == -1 ?
"channel" :
"slot",
715 (uint64_t)(oldestPossibleOutput.slot.index == -1 ? oldestPossibleOutput.channel.value : oldestPossibleOutput.slot.index));
716 O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid,
"oldest_possible_timeslice",
"Ordered active %d", decongestion->orderedCompletionPolicyActive);
717 if (decongestion->orderedCompletionPolicyActive) {
718 auto oldNextTimeslice = decongestion->nextTimeslice;
719 decongestion->nextTimeslice = std::max(decongestion->nextTimeslice, (int64_t)oldestPossibleOutput.timeslice.value);
720 O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid,
"oldest_possible_timeslice",
"Next timeslice %" PRIi64, decongestion->nextTimeslice);
721 if (oldNextTimeslice != decongestion->nextTimeslice) {
724 O2_SIGNPOST_EVENT_EMIT_WARN(data_processor_context, cid,
"oldest_possible_timeslice",
"Stop transition requested. Some Lifetime::Timeframe data got dropped starting at %" PRIi64, oldNextTimeslice);
726 O2_SIGNPOST_EVENT_EMIT_CRITICAL(data_processor_context, cid,
"oldest_possible_timeslice",
"Some Lifetime::Timeframe data got dropped starting at %" PRIi64, oldNextTimeslice);
733 for (
int fi = 0; fi < proxy.getNumForwardChannels(); fi++) {
734 auto& info = proxy.getForwardChannelInfo(
ChannelIndex{fi});
738 O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid,
"oldest_possible_timeslice",
"Skipping channel %{public}s", info.name.c_str());
743 "Forwarding to channel %{public}s oldest possible timeslice %" PRIu64
", priority %d",
744 info.name.c_str(), (uint64_t)oldestPossibleOutput.timeslice.value, 20);
747 decongestion->lastTimeslice = oldestPossibleOutput.timeslice.value; },
751 decongestion->nextEnumerationTimeslice = 0;
752 decongestion->nextEnumerationTimesliceRewinded =
false;
753 decongestion->lastTimeslice = 0;
754 decongestion->nextTimeslice = 0;
755 decongestion->oldestPossibleTimesliceTask = {0};
757 for (
auto &channel :
state.inputChannelInfos) {
758 channel.oldestForChannel = {0};
765 O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid,
"oldest_possible_timeslice",
"Received oldest possible timeframe %" PRIu64
" from channel %d",
766 (uint64_t)oldestPossibleTimeslice, channel.value);
767 relayer.setOldestPossibleInput({oldestPossibleTimeslice}, channel);
768 timesliceIndex.updateOldestPossibleOutput(decongestion.nextEnumerationTimesliceRewinded);
769 auto oldestPossibleOutput = relayer.getOldestPossibleOutput();
777 if (decongestion.consumeWhenPastOldestPossibleTimeframeActive) {
781 .id = decongestion.oldestPossibleTimesliceTask,
784 .user<
DecongestionContext>({.ref = services, .oldestPossibleOutput = oldestPossibleOutput}));
787 if (oldestPossibleOutput.timeslice.value == decongestion.lastTimeslice) {
788 O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid,
"oldest_possible_timeslice",
"Synchronous: Not sending already sent value: %" PRIu64, (uint64_t)oldestPossibleOutput.timeslice.value);
791 if (oldestPossibleOutput.timeslice.value < decongestion.lastTimeslice) {
792 LOGP(error,
"We are trying to send an oldest possible timeslice {} that is older than the last one we sent {}",
793 oldestPossibleOutput.timeslice.value, decongestion.lastTimeslice);
800 O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid,
"oldest_possible_timeslice",
"Queueing oldest possible timeslice %" PRIu64
" propagation for execution.",
801 (uint64_t)oldestPossibleOutput.timeslice.value);
804 .id = decongestion.oldestPossibleTimesliceTask,
808 if (decongestion.orderedCompletionPolicyActive) {
812 .user<
DecongestionContext>({.ref = services, .oldestPossibleOutput = oldestPossibleOutput}));
824 .
name =
"threadpool",
829 return ServiceHandle{TypeIdHelpers::uniqueId<ThreadPool>(), pool};
831 .configure = [](
InitContext&,
void* service) ->
void* {
832 auto* t =
reinterpret_cast<ThreadPool*
>(service);
840 setenv(
"UV_THREADPOOL_SIZE", numWorkersS.c_str(), 0);
854 auto& spec = registry.get<
DeviceSpec const>();
857 if (stats.hasAvailSHMMetric) {
859 long freeMemory = -1;
861 freeMemory = fair::mq::shmem::Monitor::GetFreeMemory(ShmId{makeShmIdStr(device->fConfig->GetProperty<uint64_t>(
"shmid"))}, runningWorkflow.shmSegmentId);
864 if (freeMemory == -1) {
866 freeMemory = fair::mq::shmem::Monitor::GetFreeMemory(SessionId{device->fConfig->GetProperty<std::string>(
"session")}, runningWorkflow.shmSegmentId);
873 auto device = registry.get<RawDeviceService>().device();
878 for (
auto& channel : device->GetChannels()) {
879 totalBytesIn += channel.second[0].GetBytesRx();
880 totalBytesOut += channel.second[0].GetBytesTx();
890auto flushStates(ServiceRegistryRef registry, DataProcessingStates&
states) ->
void
892 if (!registry.get<DriverConfig
const>().driverHasGUI) {
895 states.flushChangedStates([&
states, registry](std::string
const& spec,
int64_t timestamp, std::string_view
value)
mutable ->
void {
896 auto& client = registry.get<ControlService>();
897 client.push(spec,
value, timestamp);
904auto flushMetrics(ServiceRegistryRef registry, DataProcessingStats& stats) ->
void
910 if (registry.isMainThread() ==
false) {
911 LOGP(fatal,
"Flushing metrics should only happen on the main thread.");
913 auto& monitoring = registry.get<
Monitoring>();
914 auto& relayer = registry.get<DataRelayer>();
917 stats.flushChangedMetrics([&monitoring, sid](DataProcessingStats::MetricSpec
const& spec,
int64_t timestamp,
int64_t value)
mutable ->
void {
919 auto tp = std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>(std::chrono::milliseconds(timestamp));
920 auto metric = o2::monitoring::Metric{spec.name, Metric::DefaultVerbosity, tp};
923 O2_SIGNPOST_EVENT_EMIT(monitoring_service, sid,
"flushChangedMetrics",
"Value for %{public}s is negative, setting to 0",
927 metric.addValue((uint64_t)
value,
"value");
930 O2_SIGNPOST_EVENT_EMIT(monitoring_service, sid,
"flushChangedMetrics",
"Value for %{public}s is too large, setting to INT_MAX",
935 O2_SIGNPOST_EVENT_EMIT(monitoring_service, sid,
"flushChangedMetrics",
"Value for %{public}s is too small, setting to INT_MIN",
939 metric.addValue((
int)
value,
"value");
942 metric.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL);
944 O2_SIGNPOST_EVENT_EMIT(monitoring_service, sid,
"flushChangedMetrics",
"Flushing metric %{public}s", spec.name.c_str());
945 monitoring.send(std::move(metric));
947 relayer.sendContextState();
948 monitoring.flushBuffer();
949 O2_SIGNPOST_END(monitoring_service, sid,
"flush",
"done flushing metrics");
956 .
name =
"data-processing-stats",
959 clock_gettime(CLOCK_REALTIME, &now);
960 uv_update_time(
state.loop);
961 uint64_t
offset = now.tv_sec * 1000 - uv_now(
state.loop);
963 .
minOnlinePublishInterval = std::stoi(options.GetProperty<std::string>(
"dpl-stats-min-online-publishing-interval").c_str()) * 1000};
970 int quickUpdateInterval = 5000;
971 uint64_t quickRefreshInterval = 7000;
972 uint64_t onlineRefreshLatency = 60000;
978 bool enableDebugMetrics =
false;
980 bool enableDebugMetrics =
true;
982 bool arrowAndResourceLimitingMetrics =
false;
984 arrowAndResourceLimitingMetrics =
true;
987 int64_t consumedTimeframesPublishInterval = 0;
989 consumedTimeframesPublishInterval = 5000;
994 bool enableCPUUsageFraction =
true;
996 if (std::find_if(spec.labels.begin(), spec.labels.end(), isProxy) != spec.labels.end()) {
998 O2_SIGNPOST_EVENT_EMIT(policies, mid,
"metrics",
"Disabling cpu_usage_fraction metric for proxy %{public}s", spec.name.c_str());
999 enableCPUUsageFraction =
false;
1002 std::vector<DataProcessingStats::MetricSpec>
metrics = {
1003 MetricSpec{.name =
"errors",
1005 .
kind = Kind::UInt64,
1006 .scope = Scope::Online,
1007 .minPublishInterval = quickUpdateInterval,
1008 .maxRefreshLatency = quickRefreshInterval},
1009 MetricSpec{.name =
"exceptions",
1011 .
kind = Kind::UInt64,
1012 .scope = Scope::Online,
1013 .minPublishInterval = quickUpdateInterval},
1014 MetricSpec{.name =
"inputs/relayed/pending",
1016 .
kind = Kind::UInt64,
1017 .minPublishInterval = quickUpdateInterval},
1018 MetricSpec{.name =
"inputs/relayed/incomplete",
1020 .
kind = Kind::UInt64,
1021 .minPublishInterval = quickUpdateInterval},
1022 MetricSpec{.name =
"inputs/relayed/total",
1024 .
kind = Kind::UInt64,
1025 .minPublishInterval = quickUpdateInterval},
1026 MetricSpec{.name =
"elapsed_time_ms",
1028 .
kind = Kind::UInt64,
1029 .minPublishInterval = quickUpdateInterval},
1030 MetricSpec{.name =
"total_wall_time_ms",
1032 .
kind = Kind::UInt64,
1033 .minPublishInterval = quickUpdateInterval},
1034 MetricSpec{.name =
"last_processed_input_size_byte",
1036 .
kind = Kind::UInt64,
1037 .minPublishInterval = quickUpdateInterval},
1038 MetricSpec{.name =
"total_processed_input_size_byte",
1040 .
kind = Kind::UInt64,
1041 .scope = Scope::Online,
1042 .minPublishInterval = quickUpdateInterval},
1043 MetricSpec{.name =
"total_sigusr1",
1045 .
kind = Kind::UInt64,
1046 .minPublishInterval = quickUpdateInterval},
1047 MetricSpec{.name =
"consumed-timeframes",
1049 .
kind = Kind::UInt64,
1050 .minPublishInterval = consumedTimeframesPublishInterval,
1051 .maxRefreshLatency = quickRefreshInterval,
1052 .sendInitialValue =
true},
1053 MetricSpec{.name =
"min_input_latency_ms",
1055 .
kind = Kind::UInt64,
1056 .scope = Scope::Online,
1057 .minPublishInterval = quickUpdateInterval},
1058 MetricSpec{.name =
"max_input_latency_ms",
1060 .
kind = Kind::UInt64,
1061 .minPublishInterval = quickUpdateInterval},
1062 MetricSpec{.name =
"total_rate_in_mb_s",
1065 .scope = Scope::Online,
1066 .minPublishInterval = quickUpdateInterval,
1067 .maxRefreshLatency = onlineRefreshLatency,
1068 .sendInitialValue =
true},
1069 MetricSpec{.name =
"total_rate_out_mb_s",
1072 .scope = Scope::Online,
1073 .minPublishInterval = quickUpdateInterval,
1074 .maxRefreshLatency = onlineRefreshLatency,
1075 .sendInitialValue =
true},
1076 MetricSpec{.name =
"processing_rate_hz",
1079 .scope = Scope::Online,
1080 .minPublishInterval = quickUpdateInterval,
1081 .maxRefreshLatency = onlineRefreshLatency,
1082 .sendInitialValue =
true},
1083 MetricSpec{.name =
"cpu_usage_fraction",
1084 .enabled = enableCPUUsageFraction,
1087 .scope = Scope::Online,
1088 .minPublishInterval = quickUpdateInterval,
1089 .maxRefreshLatency = onlineRefreshLatency,
1090 .sendInitialValue =
true},
1091 MetricSpec{.name =
"performed_computations",
1093 .
kind = Kind::UInt64,
1094 .scope = Scope::Online,
1095 .minPublishInterval = quickUpdateInterval,
1096 .maxRefreshLatency = onlineRefreshLatency,
1097 .sendInitialValue =
true},
1098 MetricSpec{.name =
"total_bytes_in",
1100 .
kind = Kind::UInt64,
1101 .scope = Scope::Online,
1102 .minPublishInterval = quickUpdateInterval,
1103 .maxRefreshLatency = onlineRefreshLatency,
1104 .sendInitialValue =
true},
1105 MetricSpec{.name =
"total_bytes_out",
1107 .
kind = Kind::UInt64,
1108 .scope = Scope::Online,
1109 .minPublishInterval = quickUpdateInterval,
1110 .maxRefreshLatency = onlineRefreshLatency,
1111 .sendInitialValue =
true},
1112 MetricSpec{.name = fmt::format(
"available_managed_shm_{}", runningWorkflow.shmSegmentId),
1114 .kind = Kind::UInt64,
1115 .scope = Scope::Online,
1116 .minPublishInterval = 500,
1117 .maxRefreshLatency = onlineRefreshLatency,
1118 .sendInitialValue =
true},
1123 MetricSpec{.name =
"arrow-bytes-destroyed",
1124 .enabled = arrowAndResourceLimitingMetrics,
1126 .
kind = Kind::UInt64,
1127 .scope = Scope::DPL,
1128 .minPublishInterval = 0,
1129 .maxRefreshLatency = 10000,
1130 .sendInitialValue =
true},
1131 MetricSpec{.name =
"arrow-messages-destroyed",
1132 .enabled = arrowAndResourceLimitingMetrics,
1134 .
kind = Kind::UInt64,
1135 .scope = Scope::DPL,
1136 .minPublishInterval = 0,
1137 .maxRefreshLatency = 10000,
1138 .sendInitialValue =
true},
1139 MetricSpec{.name =
"arrow-bytes-created",
1140 .enabled = arrowAndResourceLimitingMetrics,
1142 .
kind = Kind::UInt64,
1143 .scope = Scope::DPL,
1144 .minPublishInterval = 0,
1145 .maxRefreshLatency = 10000,
1146 .sendInitialValue =
true},
1147 MetricSpec{.name =
"arrow-messages-created",
1148 .enabled = arrowAndResourceLimitingMetrics,
1150 .
kind = Kind::UInt64,
1151 .scope = Scope::DPL,
1152 .minPublishInterval = 0,
1153 .maxRefreshLatency = 10000,
1154 .sendInitialValue =
true},
1155 MetricSpec{.name =
"arrow-bytes-expired",
1156 .enabled = arrowAndResourceLimitingMetrics,
1158 .
kind = Kind::UInt64,
1159 .scope = Scope::DPL,
1160 .minPublishInterval = 0,
1161 .maxRefreshLatency = 10000,
1162 .sendInitialValue =
true},
1163 MetricSpec{.name =
"shm-offer-bytes-consumed",
1164 .enabled = arrowAndResourceLimitingMetrics,
1166 .
kind = Kind::UInt64,
1167 .scope = Scope::DPL,
1168 .minPublishInterval = 0,
1169 .maxRefreshLatency = 10000,
1170 .sendInitialValue =
true},
1171 MetricSpec{.name =
"timeslice-offer-number-consumed",
1172 .enabled = arrowAndResourceLimitingMetrics,
1174 .
kind = Kind::UInt64,
1175 .scope = Scope::DPL,
1176 .minPublishInterval = 0,
1177 .maxRefreshLatency = 10000,
1178 .sendInitialValue =
true},
1179 MetricSpec{.name =
"timeslices-expired",
1180 .enabled = arrowAndResourceLimitingMetrics,
1182 .
kind = Kind::UInt64,
1183 .scope = Scope::DPL,
1184 .minPublishInterval = 0,
1185 .maxRefreshLatency = 10000,
1186 .sendInitialValue =
true},
1187 MetricSpec{.name =
"timeslices-started",
1188 .enabled = arrowAndResourceLimitingMetrics,
1190 .
kind = Kind::UInt64,
1191 .scope = Scope::DPL,
1192 .minPublishInterval = 0,
1193 .maxRefreshLatency = 10000,
1194 .sendInitialValue =
true},
1195 MetricSpec{.name =
"timeslices-done",
1196 .enabled = arrowAndResourceLimitingMetrics,
1198 .
kind = Kind::UInt64,
1199 .scope = Scope::DPL,
1200 .minPublishInterval = 0,
1201 .maxRefreshLatency = 10000,
1202 .sendInitialValue =
true},
1203 MetricSpec{.name =
"resources-missing",
1204 .enabled = enableDebugMetrics,
1206 .
kind = Kind::UInt64,
1207 .scope = Scope::DPL,
1208 .minPublishInterval = 1000,
1209 .maxRefreshLatency = 1000,
1210 .sendInitialValue =
true},
1211 MetricSpec{.name =
"resources-insufficient",
1212 .enabled = enableDebugMetrics,
1214 .
kind = Kind::UInt64,
1215 .scope = Scope::DPL,
1216 .minPublishInterval = 1000,
1217 .maxRefreshLatency = 1000,
1218 .sendInitialValue =
true},
1219 MetricSpec{.name =
"resources-satisfactory",
1220 .enabled = enableDebugMetrics,
1222 .
kind = Kind::UInt64,
1223 .scope = Scope::DPL,
1224 .minPublishInterval = 1000,
1225 .maxRefreshLatency = 1000,
1226 .sendInitialValue =
true},
1227 MetricSpec{.name =
"resource-offer-expired",
1228 .enabled = arrowAndResourceLimitingMetrics,
1230 .
kind = Kind::UInt64,
1231 .scope = Scope::DPL,
1232 .minPublishInterval = 0,
1233 .maxRefreshLatency = 10000,
1234 .sendInitialValue =
true},
1235 MetricSpec{.name =
"ccdb-cache-hit",
1238 .
kind = Kind::UInt64,
1239 .scope = Scope::DPL,
1240 .minPublishInterval = 1000,
1241 .maxRefreshLatency = 10000,
1242 .sendInitialValue =
true},
1243 MetricSpec{.name =
"ccdb-cache-miss",
1246 .
kind = Kind::UInt64,
1247 .scope = Scope::DPL,
1248 .minPublishInterval = 1000,
1249 .maxRefreshLatency = 10000,
1250 .sendInitialValue =
true},
1251 MetricSpec{.name =
"ccdb-cache-failure",
1254 .
kind = Kind::UInt64,
1255 .scope = Scope::DPL,
1256 .minPublishInterval = 1000,
1257 .maxRefreshLatency = 10000,
1258 .sendInitialValue =
true},
1259 MetricSpec{.name =
"ccdb-cache-fetched-bytes",
1262 .
kind = Kind::UInt64,
1263 .scope = Scope::DPL,
1264 .minPublishInterval = 1000,
1265 .maxRefreshLatency = 10000,
1266 .sendInitialValue =
true},
1267 MetricSpec{.name =
"ccdb-cache-requested-bytes",
1270 .
kind = Kind::UInt64,
1271 .scope = Scope::DPL,
1272 .minPublishInterval = 1000,
1273 .maxRefreshLatency = 10000,
1274 .sendInitialValue =
true}};
1276 for (
auto& metric :
metrics) {
1278 if (spec.name.compare(
"readout-proxy") == 0) {
1279 stats->hasAvailSHMMetric =
true;
1284 stats->registerMetric(metric);
1287 return ServiceHandle{TypeIdHelpers::uniqueId<DataProcessingStats>(), stats};
1295 sendRelayerMetrics(context.
services(), *stats);
1296 flushMetrics(context.
services(), *stats); },
1299 sendRelayerMetrics(context.
services(), *stats);
1300 flushMetrics(context.
services(), *stats); },
1303 sendRelayerMetrics(context.
services(), *stats);
1304 flushMetrics(context.
services(), *stats); },
1307 flushMetrics(
ref, *stats); },
1316 .
name =
"data-processing-states",
1319 clock_gettime(CLOCK_REALTIME, &now);
1320 uv_update_time(
state.loop);
1321 uint64_t
offset = now.tv_sec * 1000 - uv_now(
state.loop);
1330 states->processCommandQueue(); },
1349 .
name =
"gui-metrics",
1354 monitoring.send({(
int)spec.inputChannels.size(), fmt::format(
"oldest_possible_timeslice/h"), o2::monitoring::Verbosity::Debug});
1355 monitoring.send({(
int)1, fmt::format(
"oldest_possible_timeslice/w"), o2::monitoring::Verbosity::Debug});
1356 monitoring.send({(
int)spec.outputChannels.size(), fmt::format(
"oldest_possible_output/h"), o2::monitoring::Verbosity::Debug});
1357 monitoring.send({(
int)1, fmt::format(
"oldest_possible_output/w"), o2::monitoring::Verbosity::Debug});
1358 return ServiceHandle{TypeIdHelpers::uniqueId<GUIMetrics>(), stats};
1365 auto oldestPossibleOutput = relayer.getOldestPossibleOutput();
1366 for (
size_t ci; ci < spec.outputChannels.size(); ++ci) {
1367 monitoring.send({(uint64_t)oldestPossibleOutput.timeslice.value, fmt::format(
"oldest_possible_output/{}", ci), o2::monitoring::Verbosity::Debug});
1371 monitoring.send({(uint64_t)timeslice, fmt::format(
"oldest_possible_timeslice/{}", channel.value), o2::monitoring::Verbosity::Debug}); },
1379 .
name =
"object-cache",
1382 return ServiceHandle{TypeIdHelpers::uniqueId<ObjectCache>(), cache};
1391 .
name =
"data-processing-context",
1403 .
name =
"data-allocator",
1404 .uniqueId = simpleServiceId<DataAllocator>(),
1407 .
hash = TypeIdHelpers::uniqueId<DataAllocator>(),
1410 .name =
"data-allocator",
1420 std::vector<ServiceSpec> specs{
1450 std::string loadableServicesStr = extraPlugins;
1453 if (loadableServicesStr.empty() ==
false) {
1454 loadableServicesStr +=
",";
1456 loadableServicesStr +=
"O2FrameworkDataTakingSupport:InfoLoggerContext,O2FrameworkDataTakingSupport:InfoLogger";
1459 std::vector<LoadablePlugin> loadablePlugins = {};
1460 char* loadableServicesEnv = getenv(
"DPL_LOAD_SERVICES");
1464 if (loadableServicesEnv) {
1465 if (loadableServicesStr.empty() ==
false) {
1466 loadableServicesStr +=
",";
1468 loadableServicesStr += loadableServicesEnv;
1471 PluginManager::loadFromPlugin<ServiceSpec, ServicePlugin>(loadablePlugins, specs);
std::vector< std::string > labels
std::vector< OutputRoute > routes
o2::monitoring::tags::Key Key
o2::monitoring::Metric Metric
o2::monitoring::tags::Value Value
#define MONITORING_QUEUE_SIZE
#define O2_BUILTIN_LIKELY(x)
#define O2_SIGNPOST_EVENT_EMIT_ERROR(log, id, name, format,...)
#define O2_DECLARE_DYNAMIC_LOG(name)
#define O2_SIGNPOST_ID_FROM_POINTER(name, log, pointer)
#define O2_SIGNPOST_END(log, id, name, format,...)
#define O2_SIGNPOST_ID_GENERATE(name, log)
#define O2_SIGNPOST_EVENT_EMIT_CRITICAL(log, id, name, format,...)
#define O2_SIGNPOST_EVENT_EMIT_WARN(log, id, name, format,...)
#define O2_SIGNPOST_EVENT_EMIT(log, id, name, format,...)
#define O2_SIGNPOST_START(log, id, name, format,...)
o2::monitoring::Monitoring Monitoring
decltype(auto) make(const Output &spec, Args... args)
int countDeviceOutputs(bool excludeDPLOrigin=false)
Allow injecting policies on send.
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
void registerService(ServiceTypeHash typeHash, void *service, ServiceKind kind, char const *name=nullptr) const
A text based way of communicating with the driver.
OldestOutputInfo getOldestPossibleOutput() const
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLsizei const GLfloat * value
GLuint GLsizei const GLchar * label
Defining ITS Vertex explicitly as messageable.
@ DPL
The channel is a normal input channel.
const DataProcessorLabel suppressDomainInfoLabel
std::pair< std::string, unsigned short > parse_websocket_url(char const *url)
auto decongestionCallback
@ NoTransition
No pending transitions.
@ CCDB_CACHE_FETCHED_BYTES
@ AVAILABLE_MANAGED_SHM_BASE
@ SHM_OFFER_BYTES_CONSUMED
@ TIMESLICE_NUMBER_STARTED
@ CCDB_CACHE_REQUESTED_BYTES
@ TIMESLICE_NUMBER_EXPIRED
@ DROPPED_INCOMING_MESSAGES
@ ARROW_MESSAGES_DESTROYED
@ TIMESLICE_OFFER_NUMBER_CONSUMED
auto decongestionCallbackPastOldest
auto decongestionCallbackOrdered
std::string to_string(gsl::span< T, Size > span)
static ServiceSpec arrowTableSlicingCacheSpec()
static ServiceSpec arrowBackendSpec()
static ServiceSpec arrowTableSlicingCacheDefSpec()
static AsyncTaskId create(AsyncQueue &queue, AsyncTaskSpec spec)
static void post(AsyncQueue &queue, AsyncTask const &task)
static void reset(AsyncQueue &queue)
Reset the queue to its initial state.
An actuatual task to be executed.
static ServiceSpec fairMQDeviceProxy()
static ServiceSpec fairMQBackendSpec()
static ServiceSpec stringBackendSpec()
static ServiceSpec dataRelayer()
static ServiceSpec callbacksSpec()
static ServiceSpec monitoringSpec()
static ServiceSpec dataSender()
static ServiceSpec timesliceIndex()
static std::vector< ServiceSpec > defaultServices(std::string extraPlugins="", int numWorkers=0)
Split a string into a vector of strings using : as a separator.
static ServiceSpec timingInfoSpec()
static ServiceConfigureCallback noConfiguration()
static ServiceSpec asyncQueue()
static ServiceSpec decongestionSpec()
static ServiceSpec dataProcessorContextSpec()
static ServiceSpec dataProcessingStats()
static std::vector< ServiceSpec > arrowServices()
static ServiceSpec rootFileSpec()
static ServiceSpec objectCache()
static ServiceSpec controlSpec()
static ServiceSpec configurationSpec()
static ServiceSpec ccdbSupportSpec()
static ServiceSpec datatakingContextSpec()
static ServiceSpec guiMetricsSpec()
static ServiceSpec dataProcessingStates()
static ServiceSpec tracingSpec()
static ServiceSpec dataAllocatorSpec()
static ServiceSpec driverClientSpec()
static ServiceSpec streamContextSpec()
static ServiceSpec threadPool(int numWorkers)
static ServiceSpec parallelSpec()
static bool sendOldestPossibleTimeframe(ServiceRegistryRef const &ref, ForwardChannelInfo const &info, ForwardChannelState &state, size_t timeslice)
static void broadcastOldestPossibleTimeslice(ServiceRegistryRef const &ref, size_t timeslice)
Broadcast the oldest possible timeslice to all channels in output.
int64_t minOnlinePublishInterval
Helper struct to hold statistics about the data processing happening.
@ SetIfPositive
Set the value to the specified value.
@ InstantaneousRate
Update the rate of the metric given the cumulative value since last time it got published.
@ Add
Update the rate of the metric given the amount since the last time.
A label that can be associated to a DataProcessorSpec.
static std::string describe(InputSpec const &spec)
static ConcreteDataMatcher asConcreteDataMatcher(InputSpec const &input)
static bool match(InputSpec const &spec, ConcreteDataMatcher const &target)
DeploymentMode deploymentMode
Where we thing this is running.
TimesliceIndex::OldestOutputInfo oldestPossibleOutput
static DeploymentMode deploymentMode()
static unsigned int pipelineLength(unsigned int minLength)
get max number of timeslices in the queue
static bool onlineDeploymentMode()
@true if running online
std::string name
The name of the associated DataProcessorSpec.
size_t inputTimesliceId
The time pipelining id of this particular device.
Running state information of a given device.
header::DataOrigin origin
static std::vector< LoadablePlugin > parsePluginSpecString(char const *str)
Parse a comma separated list of <library>:<plugin-name> plugin declarations.
static bool isResourcesMonitoringEnabled(unsigned short interval) noexcept
Information about the running workflow.
ServiceKind kind
Kind of service.
unsigned int hash
Unique hash associated to the type of service.
std::string name
Name of the service.
ServicePostDispatching postDispatching
ServiceKind kind
Kind of service being specified.
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)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"