|
| 1 | +/// \file |
| 2 | +/// \ingroup tutorial_multicore |
| 3 | +/// |
| 4 | +/// Fill an Ntuple in distinct workers, and write the output to a file. |
| 5 | +/// This tutorial illustrates the basics of how it's possible with ROOT |
| 6 | +/// to write simultaneously to a single output file using TBufferMerger. |
| 7 | +/// |
| 8 | +/// \macro_code |
| 9 | +/// |
| 10 | +/// \author Guilherme Amadio |
| 11 | +/// \date May 2017 |
| 12 | + |
| 13 | +#include <ROOT/TBufferMerger.hxx> |
| 14 | + |
| 15 | +using ROOT::Experimental::TBufferMerger; |
| 16 | +using ROOT::Experimental::TBufferMergerFile; |
| 17 | + |
| 18 | +#include <random> |
| 19 | +#include <thread> |
| 20 | + |
| 21 | +// A simple function to fill the ntuple with random values |
| 22 | +void fill(TNtuple &ntuple, size_t n) |
| 23 | +{ |
| 24 | + std::random_device rd; |
| 25 | + std::default_random_engine rng(rd()); |
| 26 | + std::normal_distribution<double> dist(0.0, 1.0); |
| 27 | + |
| 28 | + auto gaussian_random = [&]() { return dist(rng); }; |
| 29 | + |
| 30 | + for (auto i : ROOT::TSeqI(n)) ntuple.Fill(gaussian_random()); |
| 31 | +} |
| 32 | + |
| 33 | +void mt103_fillNtuples() |
| 34 | +{ |
| 35 | + // Avoid unnecessary output |
| 36 | + gROOT->SetBatch(); |
| 37 | + |
| 38 | + // Make ROOT thread-safe |
| 39 | + ROOT::EnableThreadSafety(); |
| 40 | + |
| 41 | + // Total number of events |
| 42 | + const size_t nEvents = 65535; |
| 43 | + |
| 44 | + // Match number of threads to what the hardware can do |
| 45 | + const size_t nWorkers = std::thread::hardware_concurrency(); |
| 46 | + |
| 47 | + // Split work in equal parts |
| 48 | + const size_t nEventsPerWorker = nEvents / nWorkers; |
| 49 | + |
| 50 | + // Create the TBufferMerger |
| 51 | + TBufferMerger merger("mp103_fillNtuple.root"); |
| 52 | + |
| 53 | + // Define what each worker will do |
| 54 | + auto work_function = [&]() { |
| 55 | + auto f = merger.GetFile(); |
| 56 | + TNtuple ntrand("ntrand", "Random Numbers", "r"); |
| 57 | + fill(ntrand, nEventsPerWorker); |
| 58 | + ntrand.Write(); |
| 59 | + f->Write(); |
| 60 | + }; |
| 61 | + |
| 62 | + // Create worker threads |
| 63 | + std::vector<std::thread> workers; |
| 64 | + |
| 65 | + for (auto i : ROOT::TSeqI(nWorkers)) workers.emplace_back(work_function); |
| 66 | + |
| 67 | + // Make sure workers are done |
| 68 | + for (auto &&worker : workers) worker.join(); |
| 69 | +} |
0 commit comments