HPCToolkit
Args.cpp
Go to the documentation of this file.
1 // -*-Mode: C++;-*-
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 //***************************************************************************
48 //
49 // File:
50 // $HeadURL$
51 //
52 // Purpose:
53 // [The purpose of this file]
54 //
55 // Description:
56 // [The set of functions, macros, etc. defined in the file]
57 //
58 //***************************************************************************
59 
60 //************************* System Include Files ****************************
61 
62 #include <iostream>
63 using std::cerr;
64 using std::endl;
65 
66 #include <string>
67 using std::string;
68 
69 #include <cstring> // strlen
70 
71 #include <dirent.h>
72 #include <sys/types.h>
73 
74 //*************************** User Include Files ****************************
75 
76 #include <include/hpctoolkit-config.h>
77 
78 #include "Args.hpp"
79 
80 #include <lib/analysis/Util.hpp>
81 
83 #include <lib/support/Trace.hpp>
84 #include <lib/support/StrUtil.hpp>
85 
86 //*************************** Forward Declarations **************************
87 
88 // Cf. DIAG_Die.
89 #define ARG_ERROR(streamArgs) \
90  { std::ostringstream WeIrDnAmE; \
91  WeIrDnAmE << streamArgs /*<< std::ends*/; \
92  printError(std::cerr, WeIrDnAmE.str()); \
93  exit(1); }
94 
95 //***************************************************************************
96 
97 const string Args::HPCTOOLKIT = "HPCTOOLKIT";
98 
99 static const char* version_info = HPCTOOLKIT_VERSION_STRING;
100 
101 static const char* usage_summary1 =
102 "[output-options] [correlation-options] <profile-file>...";
103 
104 static const char* usage_summary2 =
105 "[output-options] --config <config-file>\n";
106 
107 static const char* usage_details = "\
108 hpcprof-flat correlates flat profiling metrics with static source code\n\
109 structure and (by default) generates an Experiment database for use with\n\
110 hpcviewer. hpcprof-flat is invoked in one of two ways. In the former,\n\
111 correlation options are specified on the command line along with a list of\n\
112 flat profile files. In the latter, these options along with derived metrics\n\
113 are specified in the configuration file <config-file>. Note that the first\n\
114 mode is generally sufficient since derived metrics may be computed in\n\
115 hpcviewer. However, to facilitate the batch processing of the second mode,\n\
116 when run in the first mode, a sample configuration file (config.xml) is\n\
117 generated within the Experiment database.\n\
118 \n\
119 For optimal results, structure information from hpcstruct should be provided.\n\
120 Without structure information, hpcprof-flat will default to correlation using\n\
121 line map information.\n\
122 \n\
123 \n\
124 Options: General:\n\
125  -v [<n>], --verbose [<n>]\n\
126  Verbose: generate progress messages to stderr at\n\
127  verbosity level <n>. {1} (Use n=3 to debug path\n\
128  replacement if metric and program structure is not\n\
129  properly matched.)\n\
130  -V, --version Print version information.\n\
131  -h, --help Print help.\n\
132  --debug [<n>] Debug: use debug level <n>. {1}\n\
133 \n\
134 Options: Source Structure Correlation:\n\
135  --name <name>, --title <name>\n\
136  Set the database's name (title) to <name>.\n\
137  -I <path>, --include <path>\n\
138  Use <path> when searching for source files. For a\n\
139  recursive search, append a '*' after the last slash,\n\
140  e.g., '/mypath/*' (quote or escape to protect from\n\
141  the shell.) May pass multiple times.\n\
142  -S <file>, --structure <file>\n\
143  Use hpcstruct structure file <file> for correlation.\n\
144  May pass multiple times (e.g., for shared libraries).\n\
145  -R '<old-path>=<new-path>', --replace-path '<old-path>=<new-path>'\n\
146  Substitute instances of <old-path> with <new-path>;\n\
147  apply to all paths (profile's load map, source code)\n\
148  for which <old-path> is a prefix. Use '\\' to escape\n\
149  instances of '=' within a path. May pass multiple\n\
150  times.\n\
151 \n\
152 Options: Output:\n\
153  -o <db-path>, --db <db-path>, --output <db-path>\n\
154  Specify Experiment database name <db-path>.\n\
155  {./"Analysis_DB_DIR"}\n\
156  --src [yes|no], --source [yes|no]\n\
157  Whether to copy source code files into Experiment\n\
158  database. {yes} By default, hpcprof-flat copies source\n\
159  files with performance metrics and that can be\n\
160  reached by PATH/REPLACE statements, resulting in a\n\
161  self-contained dataset that does not rely on an\n\
162  external source code repository. Note that if\n\
163  copying is suppressed, the database is no longer\n\
164  self-contained.\n\
165 \n\
166 Output formats: Select different output formats and optionally specify the\n\
167 output filename <file> (located within the Experiment database). The output\n\
168 is sparse in the sense that it ignores program areas without profiling\n\
169 information. (Set <file> to '-' to write to stdout.)\n\
170  -x [<file>], --experiment [<file>]\n\
171  Default. ExperimentXML format. {"Analysis_OUT_DB_EXPERIMENT"}\n\
172  NOTE: To disable, set <file> to 'no'.\n";
173 
174 // FIXME: tallent: do we want this?
175 //--csv [<file>] Comma-separated-value format. {"Analysis_OUT_DB_CSV"}\n
176 // Includes flat scope tree and loops. Useful for\n
177 // downstream external tools.\n";
178 
179 
180 #define CLP CmdLineParser
181 #define CLP_SEPARATOR "!!!"
182 
183 // Note: Changing the option name requires changing the name in Parse()
185  // Config-file-mode
186  { 0 , "config", CLP::ARG_REQ, CLP::DUPOPT_CLOB, NULL,
187  NULL },
188 
189  // Source structure correlation options
190  { 0 , "name", CLP::ARG_REQ, CLP::DUPOPT_CLOB, CLP_SEPARATOR,
191  NULL },
192  { 0 , "title", CLP::ARG_REQ, CLP::DUPOPT_CLOB, CLP_SEPARATOR,
193  NULL },
194 
195  { 'I', "include", CLP::ARG_REQ, CLP::DUPOPT_CAT, CLP_SEPARATOR,
196  NULL },
197  { 'S', "structure", CLP::ARG_REQ, CLP::DUPOPT_CAT, CLP_SEPARATOR,
198  NULL },
199  { 'R', "replace-path", CLP::ARG_REQ, CLP::DUPOPT_CAT, CLP_SEPARATOR,
200  NULL},
201 
202  // Output options
203  { 'o', "output", CLP::ARG_REQ , CLP::DUPOPT_CLOB, NULL,
204  NULL },
205  { 0 , "db", CLP::ARG_REQ , CLP::DUPOPT_CLOB, NULL,
206  NULL },
207 
208  { 0 , "src", CLP::ARG_OPT, CLP::DUPOPT_CLOB, NULL,
209  NULL },
210  { 0 , "source", CLP::ARG_OPT, CLP::DUPOPT_CLOB, NULL,
211  NULL },
212 
213  // Output formats
214  { 'x', "experiment", CLP::ARG_OPT, CLP::DUPOPT_CLOB, NULL,
215  NULL },
216  { 0 , "csv", CLP::ARG_OPT, CLP::DUPOPT_CLOB, NULL,
217  NULL },
218 
219  // General
220  { 'v', "verbose", CLP::ARG_OPT, CLP::DUPOPT_CLOB, NULL,
221  CLP::isOptArg_long },
222  { 'V', "version", CLP::ARG_NONE, CLP::DUPOPT_CLOB, NULL,
223  NULL },
224  { 'h', "help", CLP::ARG_NONE, CLP::DUPOPT_CLOB, NULL,
225  NULL },
226  { 0 , "debug", CLP::ARG_OPT, CLP::DUPOPT_CLOB, NULL, // hidden
227  CLP::isOptArg_long },
228  CmdLineParser_OptArgDesc_NULL_MACRO // SGI's compiler requires this version
229 };
230 
231 #undef CLP
232 
233 
234 //***************************************************************************
235 // Args
236 //***************************************************************************
237 
238 Args::Args()
239 {
240  Ctor();
241 }
242 
243 
244 Args::Args(int argc, const char* const argv[])
245 {
246  Ctor();
247  parse(argc, argv);
248 }
249 
250 
251 void
252 Args::Ctor()
253 {
254  setHPCHome();
256 
257  configurationFileMode = false;
258 
259  // Analysis::ArgsA
261 }
262 
263 
264 Args::~Args()
265 {
266 }
267 
268 
269 void
270 Args::printVersion(std::ostream& os) const
271 {
272  os << getCmd() << ": " << version_info << endl;
273 }
274 
275 
276 void
277 Args::printUsage(std::ostream& os) const
278 {
279  os << "Usage: \n"
280  << " " << getCmd() << " " << usage_summary1 << endl
281  << " " << getCmd() << " " << usage_summary2 << endl
282  << usage_details << endl;
283 }
284 
285 
286 void
287 Args::printError(std::ostream& os, const char* msg) const
288 {
289  os << getCmd() << ": " << msg << endl
290  << "Try '" << getCmd() << " --help' for more information." << endl;
291 }
292 
293 void
294 Args::printError(std::ostream& os, const std::string& msg) const
295 {
296  printError(os, msg.c_str());
297 }
298 
299 
300 const std::string&
301 Args::getCmd() const
302 {
303  // avoid error messages with: .../bin/hpcprof-flat-bin
304  static string cmd = "hpcprof-flat";
305  return cmd; // parser.getCmd();
306 }
307 
308 
309 void
310 Args::parse(int argc, const char* const argv[])
311 {
312  try {
313  // -------------------------------------------------------
314  // Parse the command line
315  // -------------------------------------------------------
316  parser.parse(optArgs, argc, argv);
317 
318  // -------------------------------------------------------
319  // Sift through results, checking for semantic errors
320  // -------------------------------------------------------
321 
322  // Special options that should be checked first
323  if (parser.isOpt("debug")) {
324  int dbg = 1;
325  if (parser.isOptArg("debug")) {
326  const string& arg = parser.getOptArg("debug");
327  dbg = (int)CmdLineParser::toLong(arg);
328  }
330  trace = dbg;
331  }
332  if (parser.isOpt("help")) {
333  printUsage(std::cerr);
334  exit(1);
335  }
336  if (parser.isOpt("version")) {
337  printVersion(std::cerr);
338  exit(1);
339  }
340  if (parser.isOpt("verbose")) {
341  int verb = 1;
342  if (parser.isOptArg("verbose")) {
343  const string& arg = parser.getOptArg("verbose");
344  verb = (int)CmdLineParser::toLong(arg);
345  }
347  }
348 
349  // Check for Config-file-mode:
350  if (parser.isOpt("config")) {
351  configurationFile = parser.getOptArg("config");
352  }
354 
355  if (!configurationFileMode) {
356  out_db_config = "config.xml"; // Analysis::Args
357  }
358 
359  // Check for other options: Correlation options
360  if (parser.isOpt("name")) {
361  title = parser.getOptArg("name");
362  }
363  if (parser.isOpt("title")) {
364  title = parser.getOptArg("title");
365  }
366  if (parser.isOpt("include")) {
367  string str = parser.getOptArg("include");
368 
369  std::vector<std::string> searchPaths;
370  StrUtil::tokenize_str(str, CLP_SEPARATOR, searchPaths);
371 
372  for (uint i = 0; i < searchPaths.size(); ++i) {
373  searchPathTpls.push_back(Analysis::PathTuple(searchPaths[i],
375  }
376  }
377  if (parser.isOpt("structure")) {
378  string str = parser.getOptArg("structure");
380  }
381 
382  if (parser.isOpt("replace-path")) {
383  string arg = parser.getOptArg("replace-path");
384 
385  std::vector<std::string> replacePaths;
386  StrUtil::tokenize_str(arg,CLP_SEPARATOR, replacePaths);
387 
388  for (uint i = 0; i < replacePaths.size(); ++i) {
389  int occurancesOfEquals =
390  Analysis::Util::parseReplacePath(replacePaths[i]);
391 
392  if (occurancesOfEquals > 1) {
393  ARG_ERROR("Too many occurances of \'=\'; make sure to escape any \'=\' in your paths");
394  }
395  else if(occurancesOfEquals == 0) {
396  ARG_ERROR("The \'=\' between the old path and new path is missing");
397  }
398  }
399  }
400 
401  // Check for other options: Output options
402  if (parser.isOpt("output")) {
403  db_dir = parser.getOptArg("output");
404  }
405  if (parser.isOpt("db")) {
406  db_dir = parser.getOptArg("db");
407  }
408 
409  if (parser.isOpt("source") || parser.isOpt("src")) {
410  string opt;
411  if (parser.isOptArg("source")) { opt = parser.getOptArg("source"); }
412  else if (parser.isOptArg("src")) { opt = parser.getOptArg("src"); }
413  db_copySrcFiles = (opt != "no");
414  }
415 
416  // Check for other options: Output formats
417  if (parser.isOpt("experiment")) {
419  if (parser.isOptArg("experiment")) {
420  out_db_experiment = parser.getOptArg("experiment");
421  }
422  if (out_db_experiment == "no") { // special case
423  out_db_experiment = "";
424  }
425  }
426  if (parser.isOpt("csv")) {
428  if (parser.isOptArg("csv")) {
429  out_db_csv = parser.getOptArg("csv");
430  }
431  db_copySrcFiles = false;
432  }
433 
434  // Check for required arguments
435  uint numArgs = parser.getNumArgs();
436  if (configurationFileMode) {
437  if (numArgs != 0) {
438  ARG_ERROR("Incorrect number of arguments!");
439  }
440  }
441  else {
442  if ( !(numArgs >= 1) ) {
443  ARG_ERROR("Incorrect number of arguments!");
444  }
445 
446  profileFiles.resize(numArgs);
447  for (uint i = 0; i < numArgs; ++i) {
448  profileFiles[i] = parser.getArg(i);
449  }
450  }
451 
452  }
453  catch (const CmdLineParser::ParseError& x) {
454  ARG_ERROR(x.what());
455  }
456  catch (const CmdLineParser::Exception& x) {
457  DIAG_EMsg(x.message());
458  exit(1);
459  }
460 }
461 
462 
463 void
464 Args::dump(std::ostream& os) const
465 {
466  os << "Args.cmd= " << getCmd() << endl;
467  os << "Args.hpcHome= " << hpcHome << endl;
468  os << "::trace " << ::trace << endl;
470 }
471 
472 
473 //***************************************************************************
474 
475 void
477 {
478  char * home = getenv(HPCTOOLKIT.c_str());
479  if (home == NULL) {
480  cerr << "Error: Please set your " << HPCTOOLKIT << " environment variable."
481  << endl;
482  exit(1);
483  }
484 
485  // chop of trailing slashes
486  int len = strlen(home);
487  if (home[len-1] == '/') home[--len] = 0;
488 
489  DIR *fp = opendir(home);
490  if (fp == NULL) {
491  cerr << "Error: " << home << " is not a directory" << endl;
492  exit(1);
493  }
494  closedir(fp);
495  hpcHome = home;
496 }
~Args()
Definition: Args.cpp:173
bool isOpt(const char swShort) const
PathTupleVec searchPathTpls
Definition: Args.hpp:125
std::string db_dir
Definition: Args.hpp:199
void printUsage(std::ostream &os) const
Definition: Args.cpp:186
const std::string & getOptArg(const char swShort) const
#define ARG_ERROR(streamArgs)
Definition: Args.cpp:89
static const char * version_info
Definition: Args.cpp:99
int parseReplacePath(const std::string &arg)
Definition: Util.cpp:242
#define DIAG_EMsg(...)
Definition: diagnostics.h:251
static const char * usage_summary2
Definition: Args.cpp:104
void setHPCHome()
Definition: Args.cpp:476
virtual const std::string & what() const
Definition: Exception.hpp:126
std::vector< std::string > structureFiles
Definition: Args.hpp:128
bool isOptArg(const char swShort) const
void Ctor()
Definition: Args.cpp:162
bool profflat_computeFinalMetricValues
Definition: Args.hpp:182
void parse(const OptArgDesc *optArgDescs, int argc, const char *const argv[])
CmdLineParser parser
Definition: Args.hpp:120
bool configurationFileMode
Definition: Args.hpp:117
unsigned int getNumArgs() const
void printVersion(std::ostream &os) const
Definition: Args.cpp:179
#define Analysis_OUT_DB_CSV
Definition: Args.hpp:189
void parse(int argc, const char *const argv[])
Definition: Args.cpp:208
void tokenize_str(const std::string &tokenstr, const char *delim, std::vector< std::string > &tokenvec)
Definition: StrUtil.cpp:122
std::string out_db_experiment
Definition: Args.hpp:196
virtual void dump(std::ostream &os=std::cerr) const
Definition: Args.cpp:144
virtual std::string message() const
Definition: Exception.hpp:134
exit
Definition: names.cpp:1
unsigned int uint
Definition: uint.h:124
std::string configurationFile
Definition: Args.hpp:118
int trace
Definition: Trace.cpp:57
static const char * usage_summary1
Definition: Args.cpp:101
std::string out_db_config
Definition: Args.hpp:202
Args()
Definition: Args.cpp:150
#define Analysis_DB_DIR
Definition: Args.hpp:193
#define Analysis_OUT_DB_EXPERIMENT
Definition: Args.hpp:188
const std::string DefaultPathTupleTarget
Definition: Args.hpp:85
#define CmdLineParser_OptArgDesc_NULL_MACRO
std::vector< std::string > profileFiles
Definition: Args.hpp:138
static const char * usage_details
Definition: Args.cpp:107
void printError(std::ostream &os, const char *msg) const
Definition: Args.cpp:194
void Diagnostics_SetDiagnosticFilterLevel(int lvl)
Definition: diagnostics.cpp:80
static CmdLineParser::OptArgDesc optArgs[]
Definition: Args.hpp:119
const std::string & getArg(unsigned int i) const
#define NULL
Definition: ElfHelper.cpp:85
static const std::string HPCTOOLKIT
Definition: Args.hpp:125
std::string title
Definition: Args.hpp:121
std::string hpcHome
Definition: Args.hpp:111
bool db_copySrcFiles
Definition: Args.hpp:200
const std::string & getCmd() const
Definition: Args.hpp:102
#define CLP_SEPARATOR
Definition: Args.cpp:181
void dump(std::ostream &os=std::cerr) const
Definition: Args.cpp:296
std::pair< std::string, std::string > PathTuple
Definition: Args.hpp:82
static long toLong(const std::string &str)
std::string out_db_csv
Definition: Args.hpp:197