File indexing completed on 2024-04-06 12:13:01
0001 #include "TFile.h"
0002 #include "TTree.h"
0003 #include "TBranch.h"
0004 #include "TClass.h"
0005 #include "TThread.h"
0006 #include "TVirtualStreamerInfo.h"
0007
0008 #include "TList.h"
0009 #include "TMap.h"
0010 #include "TObjString.h"
0011 #include "TH1F.h"
0012
0013 #include "FWCore/FWLite/interface/FWLiteEnabler.h"
0014
0015 #include <memory>
0016 #include <cassert>
0017 #include <iostream>
0018 #include <thread>
0019 #include <atomic>
0020
0021 std::atomic<bool> waitToStart{true};
0022
0023 void printHelp(const char* iName, int iDefaultNThreads) {
0024 std::cout << iName << " [number of threads] [filename] [gDebug value]\n\n"
0025 << "[number of threads] number of threads to use in test\n"
0026 << "[filename] name of CMSSW file to read\n"
0027 << "[gDebug value] value of gDebug to pass to ROOT (gDebug=1 is useful)\n"
0028 << "If no arguments are given " << iDefaultNThreads
0029 << " threads will be used and a dummy file will be created." << std::endl;
0030 }
0031
0032 const std::string kDefaultFileName("read_test_dummy.root");
0033
0034 std::tuple<int, std::string, int> parseOptions(int argc, char** argv) {
0035 constexpr int kDefaultNThreads = 4;
0036 int kDefaultgDebug = gDebug;
0037 int nThreads = kDefaultNThreads;
0038 int newGDebug = kDefaultgDebug;
0039 std::string fileName(kDefaultFileName);
0040 if (argc >= 2) {
0041 if (strcmp("-h", argv[1]) == 0) {
0042 printHelp(argv[0], kDefaultNThreads);
0043 exit(0);
0044 }
0045
0046 nThreads = atoi(argv[1]);
0047 }
0048 if (argc >= 3) {
0049 fileName = argv[2];
0050 }
0051 if (argc == 4) {
0052 newGDebug = atoi(argv[3]);
0053 }
0054
0055 if (argc > 4) {
0056 printHelp(argv[0], kDefaultNThreads);
0057 exit(1);
0058 }
0059 return std::make_tuple(nThreads, fileName, newGDebug);
0060 }
0061
0062 void createDummyFile() {
0063 auto theList = new TList();
0064
0065 for (unsigned int i = 0; i < 10; ++i) {
0066 theList->Add(new TList());
0067 theList->Add(new TMap());
0068 theList->Add(new TObjString());
0069 theList->Add(new TH1F());
0070 theList->Add(new TH1D());
0071 }
0072
0073 TFile f(kDefaultFileName.c_str(), "RECREATE", "test");
0074
0075 auto listTree = new TTree("Events", "TheList");
0076 listTree->Branch("theList", "TList", &theList);
0077
0078 for (unsigned int i = 0; i < 100; ++i) {
0079 listTree->Fill();
0080 }
0081 f.Write();
0082 f.Close();
0083 }
0084
0085 int main(int argc, char** argv) {
0086 auto options = parseOptions(argc, argv);
0087
0088 const int kNThreads = std::get<0>(options);
0089
0090 auto const kFileName = std::get<1>(options);
0091
0092 gDebug = std::get<2>(options);
0093
0094 FWLiteEnabler::enable();
0095
0096
0097 TThread::Initialize();
0098
0099 TObject::SetObjectStat(false);
0100
0101 TVirtualStreamerInfo::Optimize(false);
0102
0103 if (kFileName == kDefaultFileName) {
0104 createDummyFile();
0105 }
0106
0107 std::vector<std::shared_ptr<std::thread>> threads;
0108 threads.reserve(kNThreads);
0109
0110 for (int i = 0; i < kNThreads; ++i) {
0111 threads.push_back(std::make_shared<std::thread>(std::thread([&kFileName]() {
0112 static thread_local TThread s_thread_guard;
0113 while (waitToStart)
0114 ;
0115 std::unique_ptr<TFile> f{TFile::Open(kFileName.c_str())};
0116 assert(f.get());
0117
0118 TTree* eventTree = dynamic_cast<TTree*>(f.get()->Get("Events"));
0119 assert(eventTree);
0120
0121 for (Long64_t i = 0, iEnd = eventTree->GetEntries(); i != iEnd; ++i) {
0122 eventTree->GetEntry(i, 1);
0123 }
0124
0125 f.get()->Close();
0126 })));
0127 }
0128 waitToStart = false;
0129 for (auto& t : threads) {
0130 t->join();
0131 }
0132
0133 return 0;
0134 }