CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
fastHadd.cc
Go to the documentation of this file.
1 
80 #include <sys/types.h>
81 #include <sys/stat.h>
82 #include <fcntl.h>
83 #include <vector>
84 #include <set>
85 #include <string>
86 #include <iostream>
87 #include <memory>
89 #include <google/protobuf/io/coded_stream.h>
90 #include <google/protobuf/io/gzip_stream.h>
91 #include <google/protobuf/io/zero_copy_stream_impl.h>
92 #include <TROOT.h>
93 #include <TFile.h>
94 #include <TBufferFile.h>
95 #include <TObject.h>
96 #include <TObjString.h>
97 #include <TH1.h>
98 #include <TKey.h>
99 
100 #define DEBUG(x, msg) if (debug >= x) std::cout << "DEBUG: " << msg << std::flush
101 
102 int debug = 0;
103 
104 static bool lessThanMME(const std::string &lhs_dirname,
105  const std::string &lhs_objname,
106  const std::string &rhs_dirname,
107  const std::string &rhs_objname) {
108  int diff = lhs_dirname.compare(rhs_dirname);
109  return (diff < 0 ? true
110  : diff == 0 ? lhs_objname < rhs_objname : false);
111 };
112 
113 struct MicroME {
115  const std::string * dir,
116  const std::string * obj,
117  uint32_t flags = 0)
118  :fullname(full), dirname(dir), objname(obj), flags(flags) {}
122  mutable TObject * obj;
123 
124  uint32_t flags;
125 
126  bool operator<(const MicroME &rhs) const {
127  return lessThanMME(*this->dirname,
128  *this->objname,
129  *rhs.dirname,
130  *rhs.objname);
131  };
132 
133  void add(TObject *obj_to_add) const {
134  DEBUG(1, "Merging: " << obj->GetName() <<
135  " << " << obj_to_add->GetName() << std::endl);
136 
137  if (dynamic_cast<TH1 *>(obj) && dynamic_cast<TH1 *>(obj_to_add)) {
138  dynamic_cast<TH1 *>(obj)->Add(dynamic_cast<TH1 *>(obj_to_add));
139  } else if (dynamic_cast<TObjString *>(obj) && dynamic_cast<TObjString *>(obj_to_add)) {
140 
141 
142  } else {
143  DEBUG(1, "Cannot merge (different types): " << obj->GetName() <<
144  " << " << obj_to_add->GetName() << std::endl);
145  }
146  };
147 };
148 
149 enum TaskType {
154 };
155 
156 enum ErrType {
159 };
160 
161 using google::protobuf::io::FileInputStream;
162 using google::protobuf::io::FileOutputStream;
163 using google::protobuf::io::GzipInputStream;
164 using google::protobuf::io::GzipOutputStream;
165 using google::protobuf::io::CodedInputStream;
166 using google::protobuf::io::ArrayInputStream;
167 
171 inline TObject * extractNextObject(TBufferFile &buf) {
172  if (buf.Length() == buf.BufferSize())
173  return 0;
174  buf.InitMap();
175  return reinterpret_cast<TObject *>(buf.ReadObjectAny(0));
176 }
177 
179  std::string &dirname,
180  std::string &objname,
181  TObject ** obj) {
182 
183  size_t slash = h.full_pathname().rfind('/');
184  size_t dirpos = (slash == std::string::npos ? 0 : slash);
185  size_t namepos = (slash == std::string::npos ? 0 : slash+1);
186  dirname.assign(h.full_pathname(), 0, dirpos);
187  objname.assign(h.full_pathname(), namepos, std::string::npos);
188  TBufferFile buf(TBufferFile::kRead, h.size(),
189  (void*)h.streamed_histo().data(),
190  kFALSE);
191  buf.Reset();
192  *obj = extractNextObject(buf);
193  if (!*obj) {
194  std::cerr << "Error reading element: " << h.full_pathname() << std::endl;
195  }
196 }
197 
198 void writeMessage(const dqmstorepb::ROOTFilePB &dqmstore_output_msg,
199  const std::string &output_filename) {
200 
201  DEBUG(1, "Writing file" << std::endl);
202 
203  int out_fd = ::open(output_filename.c_str(),
204  O_WRONLY | O_CREAT | O_TRUNC,
205  S_IRUSR | S_IWUSR |
206  S_IRGRP | S_IWGRP |
207  S_IROTH);
208 
209  FileOutputStream out_stream(out_fd);
211  options.format = GzipOutputStream::GZIP;
212  options.compression_level = 2;
213  GzipOutputStream gzip_stream(&out_stream,
214  options);
215  dqmstore_output_msg.SerializeToZeroCopyStream(&gzip_stream);
216 
217  // make sure we flush before close
218  gzip_stream.Close();
219  out_stream.Close();
220  ::close(out_fd);
221 }
222 
223 
224 void fillMessage(dqmstorepb::ROOTFilePB &dqmstore_output_msg,
225  const std::set<MicroME> & micromes) {
226  std::set<MicroME>::iterator mi = micromes.begin();
227  std::set<MicroME>::iterator me = micromes.end();
228 
229  DEBUG(1, "Streaming ROOT objects" << std::endl);
230  for (; mi != me; ++mi) {
231  dqmstorepb::ROOTFilePB::Histo* h = dqmstore_output_msg.add_histo();
232  DEBUG(2, "Streaming ROOT object " << *(mi->fullname) << "\n");
233  h->set_full_pathname(*(mi->fullname));
234  TBufferFile buffer(TBufferFile::kWrite);
235  buffer.WriteObject(mi->obj);
236  h->set_size(buffer.Length());
237  h->set_flags(mi->flags);
238  h->set_streamed_histo((const void*)buffer.Buffer(),
239  buffer.Length());
240  delete mi->obj;
241  }
242 }
243 
244 
245 void processDirectory(TFile *file,
246  const std::string& curdir,
247  std::set<std::string> &dirs,
248  std::set<std::string> &objs,
249  std::set<std::string> &fullnames,
250  std::set<MicroME>& micromes) {
251  DEBUG(1, "Processing directory " << curdir << "\n");
252  file->cd(curdir.c_str());
253  TKey *key;
254  TIter next (gDirectory->GetListOfKeys());
255  while ((key = (TKey *) next())) {
256  TObject * obj = key->ReadObj();
257  if (dynamic_cast<TDirectory *>(obj)) {
258  std::string subdir;
259  subdir.reserve(curdir.size() + strlen(obj->GetName()) + 2);
260  subdir += curdir;
261  if (! curdir.empty())
262  subdir += '/';
263  subdir += obj->GetName();
264  processDirectory(file, subdir, dirs, objs, fullnames, micromes);
265  } else if ((dynamic_cast<TH1 *>(obj)) || (dynamic_cast<TObjString *>(obj))) {
266  if (dynamic_cast<TH1 *>(obj)) {
267  dynamic_cast<TH1 *>(obj)->SetDirectory(0);
268  }
269 
270  DEBUG(2, curdir << "/" << obj->GetName() << "\n");
271  MicroME mme(&*(fullnames.insert(curdir
272  + '/'
273  + std::string(obj->GetName())).first),
274  &*(dirs.insert(curdir).first),
275  &*(objs.insert(obj->GetName()).first));
276  if (obj) {
277  mme.obj = obj;
278  micromes.insert(mme);
279  }
280  }
281  }
282 }
283 
284 
285 int encodeFile(const std::string &output_filename,
286  const std::vector<std::string> &filenames) {
287  assert(filenames.size() == 1);
288  TFile input(filenames[0].c_str());
289  DEBUG(0, "Encoding file " << filenames[0] << std::endl);
290  std::set<std::string> dirs;
291  std::set<std::string> objs;
292  std::set<std::string> fullnames;
293  std::set<MicroME> micromes;
294  dqmstorepb::ROOTFilePB dqmstore_message;
295 
296  processDirectory(&input, "", dirs, objs, fullnames, micromes);
297  fillMessage(dqmstore_message, micromes);
298  writeMessage(dqmstore_message, output_filename);
299 
300  return 0;
301 }
302 
303 int convertFile(const std::string &output_filename,
304  const std::vector<std::string> &filenames) {
305  assert(filenames.size() == 1);
306  TFile output(output_filename.c_str(), "RECREATE");
307  DEBUG(0, "Converting file " << filenames[0] << std::endl);
308  dqmstorepb::ROOTFilePB dqmstore_message;
309 
310  int filedescriptor = ::open(filenames[0].c_str(), O_RDONLY);
311  FileInputStream fin(filedescriptor);
312  GzipInputStream input(&fin);
313  CodedInputStream input_coded(&input);
314  input_coded.SetTotalBytesLimit(1024*1024*1024, -1);
315  if (!dqmstore_message.ParseFromCodedStream(&input_coded)) {
316  std::cout << "Fatal Error opening file "
317  << filenames[0] << std::endl;
318  return ERR_NOFILE;
319  }
320  ::close(filedescriptor);
321 
322  for (int i = 0; i < dqmstore_message.histo_size(); i++) {
323  const dqmstorepb::ROOTFilePB::Histo& h = dqmstore_message.histo(i);
324  DEBUG(1, h.full_pathname() << std::endl);
325  DEBUG(1, h.size() << std::endl);
326  TBufferFile buf(TBufferFile::kRead, h.size(),
327  (void*)h.streamed_histo().data(),
328  kFALSE);
329  buf.Reset();
330  TObject *obj = extractNextObject(buf);
331  std::string path,objname;
332  get_info(h, path, objname, &obj);
333  gDirectory->cd("/");
334  // Find the first path component.
335  size_t start = 0;
336  size_t end = path.find('/', start);
337  if (end == std::string::npos)
338  end = path.size();
339  while (true)
340  {
341  std::string part(path, start, end-start);
342  if (! gDirectory->Get(part.c_str()))
343  gDirectory->mkdir(part.c_str());
344  gDirectory->cd(part.c_str());
345  // Stop if we reached the end, ignoring any trailing '/'.
346  if (end+1 >= path.size())
347  break;
348  // Find the next path component.
349  start = end+1;
350  end = path.find('/', start);
351  if (end == std::string::npos)
352  end = path.size();
353  }
354  obj->Write();
355  DEBUG(1, obj->GetName() << std::endl);
356  }
357  output.Close();
358  return 0;
359 }
360 
361 int dumpFiles(const std::vector<std::string> &filenames) {
362  assert(filenames.size() > 0);
363  for (int i = 0, e = filenames.size(); i != e; ++i) {
364  DEBUG(0, "Dumping file " << filenames[i] << std::endl);
365  dqmstorepb::ROOTFilePB dqmstore_message;
366 
367  int filedescriptor = ::open(filenames[0].c_str(), O_RDONLY);
368  FileInputStream fin(filedescriptor);
369  GzipInputStream input(&fin);
370  CodedInputStream input_coded(&input);
371  input_coded.SetTotalBytesLimit(1024*1024*1024, -1);
372  if (!dqmstore_message.ParseFromCodedStream(&input_coded)) {
373  std::cout << "Fatal Error opening file "
374  << filenames[0] << std::endl;
375  return ERR_NOFILE;
376  }
377  ::close(filedescriptor);
378 
379  for (int i = 0; i < dqmstore_message.histo_size(); i++) {
380  const dqmstorepb::ROOTFilePB::Histo& h = dqmstore_message.histo(i);
381  DEBUG(1, h.full_pathname() << std::endl);
382  DEBUG(1, h.size() << std::endl);
383  TBufferFile buf(TBufferFile::kRead, h.size(),
384  (void*)h.streamed_histo().data(),
385  kFALSE);
386  buf.Reset();
387  TObject *obj = extractNextObject(buf);
388  DEBUG(1, obj->GetName() << std::endl);
389  DEBUG(1, "Flags: " << h.flags() << std::endl);
390  }
391  }
392 
393  return 0;
394 }
395 
396 int addFiles(const std::string &output_filename,
397  const std::vector<std::string> &filenames) {
398  dqmstorepb::ROOTFilePB dqmstore_outputmessage;
399  std::set<std::string> dirs;
400  std::set<std::string> objs;
401  std::set<std::string> fullnames;
402  std::set<MicroME> micromes;
403 
404  assert(filenames.size() > 0);
405  DEBUG(1, "Adding file " << filenames[0] << std::endl);
406  {
407  dqmstorepb::ROOTFilePB dqmstore_message;
408  int filedescriptor;
409  if ((filedescriptor = ::open(filenames[0].c_str(), O_RDONLY)) == -1) {
410  std::cout << "Fatal Error opening file "
411  << filenames[0] << std::endl;
412  return ERR_NOFILE;
413  }
414 
415  FileInputStream fin(filedescriptor);
416  GzipInputStream input(&fin);
417  CodedInputStream input_coded(&input);
418  input_coded.SetTotalBytesLimit(1024*1024*1024, -1);
419  if (!dqmstore_message.ParseFromCodedStream(&input_coded)) {
420  std::cout << "Fatal Error opening file "
421  << filenames[0] << std::endl;
422  return ERR_NOFILE;
423  }
424  ::close(filedescriptor);
425 
426  for (int i = 0; i < dqmstore_message.histo_size(); i++) {
428  std::string objname;
429  TObject *obj = NULL;
430  const dqmstorepb::ROOTFilePB::Histo &h = dqmstore_message.histo(i);
431  get_info(h, path, objname, &obj);
432  MicroME * mme = new MicroME(&*(fullnames.insert(h.full_pathname()).first),
433  &*(dirs.insert(path).first),
434  &*(objs.insert(objname).first),
435  h.flags());
436  if (obj) {
437  mme->obj = obj;
438  micromes.insert(*mme);
439  DEBUG(2, "Inserting MicroME " << *mme->fullname << std::endl);
440  }
441  }
442  }
443 
444  for (int i = 1, e = filenames.size(); i != e; ++i) {
445  DEBUG(1, "Adding file " << filenames[i] << std::endl);
446  dqmstorepb::ROOTFilePB dqmstore_msg;
447  int filedescriptor;
448  if ((filedescriptor = ::open(filenames[i].c_str(), O_RDONLY)) == -1) {
449  std::cout << "Fatal Error opening file "
450  << filenames[i] << std::endl;
451  return ERR_NOFILE;
452  }
453  FileInputStream fin(filedescriptor);
454  GzipInputStream input(&fin);
455  CodedInputStream input_coded(&input);
456  input_coded.SetTotalBytesLimit(1024*1024*1024, -1);
457  if (!dqmstore_msg.ParseFromCodedStream(&input_coded)) {
458  std::cout << "Fatal Error opening file "
459  << filenames[0] << std::endl;
460  return ERR_NOFILE;
461  }
462  ::close(filedescriptor);
463 
464  std::set<MicroME>::iterator mi = micromes.begin();
465  std::set<MicroME>::iterator me = micromes.end();
466  int elem = 0;
467  for (; mi != me; ++mi) {
469  std::string objname;
471  TObject *obj = NULL;
472  if (elem < dqmstore_msg.histo_size()) {
474  const_cast<dqmstorepb::ROOTFilePB::Histo &>(dqmstore_msg.histo(elem));
475  get_info(h, path, objname, &obj);
476 
477  DEBUG(2, "Comparing " << *(*mi).dirname << "/"
478  << *(*mi).objname << " vs "
479  << h.full_pathname() << std::endl);
480  int diff = (*mi).fullname->compare(h.full_pathname());
481  if (diff == 0 && obj != NULL) {
482  mi->add(obj);
483  delete obj;
484  ++elem;
485  } else if (! lessThanMME(*(*mi).dirname, *(*mi).objname,
486  path, objname)) {
487  // loop over elem till they are no longer less than iterator.
488  bool loop = true;
489  while (loop) {
490  DEBUG(2, "Adding Missing histogram "
491  << h.full_pathname() << std::endl);
492  // That's fine since we add elements to the left of the
493  // current node, so we do not screw up the iteration
494  // process.
495  MicroME * mme = new MicroME(&*(fullnames.insert(h.full_pathname()).first),
496  &*(dirs.insert(path).first),
497  &*(objs.insert(objname).first));
498  if (obj) {
499  mme->obj = obj;
500  micromes.insert(*mme);
501  ++elem;
502  }
503  if (elem < dqmstore_msg.histo_size()) {
504  h = const_cast<dqmstorepb::ROOTFilePB::Histo &>(dqmstore_msg.histo(elem));
505  get_info(h, path, objname, &obj);
506  DEBUG(2, "Comparing " << *(*mi).dirname << "/"
507  << *(*mi).objname << " vs "
508  << h.full_pathname() << std::endl);
509  loop = ! lessThanMME(*(*mi).dirname, *(*mi).objname,
510  path, objname);
511  } else {
512  loop = false;
513  }
514  }
515  }
516  }
517  }
518 
519  // Transfer whatever else is left pending in the new file.
520  while (elem < dqmstore_msg.histo_size()) {
522  std::string objname;
523  TObject *obj = NULL;
524 
525  const dqmstorepb::ROOTFilePB::Histo &h = dqmstore_msg.histo(elem);
526  get_info(h, path, objname, &obj);
527  DEBUG(2, "Adding Missing histogram " << h.full_pathname() << std::endl);
528  MicroME * mme = new MicroME(&*(fullnames.insert(h.full_pathname()).first),
529  &*(dirs.insert(path).first),
530  &*(objs.insert(objname).first));
531  if (obj) {
532  mme->obj = obj;
533  micromes.insert(*mme);
534  ++elem;
535  }
536  }
537  }
538 
539  dqmstorepb::ROOTFilePB dqmstore_output_msg;
540  fillMessage(dqmstore_output_msg, micromes);
541  writeMessage(dqmstore_output_msg, output_filename);
542 
543  return 0;
544 }
545 
546 static int
548 {
549  static const std::string app_name("fasthadd");
550 
551  std::cerr << "Usage: " << app_name
552  << " [--[no-]debug] TASK OPTIONS\n\n "
553  << app_name << " [OPTIONS] add -o OUTPUT_FILE [DAT FILE...]\n "
554  << app_name << " [OPTIONS] convert -o ROOT_FILE DAT_FILE\n "
555  << app_name << " [OPTIONS] encode -o DAT_FILE ROOT_FILE\n "
556  << app_name << " [OPTIONS] dump [DAT FILE...]\n ";
557  return ERR_BADCFG;
558 }
559 
560 int main(int argc, char * argv[]) {
561  int arg;
562  int ret = 0;
564  std::vector<std::string> filenames;
565  TaskType task;
566 
567  filenames.reserve(argc);
568 
569  for (arg = 1; arg < argc; ++arg) {
570  if (! strcmp(argv[arg], "--no-debug"))
571  debug = 0;
572  else if (! strcmp(argv[arg], "--debug")
573  || ! strcmp(argv[arg], "-d"))
574  debug++;
575  else
576  break;
577  }
578 
579  if (arg < argc) {
580  if (! strcmp(argv[arg], "add")) {
581  ++arg;
582  task = TASK_ADD;
583  } else if (! strcmp(argv[arg], "dump")) {
584  ++arg;
585  task = TASK_DUMP;
586  } else if (! strcmp(argv[arg], "convert")) {
587  ++arg;
588  task = TASK_CONVERT;
589  } else if (! strcmp(argv[arg], "encode")) {
590  ++arg;
591  task = TASK_ENCODE;
592  } else {
593  std::cerr << "Unknown action: " << argv[arg] << std::endl;
594  return showusage();
595  }
596  } else {
597  std::cerr << "Not enough arguments\n";
598  return showusage();
599  }
600 
601  if (task == TASK_ADD || task == TASK_CONVERT || task == TASK_ENCODE) {
602  if (arg == argc) {
603  std::cerr << "add|convert|encode actions requires a -o option to be set\n";
604  return showusage();
605  }
606  if (! strcmp(argv[arg], "-o")) {
607  if (arg < argc-1) {
608  output_file = argv[++arg];
609  } else {
610  std::cerr << " -o option requires a value\n";
611  return showusage();
612  }
613  }
614  } else if (task == TASK_DUMP) {
615  if (arg == argc) {
616  std::cerr << "Missing input file(s)\n";
617  return showusage();
618  }
619  for (; arg < argc; ++arg) {
620  filenames.push_back(argv[arg]);
621  }
622  }
623 
624  if (task == TASK_ADD || task == TASK_CONVERT || task == TASK_ENCODE) {
625  if (++arg == argc) {
626  std::cerr << "Missing input file(s)\n";
627  return showusage();
628  }
629  for (; arg < argc; ++arg) {
630  filenames.push_back(argv[arg]);
631  }
632  }
633 
634  if (task == TASK_ADD)
635  ret = addFiles(output_file, filenames);
636  else if (task == TASK_DUMP)
637  ret = dumpFiles(filenames);
638  else if (task == TASK_CONVERT)
639  ret = convertFile(output_file, filenames);
640  else if (task == TASK_ENCODE)
641  ret = encodeFile(output_file, filenames);
642 
643 
644  google::protobuf::ShutdownProtobufLibrary();
645  return ret;
646 }
MicroME(const std::string *full, const std::string *dir, const std::string *obj, uint32_t flags=0)
Definition: fastHadd.cc:114
void processDirectory(TFile *file, const std::string &curdir, std::set< std::string > &dirs, std::set< std::string > &objs, std::set< std::string > &fullnames, std::set< MicroME > &micromes)
Definition: fastHadd.cc:245
int i
Definition: DBlmapReader.cc:9
inline::google::protobuf::uint32 size() const
tuple start
Check for commandline option errors.
Definition: dqm_diff.py:58
const ::std::string & full_pathname() const
const std::string * objname
Definition: fastHadd.cc:121
static void get_info(const dqmstorepb::ROOTFilePB::Histo &h, std::string &dirname, std::string &objname, TObject **obj)
Definition: fastHadd.cc:178
TObject * extractNextObject(TBufferFile &buf)
Definition: fastHadd.cc:171
void fillMessage(dqmstorepb::ROOTFilePB &dqmstore_output_msg, const std::set< MicroME > &micromes)
Definition: fastHadd.cc:224
ErrType
Definition: fastHadd.cc:156
bool operator<(const MicroME &rhs) const
Definition: fastHadd.cc:126
TObject * obj
Definition: fastHadd.cc:122
#define NULL
Definition: scimark2.h:8
int addFiles(const std::string &output_filename, const std::vector< std::string > &filenames)
Definition: fastHadd.cc:396
int loop
CMSSW
const std::string * dirname
Definition: fastHadd.cc:120
void add(TObject *obj_to_add) const
Definition: fastHadd.cc:133
A arg
Definition: Factorize.h:36
void set_flags(::google::protobuf::uint32 value)
const ::std::string & streamed_histo() const
static std::string const input
Definition: EdmProvDump.cc:44
int main(int argc, char **argv)
tuple path
else: Piece not in the list, fine.
Definition: GenABIO.cc:180
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
#define end
Definition: vmac.h:37
bool first
Definition: L1TdeRCT.cc:75
TaskType
Definition: fastHadd.cc:149
const std::string * fullname
Definition: fastHadd.cc:119
int encodeFile(const std::string &output_filename, const std::vector< std::string > &filenames)
Definition: fastHadd.cc:285
string output_file
#define debug
Definition: HDRShower.cc:19
const ::dqmstorepb::ROOTFilePB_Histo & histo(int index) const
void set_size(::google::protobuf::uint32 value)
part
Definition: HCALResponse.h:20
tuple argc
Definition: dir2webdir.py:38
void writeMessage(const dqmstorepb::ROOTFilePB &dqmstore_output_msg, const std::string &output_filename)
Definition: fastHadd.cc:198
void set_full_pathname(const ::std::string &value)
int convertFile(const std::string &output_filename, const std::vector< std::string > &filenames)
Definition: fastHadd.cc:303
std::vector< boost::shared_ptr< fireworks::OptionNode > > Options
list key
Definition: combine.py:13
inline::dqmstorepb::ROOTFilePB_Histo * add_histo()
uint32_t flags
Definition: fastHadd.cc:124
inline::google::protobuf::uint32 flags() const
tuple cout
Definition: gather_cfg.py:121
dbl *** dir
Definition: mlp_gen.cc:35
static int showusage(void)
Definition: fastHadd.cc:547
int dumpFiles(const std::vector< std::string > &filenames)
Definition: fastHadd.cc:361
#define DEBUG(x, msg)
Definition: fastHadd.cc:100
static bool lessThanMME(const std::string &lhs_dirname, const std::string &lhs_objname, const std::string &rhs_dirname, const std::string &rhs_objname)
Definition: fastHadd.cc:104
void set_streamed_histo(const ::std::string &value)