Project
Loading...
Searching...
No Matches
Plugin.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#include "Framework/Plugins.h"
17#include "Framework/Signpost.h"
19#include "AODWriterHelpers.h"
20#include <TFile.h>
21#include <TMap.h>
22#include <TGrid.h>
23#include <TObjString.h>
24#include <TString.h>
25#include <fmt/format.h>
26#include <memory>
27
28O2_DECLARE_DYNAMIC_LOG(analysis_support);
29
36
43
50
51using namespace o2::framework;
54 {
56 .name = "analysis-run-summary",
57 .init = [](ServiceRegistryRef ref, DeviceState&, fair::mq::ProgOptions&) -> ServiceHandle {
58 return ServiceHandle{TypeIdHelpers::uniqueId<RunSummary>(), nullptr, ServiceKind::Serial, "analysis-run-summary"};
59 },
60 .summaryHandling = [](ServiceMetricsInfo const& info) {
61 LOGP(info, "## Analysis Run Summary ##");
63 for (size_t mi = 0; mi < info.deviceMetricsInfos.size(); ++mi) {
64 DeviceMetricsInfo &metrics = info.deviceMetricsInfos[mi];
65 for (size_t li = 0; li < metrics.metricLabels.size(); ++li) {
66 MetricLabel const&label = metrics.metricLabels[li];
67 if (strcmp(label.label, "aod-file-read-info") != 0) {
68 continue;
69 }
70 MetricInfo const&metric = metrics.metrics[li];
71 auto &files = metrics.stringMetrics[metric.storeIdx];
72 if (metric.filledMetrics) {
73 LOGP(info, "### Files read stats ###");
74 }
75 for (size_t fi = 0; fi < metric.filledMetrics; ++fi) {
76 LOGP(info, "{}", files[fi % files.size()].data);
77 }
78 }
79 for (size_t li = 0; li < metrics.metricLabels.size(); ++li) {
80 MetricLabel const&label = metrics.metricLabels[li];
81 if (strcmp(label.label, "aod-file-open-info") != 0) {
82 continue;
83 }
84 MetricInfo const&metric = metrics.metrics[li];
85 auto &files = metrics.stringMetrics[metric.storeIdx];
86 if (metric.filledMetrics) {
87 LOGP(info, "### Files opened stats ###");
88 }
89 std::string lastFileRead;
90 for (size_t fi = 0; fi < metric.filledMetrics; ++fi) {
91 lastFileRead = files[fi % files.size()].data;
92 }
93 if (lastFileRead.empty() == false) {
94 LOGP(info, "Last file opened: {}", lastFileRead);
95 }
96 }
97 } },
98 .kind = ServiceKind::Serial};
99 }
100};
101
102std::vector<std::string> getListOfTables(std::unique_ptr<TFile>& f)
103{
104 std::vector<std::string> r;
105 TList* keyList = f->GetListOfKeys();
106 // We should handle two cases, one where the list of tables in a TDirectory,
107 // the other one where the dataframe number is just a prefix
108 std::string first = "";
109
110 for (auto key : *keyList) {
111 if (!std::string_view(key->GetName()).starts_with("DF_") && !std::string_view(key->GetName()).starts_with("/DF_")) {
112 continue;
113 }
114 auto* d = (TDirectory*)f->GetObjectChecked(key->GetName(), TClass::GetClass("TDirectory"));
115 // Objects are in a folder, list it.
116 if (d) {
117 TList* branchList = d->GetListOfKeys();
118 for (auto b : *branchList) {
119 r.emplace_back(b->GetName());
120 }
121 break;
122 }
123
124#if __has_include(<ROOT/RFieldBase.hxx>)
125 void* v = f->GetObjectChecked(key->GetName(), TClass::GetClass("ROOT::RNTuple"));
126#else
127 void* v = f->GetObjectChecked(key->GetName(), TClass::GetClass("ROOT::Experimental::RNTuple"));
128#endif
129 if (v) {
130 std::string s = key->GetName();
131 size_t pos = s.find('-');
132 // Check if '-' is found
133 // Skip metaData and parentFiles
134 if (pos == std::string::npos) {
135 continue;
136 }
137 std::string t = s.substr(pos + 1);
138 // If we find a duplicate table name, it means we are in the next DF and we can stop.
139 if (t == first) {
140 break;
141 }
142 if (first.empty()) {
143 first = t;
144 }
145 // Create a new string starting after the '-'
146 r.emplace_back(t);
147 }
148 }
149 return r;
150}
151
152auto readMetadata(std::unique_ptr<TFile>& currentFile) -> std::vector<ConfigParamSpec>
153{
154 // Get the metadata, if any
155 auto m = (TMap*)currentFile->Get("metaData");
156 if (!m) {
157 return {};
158 }
159 std::vector<ConfigParamSpec> results;
160 auto it = m->MakeIterator();
161
162 // Serialise metadata into a ; separated string with : separating key and value
163 bool first = true;
164 while (auto obj = it->Next()) {
165 if (first) {
166 LOGP(info, "Metadata for file \"{}\":", currentFile->GetName());
167 first = false;
168 }
169 auto objString = (TObjString*)m->GetValue(obj);
170 LOGP(info, "- {}: {}", obj->GetName(), objString->String().Data());
171 std::string key = "aod-metadata-" + std::string(obj->GetName());
172 char const* value = strdup(objString->String());
173 results.push_back(ConfigParamSpec{key, VariantType::String, value, {"Metadata in AOD"}});
174 }
175
176 return results;
177}
178
181 {
182 return new ConfigDiscovery{
183 .init = []() {},
184 .discover = [](ConfigParamRegistry& registry, int argc, char** argv) -> std::vector<ConfigParamSpec> {
185 auto filename = registry.get<std::string>("aod-file");
186 if (filename.empty()) {
187 return {};
188 }
189 if (filename.at(0) == '@') {
190 filename.erase(0, 1);
191 // read the text file and set filename to the contents of the first line
192 std::ifstream file(filename);
193 if (!file.is_open()) {
194 LOGP(fatal, "Couldn't open file \"{}\"!", filename);
195 }
196 std::getline(file, filename);
197 file.close();
198 }
199 if (filename.rfind("alien://", 0) == 0 && !gGrid) {
200 TGrid::Connect("alien://");
201 }
202 LOGP(info, "Loading metadata from file {} in PID {}", filename, getpid());
203 std::unique_ptr<TFile> currentFile{TFile::Open(filename.c_str())};
204 if (currentFile.get() == nullptr) {
205 LOGP(fatal, "Couldn't open file \"{}\"!", filename);
206 }
207 std::vector<ConfigParamSpec> results = readMetadata(currentFile);
208 const bool metaDataEmpty = results.empty();
209 auto tables = getListOfTables(currentFile);
210 if (tables.empty() == false) {
211 results.push_back(ConfigParamSpec{"aod-metadata-tables", VariantType::ArrayString, tables, {"Tables in first AOD"}});
212 }
213
214 // Found metadata already in the main file.
215 if (!metaDataEmpty) {
216 results.push_back(ConfigParamSpec{"aod-metadata-source", VariantType::String, filename, {"File from which the metadata was extracted."}});
217 return results;
218 }
219
220 if (!registry.isSet("aod-parent-access-level") || registry.get<int>("aod-parent-access-level") == 0) {
221 LOGP(info, "No metadata found in file \"{}\" and parent level 0 prevents further lookup.", filename);
222 results.push_back(ConfigParamSpec{"aod-metadata-disable", VariantType::String, "1", {"Metadata not found in AOD"}});
223 return results;
224 }
225
226 // Lets try in parent file.
227 auto parentFiles = (TMap*)currentFile->Get("parentFiles");
228 if (!parentFiles) {
229 LOGP(info, "No metadata found in file \"{}\"", filename);
230 results.push_back(ConfigParamSpec{"aod-metadata-disable", VariantType::String, "1", {"Metadata not found in AOD"}});
231 return results;
232 }
233 LOGP(info, "No metadata found in file \"{}\", checking in its parents.", filename);
234 for (auto* p : *parentFiles) {
235 std::string parentFilename = ((TPair*)p)->Value()->GetName();
236 // Do the replacement. Notice this will require changing aod-parent-base-path-replacement to be
237 // a workflow option (because the metadata itself is potentially changing the topology).
238 if (registry.isSet("aod-parent-base-path-replacement")) {
239 auto parentFileReplacement = registry.get<std::string>("aod-parent-base-path-replacement");
240 auto pos = parentFileReplacement.find(';');
241 if (pos == std::string::npos) {
242 throw std::runtime_error(fmt::format("Invalid syntax in aod-parent-base-path-replacement: \"{}\"", parentFileReplacement.c_str()));
243 }
244 auto from = parentFileReplacement.substr(0, pos);
245 auto to = parentFileReplacement.substr(pos + 1);
246 pos = parentFilename.find(from);
247 if (pos != std::string::npos) {
248 parentFilename.replace(pos, from.length(), to);
249 }
250 }
251
252 if (parentFilename.starts_with("alien://") && !gGrid) {
253 TGrid::Connect("alien://");
254 }
255
256 std::unique_ptr<TFile> parentFile{TFile::Open(parentFilename.c_str())};
257 if (parentFile.get() == nullptr) {
258 LOGP(fatal, "Couldn't open derived file \"{}\"!", parentFilename);
259 }
260 results = readMetadata(parentFile);
261 // Found metadata already in the main file.
262 if (!results.empty()) {
263 auto tables = getListOfTables(parentFile);
264 if (tables.empty() == false) {
265 results.push_back(ConfigParamSpec{"aod-metadata-tables", VariantType::ArrayString, tables, {"Tables in first AOD"}});
266 }
267 results.push_back(ConfigParamSpec{"aod-metadata-source", VariantType::String, filename, {"File from which the metadata was extracted."}});
268 return results;
269 }
270 LOGP(info, "No metadata found in file \"{}\" nor in its parent file \"{}\"", filename, parentFilename);
271 break;
272 }
273 results.push_back(ConfigParamSpec{"aod-metadata-disable", VariantType::String, "1", {"Metadata not found in AOD"}});
274 return results;
275 }};
276 }
277};
278
std::vector< std::string > getListOfTables(std::unique_ptr< TFile > &f)
Definition Plugin.cxx:102
auto readMetadata(std::unique_ptr< TFile > &currentFile) -> std::vector< ConfigParamSpec >
Definition Plugin.cxx:152
#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
uint16_t pos
Definition RawData.h:3
#define O2_DECLARE_DYNAMIC_LOG(name)
Definition Signpost.h:483
StringRef key
const GLfloat * m
Definition glcorearb.h:4066
const GLdouble * v
Definition glcorearb.h:832
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
Definition glcorearb.h:5500
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLboolean r
Definition glcorearb.h:1233
GLint ref
Definition glcorearb.h:291
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::string filename()
ConfigDiscovery * create() override
Definition Plugin.cxx:180
o2::framework::AlgorithmSpec create(o2::framework::ConfigContext const &config) override
Definition Plugin.cxx:31
o2::framework::AlgorithmSpec create(o2::framework::ConfigContext const &config) override
Definition Plugin.cxx:38
o2::framework::AlgorithmSpec create(o2::framework::ConfigContext const &config) override
Definition Plugin.cxx:45
o2::framework::ServiceSpec * create() final
Definition Plugin.cxx:53
Helper class for an algorithm which is loaded as a plugin.
Running state information of a given device.
Definition DeviceState.h:34
std::string name
Name of the service.
static AlgorithmSpec rootFileReaderCallback(ConfigContext const &context)
static AlgorithmSpec getOutputObjHistWriter(ConfigContext const &context)
static AlgorithmSpec getOutputTTreeWriter(ConfigContext const &context)