config_dumper.cc
Go to the documentation of this file.
9 #include "cetlib/exempt_ptr.h"
10 #include "fhiclcpp/ParameterSet.h"
13 
14 #include "boost/program_options.hpp"
15 
16 #include "TFile.h"
17 #include "TTree.h"
18 
19 extern "C" {
20 #include "sqlite3.h"
21 }
22 
23 #include <cstddef>
24 #include <iomanip>
25 #include <iostream>
26 #include <memory>
27 #include <ostream>
28 #include <sstream>
29 #include <string>
30 #include <vector>
31 
32 namespace bpo = boost::program_options;
33 
37 using std::back_inserter;
38 using std::cerr;
39 using std::cout;
40 using std::endl;
41 using std::ostream;
42 using std::string;
43 using std::vector;
44 
45 typedef vector<string> stringvec;
46 
47 enum class PsetType { MODULE, SERVICE, PROCESS };
48 
49 size_t
50 db_size(sqlite3* db)
51 {
52  sqlite3_stmt* stmt;
53  sqlite3_prepare_v2(db, "PRAGMA page_size;", -1, &stmt, nullptr);
54  sqlite3_step(stmt);
55  size_t page_size = sqlite3_column_int64(stmt, 0);
56  sqlite3_finalize(stmt);
57  sqlite3_prepare_v2(db, "PRAGMA page_count;", -1, &stmt, nullptr);
58  sqlite3_step(stmt);
59  size_t page_count = sqlite3_column_int64(stmt, 0);
60  sqlite3_finalize(stmt);
61  return page_size * page_count;
62 }
63 
65 db_size_hr(sqlite3* db)
66 {
67  std::string result;
68  double size = db_size(db);
69  std::vector<std::string> units = {"b", "KiB", "MiB", "GiB", "TiB"};
70  auto unit = units.cbegin(), end = units.cend();
71  while (size > 1024.0 && unit != end) {
72  size /= 1024.0;
73  ++unit;
74  }
75  std::ostringstream ss;
76  ss << std::fixed << std::setprecision(1) << size << " " << *unit;
77  result = ss.str();
78  return result;
79 }
80 
82 want_pset(ParameterSet const& ps, stringvec const& filters, PsetType mode)
83 {
84  string label;
85  switch (mode) {
86  case PsetType::MODULE:
87  ps.get_if_present<string>("module_label", label);
88  break;
89  case PsetType::SERVICE:
90  ps.get_if_present<string>("service_provider", label) ||
91  ps.get_if_present<string>("service_type", label);
92  break;
93  case PsetType::PROCESS: {
95  if (ps.get_if_present("source", dummy)) {
96  ps.get_if_present<string>("process_name", label);
97  }
98  } break;
99  default:
100  throw std::string("INTERNAL ERROR: unknown mode ")
101  .append(std::to_string(int(mode)))
102  .append(".");
103  }
104  return (filters.empty() || label.empty() || cet::search_all(filters, label)) ?
105  label :
106  std::string();
107 }
108 
111 {
112  ParameterSet result(ps);
113  switch (mode) {
114  case PsetType::MODULE:
115  result.erase("module_label");
116  break;
117  case PsetType::SERVICE:
118  result.erase("service_type");
119  result.erase("service_provider");
120  break;
121  case PsetType::PROCESS:
122  result.erase("process_name");
123  break;
124  default:
125  throw std::string("INTERNAL ERROR: unknown mode ")
126  .append(std::to_string(int(mode)))
127  .append(".");
128  }
129  return result;
130 }
131 
132 // Read all the ParameterSets stored in 'file'. Write any error messages
133 // to errors. Return false on failure, and true on success.
134 bool
135 read_all_parameter_sets(TFile& file, ostream& errors)
136 {
137  ParameterSetMap psm;
138  ParameterSetMap* psm_address = &psm;
139  // Find the TTree that holds this data.
140  TTree* metadata_tree =
141  static_cast<TTree*>(file.Get(art::rootNames::metaDataTreeName().c_str()));
142  if (!metadata_tree) {
143  errors << "Unable to find the metadata tree in file '" << file.GetName()
144  << "';\nthis may not be an ART event data file.\n";
145  return false;
146  }
147  if (metadata_tree->GetBranch(
148  art::rootNames::metaBranchRootName<ParameterSetMap>())) {
149  metadata_tree->SetBranchAddress(
150  art::rootNames::metaBranchRootName<ParameterSetMap>(), &psm_address);
151  }
153  art::FileFormatVersion* ffv_address = &ffv;
154  metadata_tree->SetBranchAddress(
155  art::rootNames::metaBranchRootName<art::FileFormatVersion>(), &ffv_address);
156  long bytes_read = metadata_tree->GetEntry(0);
157  if (bytes_read < 0) {
158  errors << "Unable to read the metadata tree in file '" << file.GetName()
159  << ";\nthis file appears to be corrupted.\n";
160  return false;
161  }
162  // Check version
163  std::string const expected_era = art::getFileFormatEra();
164  if (ffv.era_ != expected_era) {
165  errors << "Can only read files written during the \"" << expected_era
166  << "\" era: "
167  << "Era of "
168  << "\"" << file.GetName() << "\" was "
169  << (ffv.era_.empty() ? "not set" : ("set to \"" + ffv.era_ + "\" "))
170  << ".\n";
171  return false;
172  }
173  for (auto const& pr : psm) {
174  // Read the next ParameterSet directly into the output vector.
175  fhicl::ParameterSet pset;
176  fhicl::make_ParameterSet(pr.second.pset_, pset);
178  }
179  if (ffv.value_ >= 5) { // Should have metadata DB.
180  // Open the DB
181  art::SQLite3Wrapper sqliteDB(&file, "RootFileDB");
182  std::cout << "# Read SQLiteDB from file, total size: "
183  << db_size_hr(sqliteDB) << ".\n"
184  << std::endl;
187  }
188  return true;
189 }
190 
191 // Extract all the requested module configuration ParameterSets (for
192 // modules with the given labels, run as part of processes of the given
193 // names) from the given TFIle. An empty list of process names means
194 // select all process names; an empty list of module labels means select
195 // all modules. The ParameterSets are written to the stream output, and
196 // error messages are written to the stream errors.
197 //
198 // Returns 0 to indicate success, and 1 on failure.
199 // Precondition: file.IsZombie() == false
200 
201 // Caution: We pass 'file' by non-const reference because the TFile interface
202 // does not declare the functions we use to be const, even though they do not
203 // modify the underlying file.
204 int
206  stringvec const& filters,
207  PsetType const mode,
208  ostream& output,
209  ostream& errors)
210 {
211  if (!read_all_parameter_sets(file, errors)) {
212  errors << "Unable to to read parameter sets.\n";
213  return 1;
214  }
215 
216  // Print ParameterSets alphabetically according to the top-level
217  // name. There is an additional request to sort according to
218  // chronology--i.e. presumably first according to process name, and
219  // then alphabetically within.
220  auto const& collection = fhicl::ParameterSetRegistry::get();
221 
222  // Cache pointers to the ParameterSets to avoid exorbitant copying.
223  std::map<std::string, cet::exempt_ptr<fhicl::ParameterSet const>> sorted_pses;
224  for (auto const& pr : collection) {
225  auto const& pset = pr.second;
226  std::string const label{want_pset(pset, filters, mode)};
227  if (label.empty())
228  continue;
229 
230  sorted_pses.emplace(label, &pset);
231  }
232 
233  for (auto const& pr : sorted_pses) {
234  auto const& pset = *pr.second;
235  output << pr.first << ": {\n";
236  output << strip_pset(pset, mode).to_indented_string(1);
237  output << "}\n\n";
238  }
239 
240  return 0;
241 }
242 
243 // Extract all the requested module configuration ParameterSets (for
244 // modules with the given labels, run as part of processes of the given
245 // names) from the named files. An empty list of process names means
246 // select all process names; an empty list of module labels means select
247 // all modules. The ParameterSets are written to the stream output, and
248 // error messages are written to the stream errors.
249 //
250 // The return value is the number of files in which errors were
251 // encountered, and is thus 0 to indicate success.
252 int
254  stringvec const& filters,
255  PsetType const mode,
256  ostream& output,
257  ostream& errors)
258 {
259  int rc{0};
260  for (auto const& file_name : file_names) {
261  std::unique_ptr<TFile> current_file{TFile::Open(file_name.c_str(), "READ")};
262  if (!current_file || current_file->IsZombie()) {
263  ++rc;
264  errors << "Unable to open file '" << file_name << "' for reading."
265  << "\nSkipping to next file.\n";
266  } else {
267  std::cout << "=============================================\n";
268  std::cout << "Processing file: " << file_name << std::endl;
269  rc += print_pset_from_file(*current_file, filters, mode, output, errors);
270  }
271  }
272  return rc;
273 }
274 
275 int
276 main(int argc, char* argv[])
277 {
278  // ------------------
279  // use the boost command line option processing library to help out
280  // with command line options
281  std::ostringstream descstr;
282  descstr << argv[0] << " <PsetType> <options> [<source-file>]+";
283  bpo::options_description desc(descstr.str());
284  desc.add_options()(
285  "filter,f",
286  bpo::value<stringvec>()->composing(),
287  "Only entities whose identifier (label (M), service type (S) "
288  "or process name (P)) match (multiple OK).")("help,h",
289  "this help message.")(
290  "modules,M", "PsetType: print module configurations (default).")(
291  "source,s",
292  bpo::value<stringvec>()->composing(),
293  "source data file (multiple OK).")(
294  "services,S", "PsetType: print service configurations.")(
295  "process,P", "PsetType: print process configurations.");
296  bpo::options_description all_opts("All Options.");
297  all_opts.add(desc);
298  // Each non-option argument is interpreted as the name of a file to be
299  // processed. Any number of filenames is allowed.
300  bpo::positional_options_description pd;
301  pd.add("source", -1);
302  // The variables_map contains the actual program options.
303  bpo::variables_map vm;
304  try {
305  bpo::store(bpo::command_line_parser(argc, argv)
306  .options(all_opts)
307  .positional(pd)
308  .run(),
309  vm);
310  bpo::notify(vm);
311  }
312  catch (bpo::error const& e) {
313  std::cerr << "Exception from command line processing in " << argv[0] << ": "
314  << e.what() << "\n";
315  return 2;
316  }
317  if (vm.count("help")) {
318  std::cout << desc << std::endl;
319  return 1;
320  }
321 
322  // Process the mode information.
323  PsetType mode;
324  if (vm.count("services")) {
325  mode = PsetType::SERVICE;
326  } else if (vm.count("process")) {
327  mode = PsetType::PROCESS;
328  } else {
329  mode = PsetType::MODULE;
330  }
331 
332  // Obtain any filtering names to limit what we show.
333  stringvec filters;
334  if (vm.count("filter")) {
335  cet::copy_all(vm["filter"].as<stringvec>(), std::back_inserter(filters));
336  }
337 
338  // Get the names of the files we will process.
339  stringvec file_names;
340  size_t file_count = vm.count("source");
341  if (file_count < 1) {
342  cerr << "ERROR: One or more input files must be specified;"
343  << " supply filenames as program arguments\n"
344  << "For usage and options list, please do 'config_dumper --help'.\n";
345  return 3;
346  }
347  file_names.reserve(file_count);
348  cet::copy_all(vm["source"].as<stringvec>(), std::back_inserter(file_names));
349 
350  // Register the tkey VFS with sqlite:
351  tkeyvfs_init();
352 
353  // Do the work.
354  return print_psets_from_files(file_names, filters, mode, cout, cerr);
355 }
bool read_all_parameter_sets(TFile &file, ostream &errors)
ParameterSet strip_pset(ParameterSet const &ps, PsetType mode)
static ParameterSetID const & put(ParameterSet const &ps)
static const double ps
Definition: Units.h:103
std::string string
Definition: nybbler.cc:12
static collection_type const & get() noexcept
void make_ParameterSet(intermediate_table const &tbl, ParameterSet &ps)
std::vector< std::string > stringvec
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
std::string const & metaDataTreeName()
Definition: rootNames.cc:40
error
Definition: includer.cc:31
bool search_all(FwdCont const &, Datum const &)
const double e
int tkeyvfs_init(void)
Definition: tkeyvfs.cc:1768
size_t db_size(sqlite3 *db)
std::string to_indented_string() const
vector< string > stringvec
bool get_if_present(std::string const &key, T &value) const
Definition: ParameterSet.h:208
int print_pset_from_file(TFile &file, stringvec const &filters, PsetType const mode, ostream &output, ostream &errors)
int print_psets_from_files(stringvec const &file_names, stringvec const &filters, PsetType const mode, ostream &output, ostream &errors)
std::string const & getFileFormatEra()
auto copy_all(FwdCont &, FwdIter)
int main(int argc, char *argv[])
PsetType
std::string db_size_hr(sqlite3 *db)
std::string want_pset(ParameterSet const &ps, stringvec const &filters, PsetType mode)
cet::LibraryManager dummy("noplugin")
bool erase(std::string const &key)
end
Definition: test.py:8
std::map< fhicl::ParameterSetID, ParameterSetBlob > ParameterSetMap
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
unsigned int run
static void importFrom(sqlite3 *db)