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