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  FileOutputStream out_stream(out_fd);
210  options.format = GzipOutputStream::GZIP;
211  options.compression_level = 2;
212  GzipOutputStream gzip_stream(&out_stream,
213  options);
214  dqmstore_output_msg.SerializeToZeroCopyStream(&gzip_stream);
215 
216  google::protobuf::ShutdownProtobufLibrary();
217 }
218 
219 
220 void fillMessage(dqmstorepb::ROOTFilePB &dqmstore_output_msg,
221  const std::set<MicroME> & micromes) {
222  std::set<MicroME>::iterator mi = micromes.begin();
223  std::set<MicroME>::iterator me = micromes.end();
224 
225  DEBUG(1, "Streaming ROOT objects" << std::endl);
226  for (; mi != me; ++mi) {
227  dqmstorepb::ROOTFilePB::Histo* h = dqmstore_output_msg.add_histo();
228  DEBUG(2, "Streaming ROOT object " << *(mi->fullname) << "\n");
229  h->set_full_pathname(*(mi->fullname));
230  TBufferFile buffer(TBufferFile::kWrite);
231  buffer.WriteObject(mi->obj);
232  h->set_size(buffer.Length());
233  h->set_flags(mi->flags);
234  h->set_streamed_histo((const void*)buffer.Buffer(),
235  buffer.Length());
236  delete mi->obj;
237  }
238 }
239 
240 
241 void processDirectory(TFile *file,
242  const std::string& curdir,
243  std::set<std::string> &dirs,
244  std::set<std::string> &objs,
245  std::set<std::string> &fullnames,
246  std::set<MicroME>& micromes) {
247  DEBUG(1, "Processing directory " << curdir << "\n");
248  file->cd(curdir.c_str());
249  TKey *key;
250  TIter next (gDirectory->GetListOfKeys());
251  while ((key = (TKey *) next())) {
252  TObject * obj = key->ReadObj();
253  if (dynamic_cast<TDirectory *>(obj)) {
254  std::string subdir;
255  subdir.reserve(curdir.size() + strlen(obj->GetName()) + 2);
256  subdir += curdir;
257  if (! curdir.empty())
258  subdir += '/';
259  subdir += obj->GetName();
260  processDirectory(file, subdir, dirs, objs, fullnames, micromes);
261  } else if ((dynamic_cast<TH1 *>(obj)) || (dynamic_cast<TObjString *>(obj))) {
262  if (dynamic_cast<TH1 *>(obj)) {
263  dynamic_cast<TH1 *>(obj)->SetDirectory(0);
264  }
265 
266  DEBUG(2, curdir << "/" << obj->GetName() << "\n");
267  MicroME mme(&*(fullnames.insert(curdir
268  + '/'
269  + std::string(obj->GetName())).first),
270  &*(dirs.insert(curdir).first),
271  &*(objs.insert(obj->GetName()).first));
272  if (obj) {
273  mme.obj = obj;
274  micromes.insert(mme);
275  }
276  }
277  }
278 }
279 
280 
281 int encodeFile(const std::string &output_filename,
282  const std::vector<std::string> &filenames) {
283  assert(filenames.size() == 1);
284  TFile input(filenames[0].c_str());
285  DEBUG(0, "Encoding file " << filenames[0] << std::endl);
286  std::set<std::string> dirs;
287  std::set<std::string> objs;
288  std::set<std::string> fullnames;
289  std::set<MicroME> micromes;
290  dqmstorepb::ROOTFilePB dqmstore_message;
291 
292  processDirectory(&input, "", dirs, objs, fullnames, micromes);
293  fillMessage(dqmstore_message, micromes);
294  writeMessage(dqmstore_message, output_filename);
295 
296  return 0;
297 }
298 
299 int convertFile(const std::string &output_filename,
300  const std::vector<std::string> &filenames) {
301  assert(filenames.size() == 1);
302  TFile output(output_filename.c_str(), "RECREATE");
303  DEBUG(0, "Converting file " << filenames[0] << std::endl);
304  dqmstorepb::ROOTFilePB dqmstore_message;
305 
306  int filedescriptor = open(filenames[0].c_str(), O_RDONLY);
307  FileInputStream fin(filedescriptor);
308  GzipInputStream input(&fin);
309  CodedInputStream input_coded(&input);
310  input_coded.SetTotalBytesLimit(1024*1024*1024, -1);
311  if (!dqmstore_message.ParseFromCodedStream(&input_coded)) {
312  std::cout << "Fatal Error opening file "
313  << filenames[0] << std::endl;
314  return ERR_NOFILE;
315  }
316 
317  for (int i = 0; i < dqmstore_message.histo_size(); i++) {
318  const dqmstorepb::ROOTFilePB::Histo& h = dqmstore_message.histo(i);
319  DEBUG(1, h.full_pathname() << std::endl);
320  DEBUG(1, h.size() << std::endl);
321  TBufferFile buf(TBufferFile::kRead, h.size(),
322  (void*)h.streamed_histo().data(),
323  kFALSE);
324  buf.Reset();
325  TObject *obj = extractNextObject(buf);
326  std::string path,objname;
327  get_info(h, path, objname, &obj);
328  gDirectory->cd("/");
329  // Find the first path component.
330  size_t start = 0;
331  size_t end = path.find('/', start);
332  if (end == std::string::npos)
333  end = path.size();
334  while (true)
335  {
336  std::string part(path, start, end-start);
337  if (! gDirectory->Get(part.c_str()))
338  gDirectory->mkdir(part.c_str());
339  gDirectory->cd(part.c_str());
340  // Stop if we reached the end, ignoring any trailing '/'.
341  if (end+1 >= path.size())
342  break;
343  // Find the next path component.
344  start = end+1;
345  end = path.find('/', start);
346  if (end == std::string::npos)
347  end = path.size();
348  }
349  obj->Write();
350  DEBUG(1, obj->GetName() << std::endl);
351  }
352  output.Close();
353  google::protobuf::ShutdownProtobufLibrary();
354  return 0;
355 }
356 
357 int dumpFiles(const std::vector<std::string> &filenames) {
358  assert(filenames.size() > 0);
359  for (int i = 0, e = filenames.size(); i != e; ++i) {
360  DEBUG(0, "Dumping file " << filenames[i] << std::endl);
361  dqmstorepb::ROOTFilePB dqmstore_message;
362 
363  int filedescriptor = open(filenames[0].c_str(), O_RDONLY);
364  FileInputStream fin(filedescriptor);
365  GzipInputStream input(&fin);
366  CodedInputStream input_coded(&input);
367  input_coded.SetTotalBytesLimit(1024*1024*1024, -1);
368  if (!dqmstore_message.ParseFromCodedStream(&input_coded)) {
369  std::cout << "Fatal Error opening file "
370  << filenames[0] << std::endl;
371  return ERR_NOFILE;
372  }
373 
374  for (int i = 0; i < dqmstore_message.histo_size(); i++) {
375  const dqmstorepb::ROOTFilePB::Histo& h = dqmstore_message.histo(i);
376  DEBUG(1, h.full_pathname() << std::endl);
377  DEBUG(1, h.size() << std::endl);
378  TBufferFile buf(TBufferFile::kRead, h.size(),
379  (void*)h.streamed_histo().data(),
380  kFALSE);
381  buf.Reset();
382  TObject *obj = extractNextObject(buf);
383  DEBUG(1, obj->GetName() << std::endl);
384  DEBUG(1, "Flags: " << h.flags() << std::endl);
385  }
386  }
387  google::protobuf::ShutdownProtobufLibrary();
388  return 0;
389 }
390 
391 int addFiles(const std::string &output_filename,
392  const std::vector<std::string> &filenames) {
393  dqmstorepb::ROOTFilePB dqmstore_outputmessage;
394  std::set<std::string> dirs;
395  std::set<std::string> objs;
396  std::set<std::string> fullnames;
397  std::set<MicroME> micromes;
398 
399  assert(filenames.size() > 0);
400  DEBUG(1, "Adding file " << filenames[0] << std::endl);
401  {
402  dqmstorepb::ROOTFilePB dqmstore_message;
403  int filedescriptor;
404  if ((filedescriptor = open(filenames[0].c_str(), O_RDONLY)) == -1) {
405  std::cout << "Fatal Error opening file "
406  << filenames[0] << std::endl;
407  return ERR_NOFILE;
408  }
409 
410  FileInputStream fin(filedescriptor);
411  GzipInputStream input(&fin);
412  CodedInputStream input_coded(&input);
413  input_coded.SetTotalBytesLimit(1024*1024*1024, -1);
414  if (!dqmstore_message.ParseFromCodedStream(&input_coded)) {
415  std::cout << "Fatal Error opening file "
416  << filenames[0] << std::endl;
417  return ERR_NOFILE;
418  }
419  for (int i = 0; i < dqmstore_message.histo_size(); i++) {
421  std::string objname;
422  TObject *obj = NULL;
423  const dqmstorepb::ROOTFilePB::Histo &h = dqmstore_message.histo(i);
424  get_info(h, path, objname, &obj);
425  MicroME * mme = new MicroME(&*(fullnames.insert(h.full_pathname()).first),
426  &*(dirs.insert(path).first),
427  &*(objs.insert(objname).first),
428  h.flags());
429  if (obj) {
430  mme->obj = obj;
431  micromes.insert(*mme);
432  DEBUG(2, "Inserting MicroME " << *mme->fullname << std::endl);
433  }
434  }
435  }
436 
437  for (int i = 1, e = filenames.size(); i != e; ++i) {
438  DEBUG(1, "Adding file " << filenames[i] << std::endl);
439  dqmstorepb::ROOTFilePB dqmstore_msg;
440  int filedescriptor;
441  if ((filedescriptor = open(filenames[i].c_str(), O_RDONLY)) == -1) {
442  std::cout << "Fatal Error opening file "
443  << filenames[i] << std::endl;
444  return ERR_NOFILE;
445  }
446  FileInputStream fin(filedescriptor);
447  GzipInputStream input(&fin);
448  CodedInputStream input_coded(&input);
449  input_coded.SetTotalBytesLimit(1024*1024*1024, -1);
450  if (!dqmstore_msg.ParseFromCodedStream(&input_coded)) {
451  std::cout << "Fatal Error opening file "
452  << filenames[0] << std::endl;
453  return ERR_NOFILE;
454  }
455 
456  std::set<MicroME>::iterator mi = micromes.begin();
457  std::set<MicroME>::iterator me = micromes.end();
458  int elem = 0;
459  for (; mi != me; ++mi) {
461  std::string objname;
463  TObject *obj = NULL;
464  if (elem < dqmstore_msg.histo_size()) {
466  const_cast<dqmstorepb::ROOTFilePB::Histo &>(dqmstore_msg.histo(elem));
467  get_info(h, path, objname, &obj);
468 
469  DEBUG(2, "Comparing " << *(*mi).dirname << "/"
470  << *(*mi).objname << " vs "
471  << h.full_pathname() << std::endl);
472  int diff = (*mi).fullname->compare(h.full_pathname());
473  if (diff == 0 && obj != NULL) {
474  mi->add(obj);
475  delete obj;
476  ++elem;
477  } else if (! lessThanMME(*(*mi).dirname, *(*mi).objname,
478  path, objname)) {
479  // loop over elem till they are no longer less than iterator.
480  bool loop = true;
481  while (loop) {
482  DEBUG(2, "Adding Missing histogram "
483  << h.full_pathname() << std::endl);
484  // That's fine since we add elements to the left of the
485  // current node, so we do not screw up the iteration
486  // process.
487  MicroME * mme = new MicroME(&*(fullnames.insert(h.full_pathname()).first),
488  &*(dirs.insert(path).first),
489  &*(objs.insert(objname).first));
490  if (obj) {
491  mme->obj = obj;
492  micromes.insert(*mme);
493  ++elem;
494  }
495  if (elem < dqmstore_msg.histo_size()) {
496  h = const_cast<dqmstorepb::ROOTFilePB::Histo &>(dqmstore_msg.histo(elem));
497  get_info(h, path, objname, &obj);
498  DEBUG(2, "Comparing " << *(*mi).dirname << "/"
499  << *(*mi).objname << " vs "
500  << h.full_pathname() << std::endl);
501  loop = ! lessThanMME(*(*mi).dirname, *(*mi).objname,
502  path, objname);
503  } else {
504  loop = false;
505  }
506  }
507  }
508  }
509  }
510 
511  // Transfer whatever else is left pending in the new file.
512  while (elem < dqmstore_msg.histo_size()) {
514  std::string objname;
515  TObject *obj = NULL;
516 
517  const dqmstorepb::ROOTFilePB::Histo &h = dqmstore_msg.histo(elem);
518  get_info(h, path, objname, &obj);
519  DEBUG(2, "Adding Missing histogram " << h.full_pathname() << std::endl);
520  MicroME * mme = new MicroME(&*(fullnames.insert(h.full_pathname()).first),
521  &*(dirs.insert(path).first),
522  &*(objs.insert(objname).first));
523  if (obj) {
524  mme->obj = obj;
525  micromes.insert(*mme);
526  ++elem;
527  }
528  }
529  }
530 
531  dqmstorepb::ROOTFilePB dqmstore_output_msg;
532  fillMessage(dqmstore_output_msg, micromes);
533  writeMessage(dqmstore_output_msg, output_filename);
534 
535  return 0;
536 }
537 
538 static int
540 {
541  static const std::string app_name("fasthadd");
542 
543  std::cerr << "Usage: " << app_name
544  << " [--[no-]debug] TASK OPTIONS\n\n "
545  << app_name << " [OPTIONS] add -o OUTPUT_FILE [DAT FILE...]\n "
546  << app_name << " [OPTIONS] convert -o ROOT_FILE DAT_FILE\n "
547  << app_name << " [OPTIONS] encode -o DAT_FILE ROOT_FILE\n "
548  << app_name << " [OPTIONS] dump [DAT FILE...]\n ";
549  return ERR_BADCFG;
550 }
551 
552 int main(int argc, char * argv[]) {
553  int arg;
554  int ret = 0;
556  std::vector<std::string> filenames;
557  TaskType task;
558 
559  filenames.reserve(argc);
560 
561  for (arg = 1; arg < argc; ++arg) {
562  if (! strcmp(argv[arg], "--no-debug"))
563  debug = 0;
564  else if (! strcmp(argv[arg], "--debug")
565  || ! strcmp(argv[arg], "-d"))
566  debug++;
567  else
568  break;
569  }
570 
571  if (arg < argc) {
572  if (! strcmp(argv[arg], "add")) {
573  ++arg;
574  task = TASK_ADD;
575  } else if (! strcmp(argv[arg], "dump")) {
576  ++arg;
577  task = TASK_DUMP;
578  } else if (! strcmp(argv[arg], "convert")) {
579  ++arg;
580  task = TASK_CONVERT;
581  } else if (! strcmp(argv[arg], "encode")) {
582  ++arg;
583  task = TASK_ENCODE;
584  } else {
585  std::cerr << "Unknown action: " << argv[arg] << std::endl;
586  return showusage();
587  }
588  } else {
589  std::cerr << "Not enough arguments\n";
590  return showusage();
591  }
592 
593  if (task == TASK_ADD || task == TASK_CONVERT || task == TASK_ENCODE) {
594  if (arg == argc) {
595  std::cerr << "add|convert|encode actions requires a -o option to be set\n";
596  return showusage();
597  }
598  if (! strcmp(argv[arg], "-o")) {
599  if (arg < argc-1) {
600  output_file = argv[++arg];
601  } else {
602  std::cerr << " -o option requires a value\n";
603  return showusage();
604  }
605  }
606  } else if (task == TASK_DUMP) {
607  if (arg == argc) {
608  std::cerr << "Missing input file(s)\n";
609  return showusage();
610  }
611  for (; arg < argc; ++arg) {
612  filenames.push_back(argv[arg]);
613  }
614  }
615 
616  if (task == TASK_ADD || task == TASK_CONVERT || task == TASK_ENCODE) {
617  if (++arg == argc) {
618  std::cerr << "Missing input file(s)\n";
619  return showusage();
620  }
621  for (; arg < argc; ++arg) {
622  filenames.push_back(argv[arg]);
623  }
624  }
625 
626  if (task == TASK_ADD)
627  ret = addFiles(output_file, filenames);
628  else if (task == TASK_DUMP)
629  ret = dumpFiles(filenames);
630  else if (task == TASK_CONVERT)
631  ret = convertFile(output_file, filenames);
632  else if (task == TASK_ENCODE)
633  ret = encodeFile(output_file, filenames);
634 
635  return ret;
636 }
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:241
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:220
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:391
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:281
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:299
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:539
int dumpFiles(const std::vector< std::string > &filenames)
Definition: fastHadd.cc:357
#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)