Project
Loading...
Searching...
No Matches
AODJAlienReaderHelpers.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
13#include <algorithm>
14#include <charconv>
15#include <cctype>
16#include <cstdlib>
17#include <exception>
18#include <memory>
19#include <ranges>
20#include <string>
21#include <string_view>
22#include <vector>
38#include "Framework/Signpost.h"
41#include "DataInputDirector.h"
42#include "NativeAOD.h"
45#include "Framework/Logger.h"
46
47#if __has_include(<TJAlienFile.h>)
48#include <TJAlienFile.h>
49#endif
50#include <TGrid.h>
51#include <TFile.h>
52#include <TTreeCache.h>
53#include <TSystem.h>
54
55#include <arrow/ipc/reader.h>
56#include <arrow/ipc/writer.h>
57#include <arrow/io/interfaces.h>
58#include <arrow/table.h>
59#include <arrow/util/key_value_metadata.h>
60#include <arrow/dataset/dataset.h>
61#include <arrow/dataset/file_base.h>
62
63using namespace o2;
64using namespace o2::aod;
65
67
70 uint64_t startTime;
71 uint64_t lastTime;
72 double runTime;
73 uint64_t runTimeLimit;
74
75 RuntimeWatchdog(Long64_t limit)
76 {
78 startTime = uv_hrtime();
80 runTime = 0.;
81 runTimeLimit = limit;
82 }
83
84 bool update()
85 {
87 if (runTimeLimit <= 0) {
88 return true;
89 }
90
91 auto nowTime = uv_hrtime();
92
93 // time spent to process the time frame
94 double time_spent = numberTimeFrames < 1 ? (double)(nowTime - lastTime) / 1.E9 : 0.;
95 runTime += time_spent;
96 lastTime = nowTime;
97
98 return ((double)(lastTime - startTime) / 1.E9 + runTime / (numberTimeFrames + 1)) < runTimeLimit;
99 }
100
101 void printOut()
102 {
103 LOGP(info, "RuntimeWatchdog");
104 LOGP(info, " run time limit: {}", runTimeLimit);
105 LOGP(info, " number of time frames: {}", numberTimeFrames);
106 LOGP(info, " estimated run time per time frame: {}", (numberTimeFrames >= 0) ? runTime / (numberTimeFrames + 1) : 0.);
107 LOGP(info, " estimated total run time: {}", (double)(lastTime - startTime) / 1.E9 + ((numberTimeFrames >= 0) ? runTime / (numberTimeFrames + 1) : 0.));
108 }
109};
110
111using o2::monitoring::Metric;
112using o2::monitoring::Monitoring;
113using o2::monitoring::tags::Key;
114using o2::monitoring::tags::Value;
115
117{
118static bool shouldSkipInvalidReads()
119{
120 auto const* envValue = getenv("DPL_AOD_READER_SKIP_INVALID");
121 if (envValue == nullptr) {
122 return false;
123 }
124
125 std::string value{envValue};
126 std::ranges::transform(value, value.begin(), [](unsigned char c) { return std::tolower(c); });
127 return !value.empty() && value != "0" && value != "false";
128}
129
130static std::string describeException(std::exception const& exception)
131{
132 std::string description{exception.what()};
133 try {
134 std::rethrow_if_nested(exception);
135 } catch (std::exception const& nested) {
136 description += fmt::format(": {}", describeException(nested));
137 } catch (RuntimeErrorRef const& ref) {
138 description += fmt::format(": {}", error_from_ref(ref).what);
139 } catch (...) {
140 description += ": unknown exception";
141 }
142 return description;
143}
144
146{
147 // aod-parent-base-path-replacement is now a workflow option, so it needs to be
148 // retrieved from the ConfigContext. This is because we do not allow workflow options
149 // to change over start-stop-start because they can affect the topology generation.
150 std::string parentFileReplacement;
151 if (ctx.options().isSet("aod-parent-base-path-replacement")) {
152 parentFileReplacement = ctx.options().get<std::string>("aod-parent-base-path-replacement");
153 }
154 int parentAccessLevel = 0;
155 if (ctx.options().isSet("aod-parent-access-level")) {
156 parentAccessLevel = ctx.options().get<int>("aod-parent-access-level");
157 }
158 std::vector<std::pair<std::string, int>> originLevelMapping;
159 if (ctx.options().isSet("aod-origin-level-mapping")) {
160 auto originLevelMappingStr = ctx.options().get<std::string>("aod-origin-level-mapping");
161 for (auto pairRange : originLevelMappingStr | std::views::split(',')) {
162 std::string_view pair{pairRange.begin(), pairRange.end()};
163 auto colonPos = pair.find(':');
164 if (colonPos == std::string_view::npos) {
165 LOGP(fatal, "Badly formatted aod-origin-level-mapping entry: \"{}\"", pair);
166 continue;
167 }
168 std::string key(pair.substr(0, colonPos));
169 std::string_view valueStr = pair.substr(colonPos + 1);
170 int value{};
171 auto [ptr, ec] = std::from_chars(valueStr.data(), valueStr.data() + valueStr.size(), value);
172 if (ec == std::errc{}) {
173 originLevelMapping.emplace_back(std::move(key), value);
174 } else {
175 LOGP(fatal, "Unable to parse level in aod-origin-level-mapping entry: \"{}\"", pair);
176 }
177 }
178 }
179 auto callback = AlgorithmSpec{adaptStateful([parentFileReplacement, parentAccessLevel, originLevelMapping](ConfigParamRegistry const& options,
180 DeviceSpec const& spec,
181 Monitoring& monitoring,
182 DataProcessingStats& stats) {
183 // FIXME: not actually needed, since data processing stats can specify that we should
184 // send the initial value.
185 stats.updateStats({static_cast<short>(ProcessingStatsId::ARROW_BYTES_CREATED), DataProcessingStats::Op::Set, 0});
186 stats.updateStats({static_cast<short>(ProcessingStatsId::ARROW_MESSAGES_CREATED), DataProcessingStats::Op::Set, 0});
187 stats.updateStats({static_cast<short>(ProcessingStatsId::ARROW_BYTES_DESTROYED), DataProcessingStats::Op::Set, 0});
188 stats.updateStats({static_cast<short>(ProcessingStatsId::ARROW_MESSAGES_DESTROYED), DataProcessingStats::Op::Set, 0});
189 stats.updateStats({static_cast<short>(ProcessingStatsId::ARROW_BYTES_EXPIRED), DataProcessingStats::Op::Set, 0});
190 stats.updateStats({static_cast<short>(ProcessingStatsId::CONSUMED_TIMEFRAMES), DataProcessingStats::Op::Set, 0});
191
192 if (!options.isSet("aod-file-private")) {
193 LOGP(fatal, "No input file defined!");
194 throw std::runtime_error("Processing is stopped!");
195 }
196
197 auto filename = options.get<std::string>("aod-file-private");
198
199 auto maxRate = options.get<float>("aod-max-io-rate");
200
201 // create a DataInputDirector
202 DataInputDirectorContext context{&monitoring, parentAccessLevel, parentFileReplacement, originLevelMapping};
203 context.readerBackend = options.get<std::string>("aod-reader-backend");
204 if (context.readerBackend != "root" && context.readerBackend != "native" && context.readerBackend != "auto") {
205 LOGP(fatal, "Invalid --aod-reader-backend \"{}\": use root, native or auto.", context.readerBackend);
206 }
207 context.nativeOptions.threads = std::max(1, options.get<int>("aod-reader-threads"));
208 context.nativeOptions.prefetchDepth = std::max(0, options.get<int>("aod-reader-prefetch"));
209 if (auto mb = options.get<int>("aod-reader-buffer-mb"); mb >= 0) {
210 context.nativeOptions.bufferBudget = mb * size_t{1024 * 1024};
211 }
212 auto localIO = options.get<std::string>("aod-reader-local-io");
213 if (localIO != "mmap" && localIO != "pread") {
214 LOGP(fatal, "Invalid --aod-reader-local-io \"{}\": use mmap or pread.", localIO);
215 }
216 context.nativeOptions.localIO = localIO == "pread" ? o2::aod::native::Options::LocalIO::PRead : o2::aod::native::Options::LocalIO::MMap;
217 auto didir = std::make_shared<DataInputDirector>(std::vector<std::string>{filename}, std::move(context));
218 if (options.isSet("aod-reader-json")) {
219 auto jsonFile = options.get<std::string>("aod-reader-json");
220 if (!didir->readJson(jsonFile)) {
221 LOGP(error, "Check the JSON document! Can not be properly parsed!");
222 }
223 }
224
225 // get the run time watchdog
226 auto* watchdog = new RuntimeWatchdog(options.get<int64_t>("time-limit"));
227
228 // selected the TFN input and
229 // create list of requested tables
230 bool reportTFN = false;
231 bool reportTFFileName = false;
232 header::DataHeader TFNumberHeader;
233 header::DataHeader TFFileNameHeader;
234 std::vector<OutputRoute> requestedTables;
235 std::vector<OutputRoute> routes(spec.outputs);
236 for (auto route : routes) {
237 if (DataSpecUtils::partialMatch(route.matcher, header::DataOrigin("TFN"))) {
238 auto concrete = DataSpecUtils::asConcreteDataMatcher(route.matcher);
239 TFNumberHeader = header::DataHeader(concrete.description, concrete.origin, concrete.subSpec);
240 reportTFN = true;
241 } else if (DataSpecUtils::partialMatch(route.matcher, header::DataOrigin("TFF"))) {
242 auto concrete = DataSpecUtils::asConcreteDataMatcher(route.matcher);
243 TFFileNameHeader = header::DataHeader(concrete.description, concrete.origin, concrete.subSpec);
244 reportTFFileName = true;
245 } else {
246 requestedTables.emplace_back(route);
247 }
248 }
249 int level = originLevelMapping.empty() ? -1 : 0;
250 auto fileCounter = std::make_shared<int>(0);
251 auto numTF = std::make_shared<int>(-1);
252 bool const skipInvalidReads = shouldSkipInvalidReads();
253 return adaptStateless([TFNumberHeader,
254 TFFileNameHeader,
255 requestedTables,
256 fileCounter,
257 numTF,
258 watchdog,
259 maxRate,
260 skipInvalidReads,
261 didir, reportTFN, reportTFFileName, level](Monitoring& monitoring, DataAllocator& outputs, ControlService& control, DeviceSpec const& device, DataProcessingStats& dpstats, ArrowContext& arrowContext, MessageContext& messageContext, StringContext& stringContext) {
262 // Each parallel reader device.inputTimesliceId reads the files fileCounter*device.maxInputTimeslices+device.inputTimesliceId
263 // the TF to read is numTF
264 assert(device.inputTimesliceId < device.maxInputTimeslices);
265 int fcnt = (*fileCounter * device.maxInputTimeslices) + device.inputTimesliceId;
266 int ntf = *numTF + 1;
267 static int currentFileCounter = -1;
268 static int filesProcessed = 0;
269 if (currentFileCounter != *fileCounter) {
270 currentFileCounter = *fileCounter;
271 monitoring.send(Metric{(uint64_t)++filesProcessed, "files-opened"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL));
272 }
273
274 // loop over requested tables
275 static size_t totalSizeUncompressed = 0;
276 static size_t totalSizeCompressed = 0;
277 static uint64_t totalDFSent = 0;
278 static uint64_t totalInvalidReadSkipped = 0;
279 static uint64_t totalFileOpenSkipped = 0;
280
281 // check if RuntimeLimit is reached
282 if (!watchdog->update()) {
283 LOGP(info, "Run time exceeds run time limit of {} seconds. Exiting gracefully...", watchdog->runTimeLimit);
284 LOGP(info, "Stopping reader {} after time frame {}.", device.inputTimesliceId, watchdog->numberTimeFrames - 1);
285 didir->closeInputFiles();
286 monitoring.flushBuffer();
287 control.endOfStream();
289 return;
290 }
291
292 int64_t startTime = uv_hrtime();
293 int64_t startSize = totalSizeCompressed;
294 auto discardTimeframe = [&didir, &arrowContext, &messageContext, &stringContext]() {
296 didir->finishTimeFrame(true);
297 arrowContext.clear();
298 messageContext.discard();
299 stringContext.clear();
300 };
301 auto skipInvalidRead = [&fcnt, &ntf, &discardTimeframe, &dpstats, &fileCounter, &numTF, &device](ConcreteDataMatcher const& concrete, AODReadError const& e) {
302 auto skippedTimeframes = ++totalInvalidReadSkipped;
303 LOGP(error, "Invalid AOD read for table {}: fileCounter {}, timeFrame {}. Skipping timeframe (skipped timeframes: {}). Reason: {}",
304 concrete.origin.as<std::string>(), fcnt, ntf, skippedTimeframes, describeException(e));
305 discardTimeframe();
307 *fileCounter = (fcnt - device.inputTimesliceId) / device.maxInputTimeslices;
308 *numTF = ntf;
309 };
310 enum class TFReaderState {
311 READ_FIRST_TABLE,
312 READ_FIRST_TABLE_FROM_NEXT_FILE,
313 READ_NEXT_TABLE,
314 TRY_NEXT_FILE,
315 TIMEFRAME_READ,
316 INVALID_TIMEFRAME,
317 INVALID_FILE,
318 };
319 auto readState = TFReaderState::READ_FIRST_TABLE;
320 [[maybe_unused]] auto stateName = [](TFReaderState state) -> char const* {
321 switch (state) {
322 case TFReaderState::READ_FIRST_TABLE:
323 return "READ_FIRST_TABLE";
324 case TFReaderState::READ_FIRST_TABLE_FROM_NEXT_FILE:
325 return "READ_FIRST_TABLE_FROM_NEXT_FILE";
326 case TFReaderState::READ_NEXT_TABLE:
327 return "READ_NEXT_TABLE";
328 case TFReaderState::TRY_NEXT_FILE:
329 return "TRY_NEXT_FILE";
330 case TFReaderState::TIMEFRAME_READ:
331 return "TIMEFRAME_READ";
332 case TFReaderState::INVALID_TIMEFRAME:
333 return "INVALID_TIMEFRAME";
334 case TFReaderState::INVALID_FILE:
335 return "INVALID_FILE";
336 }
337 return "UNKNOWN";
338 };
339 O2_SIGNPOST_ID_FROM_POINTER(readerStateId, aod_reader, &readState);
340 auto transitionTo = [&](TFReaderState nextState) {
341 O2_SIGNPOST_EVENT_EMIT(aod_reader, readerStateId, "state transition",
342 "%{public}s -> %{public}s (fileCounter %d, timeFrame %d)",
343 stateName(readState), stateName(nextState), fcnt, ntf);
344 readState = nextState;
345 };
346 size_t routeIndex = 0;
347 auto reportTimeframe = [&didir, &fcnt, &ntf, &outputs, &TFNumberHeader, &TFFileNameHeader, reportTFN, reportTFFileName](header::DataHeader const& dh) {
348 if (reportTFN) {
349 // TF number
350 auto timeFrameNumber = didir->getTimeFrameNumber(dh, fcnt, ntf);
351 auto o = Output(TFNumberHeader);
352 outputs.make<uint64_t>(o) = timeFrameNumber;
353 }
354
355 if (reportTFFileName) {
356 // Origin file name for derived output map
357 auto o2 = Output(TFFileNameHeader);
358 auto fileAndFolder = didir->getFileFolder(dh, fcnt, ntf);
359 static std::string pwd = gSystem->pwd() + std::string("/");
360 std::string currentFilename;
361 if (auto nativeFS = std::dynamic_pointer_cast<NativeAODFileSystem>(fileAndFolder.filesystem())) {
362 currentFilename = nativeFS->name();
363 // Only a relative local path needs to be made absolute; URLs are kept as they are.
364 if (!currentFilename.starts_with("/") && currentFilename.find("://") == std::string::npos) {
365 currentFilename = pwd + currentFilename;
366 }
367 } else {
368 auto rootFS = std::dynamic_pointer_cast<TFileFileSystem>(fileAndFolder.filesystem());
369 auto* f = dynamic_cast<TFile*>(rootFS->GetFile());
370 currentFilename = f->GetFile()->GetName();
371 if (strcmp(f->GetEndpointUrl()->GetProtocol(), "file") == 0 && f->GetEndpointUrl()->GetFile()[0] != '/') {
372 // This is not an absolute local path. Make it absolute.
373 currentFilename = pwd + std::string(f->GetName());
374 }
375 }
376 outputs.make<std::string>(o2) = currentFilename;
377 }
378 };
379 auto tryReadTable = [&device, &didir, &fcnt, &ntf, &outputs, &reportTimeframe, &requestedTables, &routeIndex, &skipInvalidRead, &discardTimeframe, &dpstats, skipInvalidReads](TFReaderState currentState) -> TFReaderState {
380 while (routeIndex < requestedTables.size() &&
381 (device.inputTimesliceId % requestedTables[routeIndex].maxTimeslices) != requestedTables[routeIndex].timeslice) {
382 ++routeIndex;
383 }
384 if (routeIndex == requestedTables.size()) {
385 return TFReaderState::TIMEFRAME_READ;
386 }
387
388 auto& route = requestedTables[routeIndex];
389 auto concrete = DataSpecUtils::asConcreteDataMatcher(route.matcher);
390 auto dh = header::DataHeader(concrete.description, concrete.origin, concrete.subSpec);
391 bool wasAOD = std::ranges::any_of(route.matcher.metadata, [](ConfigParamSpec const& p) { return p.name.starts_with("aod-origin-replaced"); });
392
393 if (currentState == TFReaderState::READ_FIRST_TABLE || currentState == TFReaderState::READ_FIRST_TABLE_FROM_NEXT_FILE) {
394 didir->beginTimeFrame();
395 }
396 try {
397 if (!didir->readTree(outputs, dh, fcnt, ntf, totalSizeCompressed, totalSizeUncompressed, wasAOD)) {
398 return TFReaderState::TRY_NEXT_FILE;
399 }
400 } catch (AODReadError const& e) {
401 if (!skipInvalidReads) {
402 throw AODReadError(e.getKind(), describeException(e));
403 }
404 switch (e.getKind()) {
406 skipInvalidRead(concrete, e);
407 return TFReaderState::INVALID_TIMEFRAME;
409 auto skippedFiles = ++totalFileOpenSkipped;
410 LOGP(error, "Unable to open AOD input for table {}: fileCounter {}, timeFrame {}. Skipping file (skipped files: {}). Reason: {}",
411 concrete.origin.as<std::string>(), fcnt, ntf, skippedFiles, describeException(e));
412 discardTimeframe();
413 dpstats.updateStats({static_cast<short>(ProcessingStatsId::AOD_FILE_OPEN_SKIPPED_FILES), DataProcessingStats::Op::Add, 1});
414 return TFReaderState::INVALID_FILE;
415 }
416 }
417 throw;
418 }
419
420 if (currentState == TFReaderState::READ_FIRST_TABLE || currentState == TFReaderState::READ_FIRST_TABLE_FROM_NEXT_FILE) {
421 reportTimeframe(dh);
422 }
423 ++routeIndex;
424 return TFReaderState::READ_NEXT_TABLE;
425 };
426 while (readState != TFReaderState::TIMEFRAME_READ) {
427 switch (readState) {
428 case TFReaderState::READ_FIRST_TABLE:
429 transitionTo(tryReadTable(readState));
430 break;
431 case TFReaderState::READ_FIRST_TABLE_FROM_NEXT_FILE:
432 case TFReaderState::READ_NEXT_TABLE:
433 transitionTo(tryReadTable(readState));
434 if (readState == TFReaderState::TRY_NEXT_FILE) {
435 // Once a file has been selected, every requested table must exist.
436 auto concrete = DataSpecUtils::asConcreteDataMatcher(requestedTables[routeIndex].matcher);
437 LOGP(fatal, "Can not retrieve tree for table {}: fileCounter {}, timeFrame {}", concrete.origin.as<std::string>(), fcnt, ntf);
438 throw std::runtime_error("Processing is stopped!");
439 }
440 break;
441 case TFReaderState::INVALID_FILE:
442 // Undo the discard so outputs read from the next file are checked as usual
443 messageContext.clear();
444 [[fallthrough]];
445 case TFReaderState::TRY_NEXT_FILE:
446 didir->finishTimeFrame();
447 fcnt += device.maxInputTimeslices;
448 if (didir->atEnd(fcnt)) {
449 LOGP(info, "No input files left to read for reader {}!", device.inputTimesliceId);
450 didir->closeInputFiles();
451 monitoring.flushBuffer();
452 control.endOfStream();
454 return;
455 }
456 ntf = 0;
457 routeIndex = 0;
458 transitionTo(TFReaderState::READ_FIRST_TABLE_FROM_NEXT_FILE);
459 break;
460 case TFReaderState::INVALID_TIMEFRAME:
461 // Returning would leak this callback's timeslice offer, so read the next timeframe.
462 messageContext.clear();
463 ++ntf;
464 routeIndex = 0;
465 transitionTo(TFReaderState::READ_FIRST_TABLE);
466 break;
467 case TFReaderState::TIMEFRAME_READ:
468 break;
469 }
470 }
471 didir->finishTimeFrame();
472 int64_t stopSize = totalSizeCompressed;
473 int64_t bytesDelta = stopSize - startSize;
474 int64_t stopTime = uv_hrtime();
475 float currentDelta = float(stopTime - startTime) / 1000000000; // in s
476 if (ceil(maxRate) > 0.) {
477 float extraTime = (bytesDelta / 1000000 - currentDelta * maxRate) / maxRate;
478 // We only sleep if we read faster than the max-read-rate.
479 if (extraTime > 0.) {
480 LOGP(info, "Read {} MB in {} s. Sleeping for {} seconds to stay within {} MB/s limit.", bytesDelta / 1000000, currentDelta, extraTime, maxRate);
481 uv_sleep(extraTime * 1000); // in milliseconds
482 }
483 }
484 totalDFSent++;
485
486 // Use the new API for sending TIMESLICE_NUMBER_STARTED
488 dpstats.processCommandQueue();
489 monitoring.send(Metric{(uint64_t)totalDFSent, "df-sent"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL));
490 monitoring.send(Metric{(uint64_t)totalSizeUncompressed / 1000, "aod-bytes-read-uncompressed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL));
491 monitoring.send(Metric{(uint64_t)totalSizeCompressed / 1000, "aod-bytes-read-compressed"}.addTag(Key::Subsystem, monitoring::tags::Value::DPL));
492
493 // save file number and time frame
494 *fileCounter = (fcnt - device.inputTimesliceId) / device.maxInputTimeslices;
495 *numTF = ntf;
496
497 // Check if the next timeframe is available or
498 // if there are more files to be processed. If not, simply exit.
499 ntf = *numTF + 1;
500 // first route with level 0 or -1 if no mapping requested
501 auto firstRoute = std::ranges::find_if(requestedTables, [&didir, level](auto const& route) {
502 auto concrete = DataSpecUtils::asConcreteDataMatcher(route.matcher);
503 return didir->getLevelForOrigin(concrete.origin) == level;
504 });
505 auto concrete = DataSpecUtils::asConcreteDataMatcher(firstRoute->matcher);
506 auto dh = header::DataHeader(concrete.description, concrete.origin, concrete.subSpec);
507 auto fileAndFolder = didir->getFileFolder(dh, fcnt, ntf);
508
509 // In case the filesource is empty, move to the next one.
510 if (fileAndFolder.filesystem() == nullptr) {
511 fcnt += 1;
512 ntf = 0;
513 if (didir->atEnd(fcnt)) {
514 LOGP(info, "No input files left to read for reader {}!", device.inputTimesliceId);
515 didir->closeInputFiles();
516 monitoring.flushBuffer();
517 control.endOfStream();
519 return;
520 }
521 }
522 });
523 })};
524
525 return callback;
526}
527
528} // namespace o2::framework::readers
header::DataDescription description
std::vector< OutputRoute > routes
o2::monitoring::Metric Metric
char error[CURL_ERROR_SIZE]
SurfaceTrackState state
uint32_t c
Definition RawData.h:2
#define O2_DECLARE_DYNAMIC_LOG(name)
Definition Signpost.h:490
#define O2_SIGNPOST_ID_FROM_POINTER(name, log, pointer)
Definition Signpost.h:506
#define O2_SIGNPOST_EVENT_EMIT(log, id, name, format,...)
Definition Signpost.h:523
TBranch * ptr
o2::monitoring::Monitoring Monitoring
StringRef key
void readyToQuit(bool all)
Compatibility with old API.
void endOfStream()
Signal that we are done with the current stream.
GLdouble f
Definition glcorearb.h:310
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLint level
Definition glcorearb.h:275
GLint ref
Definition glcorearb.h:291
constexpr framework::ConcreteDataMatcher matcher()
Definition ASoA.h:388
void clean_all_runtime_errors()
RuntimeError & error_from_ref(RuntimeErrorRef)
@ Me
Only quit this data processor.
AlgorithmSpec::ProcessCallback adaptStateless(LAMBDA l)
AlgorithmSpec::InitCallback adaptStateful(LAMBDA l)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string filename()
RuntimeWatchdog(Long64_t limit)
Helper struct to hold statistics about the data processing happening.
@ Add
Update the rate of the metric given the amount since the last time.
static bool partialMatch(InputSpec const &spec, o2::header::DataOrigin const &origin)
static ConcreteDataMatcher asConcreteDataMatcher(InputSpec const &input)
size_t maxInputTimeslices
The maximum number of time pipelining for this device.
Definition DeviceSpec.h:70
size_t inputTimesliceId
The time pipelining id of this particular device.
Definition DeviceSpec.h:68
std::vector< OutputRoute > outputs
Definition DeviceSpec.h:63
static AlgorithmSpec rootFileReaderCallback(ConfigContext const &context)
the main header struct
Definition DataHeader.h:623