Project
Loading...
Searching...
No Matches
Plugin.cxx
Go to the documentation of this file.
1// Copyright 2019-2024 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#include "Framework/Plugins.h"
15#include "Framework/Logger.h"
17#include "Framework/Signpost.h"
20#include <TBufferFile.h>
21#include <TDirectory.h>
22#include <TTree.h>
23#include <TDirectoryFile.h>
24#include <TClass.h>
25#include <arrow/dataset/file_base.h>
26#include <arrow/filesystem/filesystem.h>
27#include <atomic>
28#include <cstddef>
29#include <memory>
30#include <string_view>
31
33namespace o2::framework
34{
35auto lookForAodFile = [](ConfigParamRegistry& registry, int argc, char** argv) -> bool {
36 O2_SIGNPOST_ID_GENERATE(sid, capabilities);
37 if (registry.hasOption("aod-file") && registry.isSet("aod-file")) {
38 for (size_t i = 0; i < argc; i++) {
39 std::string_view arg = argv[i];
40 if (arg.starts_with("--aod-metadata-")) {
41 return false;
42 }
43 }
44 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverMetadataInAODCapability", "Metadata not found in arguments. Checking in AOD file.");
45 return true;
46 }
47 return false;
48};
49
50auto lookForCommandLineOptions = [](ConfigParamRegistry& registry, int argc, char** argv) -> bool {
51 O2_SIGNPOST_ID_GENERATE(sid, capabilities);
52 for (size_t i = 0; i < argc; i++) {
53 std::string_view arg = argv[i];
54 if (arg.starts_with("--aod-metadata-")) {
55 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverMetadataInCommandLineCapability", "Metadata found in arguments. Populating from them.");
56 return true;
57 }
58 }
59 return false;
60};
61
62auto lookForCommandLineAODOptions = [](ConfigParamRegistry& registry, int argc, char** argv) -> bool {
63 O2_SIGNPOST_ID_GENERATE(sid, capabilities);
64 // If one of the options for aod-writer is specified, we should allow configuring compression.
65 for (size_t i = 0; i < argc; i++) {
66 std::string_view arg = argv[i];
67 if (arg.starts_with("--aod-writer-")) {
68 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverAODOptionsInCommandLineCapability", "AOD options found in arguments. Populating from them.");
69 return true;
70 }
71 if (arg.starts_with("--aod-parent-")) {
72 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverAODOptionsInCommandLineCapability", "AOD options found in arguments. Populating from them.");
73 return true;
74 }
75 if (arg.starts_with("--aod-origin-")) {
76 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverAODOptionsInCommandLineCapability", "AOD options found in arguments. Populating from them.");
77 return true;
78 }
79 }
80 return false;
81};
82
83struct DiscoverMetadataInAODCapability : o2::framework::CapabilityPlugin {
84 Capability* create() override
85 {
86 return new Capability{
87 .name = "DiscoverMetadataInAODCapability",
88 .checkIfNeeded = lookForAodFile,
89 .requiredPlugin = "O2FrameworkAnalysisSupport:DiscoverMetadataInAOD"};
90 }
91};
92
93// Trigger discovery of metadata from command line, if needed.
94struct DiscoverMetadataInCommandLineCapability : o2::framework::CapabilityPlugin {
95 Capability* create() override
96 {
97 return new Capability{
98 .name = "DiscoverMetadataInCommandLineCapability",
99 .checkIfNeeded = lookForCommandLineOptions,
100 .requiredPlugin = "O2Framework:DiscoverMetadataInCommandLine"};
101 }
102};
103
104struct DiscoverAODOptionsInCommandLineCapability : o2::framework::CapabilityPlugin {
105 Capability* create() override
106 {
107 return new Capability{
108 .name = "DiscoverAODOptionsInCommandLineCapability",
109 .checkIfNeeded = lookForCommandLineAODOptions,
110 .requiredPlugin = "O2Framework:DiscoverAODOptionsInCommandLine"};
111 }
112};
113
114struct DiscoverMetadataInCommandLine : o2::framework::ConfigDiscoveryPlugin {
115 ConfigDiscovery* create() override
116 {
117 return new ConfigDiscovery{
118 .init = []() {},
119 .discover = [](ConfigParamRegistry& registry, int argc, char** argv) -> std::vector<ConfigParamSpec> {
120 O2_SIGNPOST_ID_GENERATE(sid, capabilities);
121 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverMetadataInCommandLine",
122 "Discovering metadata for analysis from well known environment variables.");
123 std::vector<ConfigParamSpec> results;
124 for (size_t i = 0; i < argc; i++) {
125 std::string_view arg = argv[i];
126 if (!arg.starts_with("--aod-metadata")) {
127 continue;
128 }
129 std::string key = arg.data() + 2;
130 std::string value = argv[i + 1];
131 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverMetadataInCommandLine",
132 "Found %{public}s with value %{public}s.", key.c_str(), value.c_str());
133 if (key == "aod-metadata-tables") {
134 std::stringstream is(value);
135 auto arrayValue = VariantJSONHelpers::read<VariantType::ArrayString>(is);
136 results.push_back(ConfigParamSpec{key, VariantType::ArrayString, arrayValue, {"Metadata in command line"}});
137 } else {
138 results.push_back(ConfigParamSpec{key, VariantType::String, value, {"Metadata in command line"}});
139 }
140 }
141 return results;
142 }};
143 }
144};
145
146struct DiscoverAODOptionsInCommandLine : o2::framework::ConfigDiscoveryPlugin {
147 ConfigDiscovery* create() override
148 {
149 return new ConfigDiscovery{
150 .init = []() {},
151 .discover = [](ConfigParamRegistry& registry, int argc, char** argv) -> std::vector<ConfigParamSpec> {
152 O2_SIGNPOST_ID_GENERATE(sid, capabilities);
153 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverAODOptionsInCommandLine",
154 "Discovering AOD handling related options in commandline arguments.");
155 std::vector<ConfigParamSpec> results;
156 bool injectOption = true;
157 for (size_t i = 0; i < argc; i++) {
158 std::string_view arg = argv[i];
159 if (!arg.starts_with("--aod-writer-") && !arg.starts_with("--aod-parent-") && !arg.starts_with("--aod-origin-")) {
160 continue;
161 }
162 std::string key = arg.data() + 2;
163 std::string value = argv[i + 1];
164 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverAODOptionsInCommandLine",
165 "Found %{public}s with value %{public}s.", key.c_str(), value.c_str());
166 if (key == "aod-writer-compression") {
167 int numericValue = std::stoi(value);
168 results.push_back(ConfigParamSpec{"aod-writer-compression", VariantType::Int, numericValue, {"AOD Compression options"}});
169 injectOption = false;
170 }
171 if (key == "aod-parent-base-path-replacement") {
172 results.push_back(ConfigParamSpec{"aod-parent-base-path-replacement", VariantType::String, value, {R"(Replace base path of parent files. Syntax: FROM;TO. E.g. "alien:///path/in/alien;/local/path". Enclose in "" on the command line.)"}});
173 }
174 if (key == "aod-parent-access-level") {
175 results.push_back(ConfigParamSpec{"aod-parent-access-level", VariantType::String, value, {"Allow parent file access up to specified level. Default: no (0)"}});
176 }
177 if (key == "aod-origin-level-mapping") {
178 results.push_back(ConfigParamSpec{"aod-origin-level-mapping", VariantType::String, value, {"Map origin to parent level for AOD reading. Syntax: ORIGIN:LEVEL[,ORIGIN2:LEVEL2,...]. E.g. \"DYN:1\"."}});
179 }
180 }
181 if (injectOption) {
182 results.push_back(ConfigParamSpec{"aod-writer-compression", VariantType::Int, 505, {"AOD Compression options"}});
183 }
184 return results;
185 }};
186 }
187};
188
189struct ImplementationContext {
190 std::vector<RootArrowFactory> implementations;
191};
192
193std::function<void*(std::shared_ptr<arrow::fs::FileSystem>, std::string const&)> getHandleByClass(char const* classname)
194{
195 return [classname, cache = std::make_shared<std::atomic<TClass*>>(nullptr)](std::shared_ptr<arrow::fs::FileSystem> fs, std::string const& path) -> void* {
196 auto getClass = [&]() {
197 auto* c = cache->load();
198 if (c == nullptr) {
199 c = TClass::GetClass(classname);
200 cache->store(c);
201 }
202 return c;
203 };
204 if (auto tfileFS = std::dynamic_pointer_cast<TFileFileSystem>(fs)) {
205 return tfileFS->GetFile()->GetObjectChecked(path.c_str(), getClass());
206 } else if (auto tbufferFS = std::dynamic_pointer_cast<TBufferFileFS>(fs)) {
207 tbufferFS->GetBuffer()->Reset();
208 return tbufferFS->GetBuffer()->ReadObjectAny(getClass());
209 }
210 return nullptr;
211 };
212}
213
214std::function<bool(char const*)> matchClassByName(std::string_view classname)
215{
216 return [c = classname](char const* attempt) -> bool {
217 return c == attempt;
218 };
219}
220
221void lazyLoadFactory(std::vector<RootArrowFactory>& implementations, char const* specs)
222{
223 // Lazy loading of the plugin so that we do not bring in RNTuple / TTree if not needed
224 if (implementations.empty()) {
225 std::vector<LoadablePlugin> plugins;
226 auto morePlugins = PluginManager::parsePluginSpecString(specs);
227 for (auto& extra : morePlugins) {
228 plugins.push_back(extra);
229 }
230 PluginManager::loadFromPlugin<RootArrowFactory, RootArrowFactoryPlugin>(plugins, implementations);
231 if (implementations.empty()) {
232 return;
233 }
234 }
235}
236
237struct RNTupleObjectReadingCapability : o2::framework::RootObjectReadingCapabilityPlugin {
239 {
240 auto context = new ImplementationContext;
241
243 {
244 .name = "rntuple",
245 .lfn2objectPath = [](std::string s) -> std::string {
246 std::replace(s.begin()+1, s.end(), '/', '-');
247#if __has_include(<ROOT/RFieldBase.hxx>)
248 if (s.starts_with("/")) {
249 return std::string(s.begin() + 1, s.end());
250 } else {
251 return s;
252 } },
253#else
254 if (s.starts_with("/")) {
255 return s;
256 } else {
257 return "/" + s;
258 } },
259#endif
260#if __has_include(<ROOT/RFieldBase.hxx>)
261 .getHandle = getHandleByClass("ROOT::RNTuple"),
262 .checkSupport = matchClassByName("ROOT::RNTuple"),
263#else
264 .getHandle = getHandleByClass("ROOT::Experimental::RNTuple"),
265 .checkSupport = matchClassByName("ROOT::Experimental::RNTuple"),
266#endif
267 .factory = [context]() -> RootArrowFactory& {
268 lazyLoadFactory(context->implementations, "O2FrameworkAnalysisRNTupleSupport:RNTupleObjectReadingImplementation");
269 return context->implementations.back();
270 }
271 };
272 }
273};
274
275struct TTreeObjectReadingCapability : o2::framework::RootObjectReadingCapabilityPlugin {
277 {
278 auto context = new ImplementationContext;
279
281 .name = "ttree",
282 .lfn2objectPath = [](std::string s) { return s; },
283 .getHandle = getHandleByClass("TTree"),
284 .checkSupport = matchClassByName("TTree"),
285 .accountBytes = [](void* handle, size_t& compressed, size_t& uncompressed) {
286 auto* tree = (TTree*)handle;
287 compressed += tree->GetZipBytes();
288 uncompressed += tree->GetTotBytes(); },
289 .factory = [context]() -> RootArrowFactory& {
290 lazyLoadFactory(context->implementations, "O2FrameworkAnalysisTTreeSupport:TTreeObjectReadingImplementation");
291 return context->implementations.back();
292 }};
293 }
294};
295
297DEFINE_DPL_PLUGIN_INSTANCE(DiscoverMetadataInAODCapability, Capability);
298DEFINE_DPL_PLUGIN_INSTANCE(DiscoverMetadataInCommandLineCapability, Capability);
299DEFINE_DPL_PLUGIN_INSTANCE(DiscoverAODOptionsInCommandLineCapability, Capability);
300DEFINE_DPL_PLUGIN_INSTANCE(DiscoverMetadataInCommandLine, ConfigDiscovery);
301DEFINE_DPL_PLUGIN_INSTANCE(DiscoverAODOptionsInCommandLine, ConfigDiscovery);
302DEFINE_DPL_PLUGIN_INSTANCE(RNTupleObjectReadingCapability, RootObjectReadingCapability);
303DEFINE_DPL_PLUGIN_INSTANCE(TTreeObjectReadingCapability, RootObjectReadingCapability);
305} // namespace o2::framework
int32_t i
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
CURL * handle
#define DEFINE_DPL_PLUGIN_INSTANCE(NAME, KIND)
Definition Plugins.h:112
#define DEFINE_DPL_PLUGINS_END
Definition Plugins.h:115
#define DEFINE_DPL_PLUGINS_BEGIN
Definition Plugins.h:107
uint32_t c
Definition RawData.h:2
#define O2_DECLARE_DYNAMIC_LOG(name)
Definition Signpost.h:490
#define O2_SIGNPOST_ID_GENERATE(name, log)
Definition Signpost.h:507
#define O2_SIGNPOST_EVENT_EMIT(log, id, name, format,...)
Definition Signpost.h:523
StringRef key
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
ConcreteParserVariants< PageSize, BOUNDS_CHECKS > create(T const *buffer, size_t size)
create a raw parser depending on version of RAWDataHeader found at beginning of data
Definition RawParser.h:378
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
static std::vector< LoadablePlugin > parsePluginSpecString(char const *str)
Parse a comma separated list of <library>:<plugin-name> plugin declarations.
virtual RootObjectReadingCapability * create()=0
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))