Logo ROOT   6.10/09
Reference Guide
TBufferMerger.cxx
Go to the documentation of this file.
1 #include "ROOT/TBufferMerger.hxx"
2 
3 #include "TFile.h"
4 #include "TROOT.h"
5 #include "TTree.h"
6 
7 #include <memory>
8 #include <thread>
9 #include <sys/stat.h>
10 
11 #include "gtest/gtest.h"
12 
13 using namespace ROOT::Experimental;
14 
15 static void Fill(TTree *tree, int init, int count)
16 {
17  int n = 0;
18 
19  tree->Branch("n", &n, "n/I");
20 
21  for (int i = 0; i < count; ++i) {
22  n = init + i;
23  tree->Fill();
24  }
25 }
26 
27 static bool FileExists(const char *name)
28 {
29  struct stat buffer;
30  return stat(name, &buffer) == 0;
31 }
32 
33 TEST(TBufferMerger, CreateAndDestroy)
34 {
35  TBufferMerger merger("tbuffermerger_create.root");
36 }
37 
38 TEST(TBufferMerger, CreateAndDestroyWithAttachedFiles)
39 {
41 
42  {
43  TBufferMerger merger("tbuffermerger_create.root");
44 
45  auto f1 = merger.GetFile();
46  auto f2 = merger.GetFile();
47  auto f3 = merger.GetFile();
48  }
49 
50  EXPECT_TRUE(FileExists("tbuffermerger_create.root"));
51 }
52 
53 TEST(TBufferMerger, SequentialTreeFill)
54 {
55  int nevents = 1024;
56 
58 
59  {
60  TBufferMerger merger("tbuffermerger_sequential.root");
61 
62  auto myfile = merger.GetFile();
63  auto mytree = new TTree("mytree", "mytree");
64 
65  // The resetting of the kCleanup bit below is necessary to avoid leaving
66  // the management of this object to ROOT, which leads to a race condition
67  // that may cause a crash once all threads are finished and the final
68  // merge is happening
69  mytree->ResetBit(kMustCleanup);
70 
71  Fill(mytree, 0, nevents);
72  myfile->Write();
73  }
74 
75  EXPECT_TRUE(FileExists("tbuffermerger_sequential.root"));
76 }
77 
78 TEST(TBufferMerger, ParallelTreeFill)
79 {
80  int nthreads = 4;
81  int nevents = 256;
82 
84 
85  {
86  TBufferMerger merger("tbuffermerger_parallel.root");
87  std::vector<std::thread> threads;
88  for (int i = 0; i < nthreads; ++i) {
89  threads.emplace_back([=, &merger]() {
90  auto myfile = merger.GetFile();
91  auto mytree = new TTree("mytree", "mytree");
92 
93  // The resetting of the kCleanup bit below is necessary to avoid leaving
94  // the management of this object to ROOT, which leads to a race condition
95  // that may cause a crash once all threads are finished and the final
96  // merge is happening
97  mytree->ResetBit(kMustCleanup);
98 
99  Fill(mytree, i * nevents, nevents);
100  myfile->Write();
101  });
102  }
103 
104  for (auto &&t : threads) t.join();
105  }
106 
107  EXPECT_TRUE(FileExists("tbuffermerger_parallel.root"));
108 }
109 
110 TEST(TBufferMerger, CheckTreeFillResults)
111 {
112  int sum_s, sum_p;
113 
114  ASSERT_TRUE(FileExists("tbuffermerger_sequential.root"));
115 
116  { // sum of all branch values in sequential mode
117  TFile f("tbuffermerger_sequential.root");
118  auto t = (TTree *)f.Get("mytree");
119 
120  int n, sum = 0;
121  int nentries = (int)t->GetEntries();
122 
123  t->SetBranchAddress("n", &n);
124 
125  for (int i = 0; i < nentries; ++i) {
126  t->GetEntry(i);
127  sum += n;
128  }
129 
130  sum_s = sum;
131  }
132 
133  ASSERT_TRUE(FileExists("tbuffermerger_parallel.root"));
134 
135  { // sum of all branch values in parallel mode
136  TFile f("tbuffermerger_parallel.root");
137  auto t = (TTree *)f.Get("mytree");
138 
139  int n, sum = 0;
140  int nentries = (int)t->GetEntries();
141 
142  t->SetBranchAddress("n", &n);
143 
144  for (int i = 0; i < nentries; ++i) {
145  t->GetEntry(i);
146  sum += n;
147  }
148 
149  sum_p = sum;
150  }
151 
152  // Note: 0 + 1 + ... + 1024 = 523776
153 
154  EXPECT_EQ(523776, sum_s);
155  EXPECT_EQ(523776, sum_p);
156 }
static long int sum(long int i)
Definition: Factory.cxx:2162
std::shared_ptr< ToContentType_t< T > > Get(const std::string &name)
Get the object for a key.
Definition: TDirectory.hxx:149
TBufferMerger is a class to facilitate writing data in parallel from multiple threads, while writing to a single output file.
static bool FileExists(const char *name)
double f(double x)
void EnableThreadSafety()
Enables the global mutex to make ROOT thread safe/aware.
Definition: TROOT.cxx:498
static Int_t init()
int nentries
Definition: THbookFile.cxx:89
std::shared_ptr< TBufferMergerFile > GetFile()
Returns a TBufferMergerFile to which data can be written.
double f2(const double *x)
TF1 * f1
Definition: legend1.C:11
Definition: tree.py:1
A ROOT file.
Definition: TFile.hxx:44
TEST(TBufferMerger, CreateAndDestroy)
const Int_t n
Definition: legend1.C:16
static void Fill(TTree *tree, int init, int count)