22#include "../src/AODInputFile.h"
23#include "../src/NativeAOD.h"
28#include <arrow/buffer.h>
29#include <arrow/dataset/file_base.h>
30#include <arrow/io/memory.h>
31#include <arrow/ipc/reader.h>
32#include <arrow/ipc/writer.h>
33#include <arrow/record_batch.h>
35#include <sys/resource.h>
48T orThrow(arrow::Result<T>
result, std::string
const& what)
51 throw std::runtime_error(what +
": " +
result.status().ToString());
53 return std::move(
result).ValueUnsafe();
57 std::shared_ptr<arrow::Buffer>
bytes;
58 std::string capability;
66 for (
auto& capability : factory.capabilities) {
67 if (!capability.getHandle(fs, capability.lfn2objectPath(
path))) {
70 auto format = capability.factory().format();
72 std::vector<std::shared_ptr<arrow::Field>>
fields;
74 if (!field->name().ends_with(
"_size")) {
80 auto options = std::make_shared<arrow::dataset::ScanOptions>();
82 auto batch = orThrow(orThrow(
format->ScanBatchesAsync(options, fragment),
"scan")().result(),
"scan");
84 auto mock = std::make_shared<arrow::io::MockOutputStream>();
85 (
void)arrow::ipc::MakeStreamWriter(mock.get(), batch->schema()).ValueOrDie()->WriteRecordBatch(*batch);
86 std::shared_ptr<arrow::ResizableBuffer>
buffer = arrow::AllocateResizableBuffer(0, 64).ValueOrDie();
87 if (!
buffer->Reserve(mock->Tell().ValueOrDie()).ok()) {
88 throw std::runtime_error(
"cannot reserve " +
path);
90 auto stream = capability.factory().deferredOutputStreamer(fragment,
buffer);
91 auto writer = arrow::ipc::MakeStreamWriter(
stream, batch->schema()).ValueOrDie();
92 auto status = writer->WriteRecordBatch(*batch);
94 status = writer->Close();
100 throw std::runtime_error(
path +
": " + status.ToString());
102 return {
buffer, capability.name};
104 throw std::runtime_error(
"no capability reads " +
path);
107std::shared_ptr<arrow::RecordBatch>
decode(std::shared_ptr<arrow::Buffer>
const&
bytes)
109 auto reader = arrow::ipc::RecordBatchStreamReader::Open(std::make_shared<arrow::io::BufferReader>(
bytes)).ValueOrDie();
110 std::shared_ptr<arrow::RecordBatch> batch;
111 (
void)reader->ReadNext(&batch);
115std::string describeDifference(Serialised
const& root, Serialised
const& native)
120 return "one of the two streams has no batch";
122 if (!
r->schema()->Equals(*
n->schema())) {
123 return "schemas differ:\n root: " +
r->schema()->ToString() +
"\n native: " +
n->schema()->ToString();
125 if (
r->num_rows() !=
n->num_rows()) {
128 for (
int i = 0;
i <
r->num_columns(); ++
i) {
129 if (!
r->column(
i)->Equals(
n->column(
i))) {
130 return "column " +
r->schema()->field(
i)->name() +
" differs";
136double cpuSeconds(timeval
const& tv) {
return tv.tv_sec + tv.tv_usec * 1
e-6; }
141 static const std::regex dfRegex{
"DF_[0-9]+"};
142 std::vector<std::string> dfs;
143 for (
auto&
key :
file.topLevelKeys()) {
144 if (std::regex_match(
key.name, dfRegex) && (maxDFs < 0 || (
int)dfs.size() < maxDFs) && std::ranges::find(dfs,
key.name) == dfs.end()) {
145 dfs.push_back(
key.name);
158 std::vector<std::string> files;
159 for (
int i = 1;
i < argc; ++
i) {
160 if (std::strcmp(argv[
i],
"--threads") == 0 &&
i + 1 < argc) {
161 nativeOptions.
threads = std::stoi(argv[++
i]);
162 }
else if (std::strcmp(argv[
i],
"--pread") == 0) {
163 nativeOptions.
localIO = o2::aod::native::Options::LocalIO::PRead;
164 }
else if (std::strcmp(argv[
i],
"--prefetch") == 0 &&
i + 1 < argc) {
166 }
else if (std::strcmp(argv[
i],
"--max-dfs") == 0 &&
i + 1 < argc) {
167 maxDFs = std::stoi(argv[++
i]);
168 }
else if (std::strcmp(argv[
i],
"--bench") == 0 &&
i + 1 < argc) {
171 files.push_back(argv[
i]);
174 if (files.empty() || (!bench.empty() && bench !=
"root" && bench !=
"native")) {
175 std::fprintf(stderr,
"usage: %s [--threads N] [--pread] [--prefetch N] [--max-dfs N] [--bench root|native] <file>...\n", argv[0]);
180 std::vector<LoadablePlugin> plugins;
181 for (
auto spec : {
"O2FrameworkAnalysisNativeAODSupport:NativeAODObjectReadingCapability",
"O2Framework:TTreeObjectReadingCapability"}) {
183 plugins.push_back(plugin);
186 PluginManager::loadFromPlugin<RootObjectReadingCapability, RootObjectReadingCapabilityPlugin>(plugins, factory.
capabilities);
187 for (
auto&
name : files) {
188 if (
name.starts_with(
"alien://") && !gGrid) {
189 TGrid::Connect(
"alien://");
194 if (!bench.empty()) {
195 for (
auto&
name : files) {
196 auto start = std::chrono::steady_clock::now();
198 getrusage(RUSAGE_SELF, &before);
199 std::shared_ptr<AODInputFile>
file;
200 if (bench ==
"root") {
205 size_t trees = 0,
bytes = 0;
206 auto order = dataFramesOf(*
file, maxDFs);
207 file->setReadOrder(order);
208 int dfs = order.size();
209 for (
auto& df : order) {
210 for (
auto&
tree :
file->keysIn(df)) {
211 bytes += serialise(factory,
file->filesystem(), df +
"/" +
tree).bytes->size();
215 auto bytesRead =
file->bytesRead();
216 auto readCalls =
file->readCalls();
218 double wall = std::chrono::duration<double>(std::chrono::steady_clock::now() -
start).count();
220 getrusage(RUSAGE_SELF, &after);
221 double user = cpuSeconds(after.ru_utime) - cpuSeconds(before.ru_utime);
222 double sys = cpuSeconds(after.ru_stime) - cpuSeconds(before.ru_stime);
224 double maxRssMiB = after.ru_maxrss / 1048576.;
226 double maxRssMiB = after.ru_maxrss / 1024.;
228 std::printf(
"%s %s: %d DFs, %zu trees, %.1f MB out, read %.1f MB in %llu calls; wall %.2f s, user %.2f s, sys %.2f s, %.0f MB/s out, max RSS %.0f MiB\n",
229 bench.c_str(),
name.c_str(), dfs, trees,
bytes / 1e6, bytesRead / 1e6, (
unsigned long long)readCalls,
230 wall, user, sys,
bytes / 1e6 / wall, maxRssMiB);
234 for (
auto&
file : files) {
240 std::printf(
"FAIL %s: ROOT cannot open it\n",
name.c_str());
244 std::shared_ptr<AODInputFile> native;
248 std::printf(
"FAIL %s: native reader cannot open it: %s\n",
name.c_str(),
e.what());
252 if (root->parentFiles() != native->parentFiles() || root->metaData() != native->metaData()) {
253 std::printf(
"FAIL %s: parentFiles or metaData differ\n",
name.c_str());
256 size_t trees = 0, rootBytes = 0, nativeBytes = 0;
257 auto order = dataFramesOf(*root, maxDFs);
258 native->setReadOrder(order);
259 int dfs = order.size();
260 for (
auto& df : order) {
261 auto nativeKeys = native->keysIn(df);
262 if (nativeKeys != root->keysIn(df)) {
263 std::printf(
"FAIL %s: keys of %s differ\n",
name.c_str(), df.c_str());
267 for (
auto&
tree : nativeKeys) {
270 auto r = serialise(factory, root->filesystem(),
path);
271 auto n = serialise(factory, native->filesystem(),
path);
273 rootBytes +=
r.bytes->size();
274 nativeBytes +=
n.bytes->size();
275 if (
r.capability !=
"ttree" ||
n.capability !=
"native-ttree") {
276 std::printf(
"FAIL %s %s: read by %s and %s\n",
name.c_str(),
path.c_str(),
r.capability.c_str(),
n.capability.c_str());
278 }
else if (!
r.bytes->Equals(*
n.bytes)) {
279 std::printf(
"FAIL %s %s: %s\n",
name.c_str(),
path.c_str(), describeDifference(
r,
n).c_str());
282 }
catch (std::exception
const&
e) {
283 std::printf(
"FAIL %s %s: %s\n",
name.c_str(),
path.c_str(),
e.what());
288 std::printf(
"%s: %d DFs, %zu trees, %zu / %zu bytes serialised (root / native), native read %llu bytes in %llu calls\n",
289 name.c_str(), dfs, trees, rootBytes, nativeBytes, (
unsigned long long)native->bytesRead(), (
unsigned long long)native->readCalls());
291 std::printf(
"%s: %d failure(s)\n", failures ?
"FAILED" :
"OK", failures);
292 return failures ? 1 : 0;
std::vector< std::shared_ptr< arrow::Field > > fields
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 e
GLuint const GLchar * name
GLsizei GLsizei GLchar * source
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLsizei const GLchar *const * path
GLint GLint GLsizei GLint GLenum format
std::shared_ptr< arrow::Schema > datasetSchema(std::shared_ptr< arrow::Schema > const &physical)
The physical schema without the *_size fields, as DataInputDirector derives it.
std::shared_ptr< arrow::Schema > physicalSchema(TreeInfo const &tree)
Defining ITS Vertex explicitly as messageable.
std::shared_ptr< AODInputFile > openNativeAOD(std::string const &filename, RootObjectReadingFactory &factory, o2::aod::native::Options const &options)
std::string to_string(gsl::span< T, Size > span)
std::vector< std::string > split(const std::string &str, char delimiter=',')
static std::vector< LoadablePlugin > parsePluginSpecString(char const *str)
Parse a comma separated list of <library>:<plugin-name> plugin declarations.
std::vector< RootObjectReadingCapability > capabilities
coder decode(ctfImage, triggersD, clustersD)
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))