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 //*************************** User Include Files ****************************
70 
71 #include <include/hpctoolkit-config.h>
72 
73 #include "Args.hpp"
74 
76 
77 //*************************** Forward Declarations **************************
78 
79 // Cf. DIAG_Die.
80 #define ARG_ERROR(streamArgs) \
81  { std::ostringstream WeIrDnAmE; \
82  WeIrDnAmE << streamArgs /*<< std::ends*/; \
83  printError(std::cerr, WeIrDnAmE.str()); \
84  exit(1); }
85 
86 //***************************************************************************
87 
88 static const char* version_info = HPCTOOLKIT_VERSION_STRING;
89 
90 static const char* usage_summary1 =
91 "[profiling-options] -- <command> [command-arguments]";
92 
93 static const char* usage_summary2 =
94 "[info-options]\n";
95 
96 static const char* usage_details = "\
97 hpcrun-flat profiles the execution of an arbitrary command <command> using\n\
98 statistical sampling (rather than instrumentation). It collects per-thread\n\
99 flat profiles, or IP (instruction pointer) histograms. Sample points may\n\
100 be generated from multiple simultaneous sampling sources. hpcrun-flat\n\
101 profiles complex applications that use forks, execs, and threads (but not\n\
102 dynamic linking/unlinking); it may be used in conjuction with parallel\n\
103 process launchers such as MPICH's mpiexec and SLURM's srun.\n\
104 \n\
105 To configure hpcrun's sampling sources, specify events and periods using\n\
106 the -e/--event option. For an event 'e' and period 'p', after every 'p'\n\
107 instances of 'e', a sample is generated that causes hpcrun to inspect the\n\
108 and record information about the monitored <command>.\n\
109 \n\
110 When <command> terminates, per-thread profiles are written to files with\n\
111 the names of the form:\n\
112  <command>.hpcrun-flat.<hostname>.<pid>.<tid>\n\
113 \n\
114 hpcrun-flat enables a user to abort a process and write the partial profiling\n\
115 data to disk by sending the Interrupt signal (INT or Ctrl-C). This can be\n\
116 extremely useful on long-running or misbehaving applications.\n\
117 \n\
118 The special option '--' can be used to stop hpcrun option parsing; this is\n\
119 especially useful when <command> takes arguments of its own.\n\
120 \n\
121 Options: Informational\n\
122  -l, --list-events-short\n\
123  List available events. (N.B.: some may not be\n\
124  profilable)\n\
125  -L, --list-events-long\n\
126  Similar to above but with more information.\n\
127  --paths Print paths for external PAPI and MONITOR.\n\
128  -V, --version Print version information.\n\
129  -h, --help Print help.\n\
130  --debug [<n>] Debug: use debug level <n>. {1}\n\
131 \n\
132 Options: Profiling (Defaults shown in curly brackets {})\n\
133  -r [<yes|no>], --recursive [<yes|no>]\n\
134  Profile processes spawned by <command>. {no} (Each\n\
135  process will receive its own output file.)\n\
136  -t <mode>, --threads <mode>\n\
137  Select thread profiling mode. {each}\n\
138  each: Separate profiles for each thread.\n\
139  all: Combined profiles of all threads.\n\
140  Only POSIX threads are supported; the WALLCLOCK event\n\
141  cannot be used in a multithreaded process.\n\
142  -e <event>[:<period>], --event <event>[:<period>]\n\
143  An event to profile and its corresponding sample\n\
144  period. <event> may be either a PAPI or native\n\
145  processor event. May pass multiple times.\n\
146  {PAPI_TOT_CYC:999999}.\n\
147  o Recommended: always specify sampling period.\n\
148  o Special event: WALLCLOCK (use once, without period)\n\
149  o Hardware and drivers limit possibilities.\n\
150  -o <outpath>, --output <outpath>\n\
151  Directory for output data {.}\n\
152  --papi-flag <flag>\n\
153  Profile style flag {PAPI_POSIX_PROFIL}\n\
154 \n\
155 NOTES:\n\
156 * hpcrun-flat uses preloaded shared libraries to initiate profiling. For\n\
157  this reason, it cannot be used to profile setuid programs.\n\
158 * For the same reason, it cannot profile statically linked applications.\n\
159 * Bug: hpcrun-flat cannot currently profile programs that themselves use\n\
160  preloading.\n\
161 ";
162 
163 
164 #define CLP CmdLineParser
165 
166 // Note: Changing the option name requires changing the name in Parse()
168  // Options: info
169  { 'l', "list-events-short", CLP::ARG_NONE, CLP::DUPOPT_CLOB, NULL, NULL },
170  { 'L', "list-events-long", CLP::ARG_NONE, CLP::DUPOPT_CLOB, NULL, NULL },
171  { 0 , "paths", CLP::ARG_NONE, CLP::DUPOPT_CLOB, NULL, NULL },
172 
173  // Options: profiling
174  { 'r', "recursive", CLP::ARG_OPT, CLP::DUPOPT_CLOB, NULL, NULL },
175  { 't', "threads", CLP::ARG_REQ, CLP::DUPOPT_CLOB, NULL, NULL },
176  { 'e', "event", CLP::ARG_REQ, CLP::DUPOPT_CAT, ";" , NULL },
177  { 'o', "output", CLP::ARG_REQ , CLP::DUPOPT_CLOB, NULL, NULL },
178  { 'f', "papi-flag", CLP::ARG_REQ , CLP::DUPOPT_CLOB, NULL, NULL },
179 
180  { 'V', "version", CLP::ARG_NONE, CLP::DUPOPT_CLOB, NULL, NULL },
181  { 'h', "help", CLP::ARG_NONE, CLP::DUPOPT_CLOB, NULL, NULL },
182  { 0 , "debug", CLP::ARG_OPT, CLP::DUPOPT_CLOB, NULL, NULL }, // hidden
183  CmdLineParser_OptArgDesc_NULL_MACRO // SGI's compiler requires this version
184 };
185 
186 #undef CLP
187 
188 
189 //***************************************************************************
190 // Args
191 //***************************************************************************
192 
193 Args::Args()
194 {
195  Ctor();
196 }
197 
198 
199 Args::Args(int argc, const char* const argv[])
200 {
201  Ctor();
202  parse(argc, argv);
203 }
204 
205 
206 void
207 Args::Ctor()
208 {
210  printPaths = false;
211 }
212 
213 
214 Args::~Args()
215 {
216 }
217 
218 
219 void
220 Args::printVersion(std::ostream& os) const
221 {
222  os << getCmd() << ": " << version_info << endl;
223 }
224 
225 
226 void
227 Args::printUsage(std::ostream& os) const
228 {
229  os << "Usage: \n"
230  << " " << getCmd() << " " << usage_summary1 << endl
231  << " " << getCmd() << " " << usage_summary2 << endl
232  << usage_details << endl;
233 }
234 
235 
236 void
237 Args::printError(std::ostream& os, const char* msg) const
238 {
239  os << getCmd() << ": " << msg << endl
240  << "Try '" << getCmd() << " --help' for more information." << endl;
241 }
242 
243 void
244 Args::printError(std::ostream& os, const std::string& msg) const
245 {
246  printError(os, msg.c_str());
247 }
248 
249 
250 const std::string&
251 Args::getCmd() const
252 {
253  return parser.getCmd();
254 }
255 
256 
257 void
258 Args::parse(int argc, const char* const argv[])
259 {
260  try {
261  bool requireCmd = true;
262 
263  // -------------------------------------------------------
264  // Parse the command line
265  // -------------------------------------------------------
266  parser.parse(optArgs, argc, argv);
267 
268  // -------------------------------------------------------
269  // Sift through results, checking for semantic errors
270  // -------------------------------------------------------
271 
272  // Special options that should be checked first
273  if (parser.isOpt("debug")) {
274  int dbg = 1;
275  if (parser.isOptArg("debug")) {
276  const string& arg = parser.getOptArg("debug");
277  dbg = (int)CmdLineParser::toLong(arg);
278  }
280  }
281  if (parser.isOpt("help")) {
282  printUsage(std::cerr);
283  exit(1);
284  }
285  if (parser.isOpt("version")) {
286  printVersion(std::cerr);
287  exit(1);
288  }
289 
290  // Check for informational options
291  if (parser.isOpt("list-events-short")) {
293  requireCmd = false;
294  }
295  if (parser.isOpt("list-events-long")) {
297  requireCmd = false;
298  }
299  if (parser.isOpt("paths")) {
300  printPaths = true;
301  requireCmd = false;
302  }
303 
304  // Check for profiling options
305  if (parser.isOpt("recursive")) {
306  if (parser.isOptArg("recursive")) {
307  const string& arg = parser.getOptArg("recursive");
308  if (arg == "no" || arg == "yes") {
309  profRecursive = arg;
310  }
311  else {
312  ARG_ERROR("Unexpected option argument '" << arg << "'");
313  }
314  }
315  else {
316  profRecursive = "no";
317  }
318  }
319  if (parser.isOpt("threads")) {
320  const string& arg = parser.getOptArg("threads");
321  if (arg == "each" || arg == "all") {
322  profThread = arg;
323  }
324  else {
325  ARG_ERROR("Unexpected option argument '" << arg << "'");
326  }
327  }
328  if (parser.isOpt("event")) {
329  profEvents = parser.getOptArg("event");
330  }
331  if (parser.isOpt("output")) {
332  profOutput = parser.getOptArg("output");
333  }
334  if (parser.isOpt("papi-flag")) {
335  profPAPIFlag = parser.getOptArg("papi-flag");
336  }
337 
338  // Check for required arguments: get <command> [command-arguments]
339  uint numArgs = parser.getNumArgs();
340  if (requireCmd && numArgs < 1) {
341  ARG_ERROR("Incorrect number of arguments: Missing <command> to profile.");
342  }
343 
344  profArgV.resize(numArgs);
345  for (uint i = 0; i < numArgs; ++i) {
346  profArgV[i] = parser.getArg(i);
347  }
348  }
349  catch (const CmdLineParser::ParseError& x) {
350  ARG_ERROR(x.what());
351  }
352  catch (const CmdLineParser::Exception& x) {
353  DIAG_EMsg(x.message());
354  exit(1);
355  }
356 }
357 
358 
359 void
360 Args::dump(std::ostream& os) const
361 {
362  os << "Args.cmd= " << getCmd() << endl;
363 }
364 
365 
366 void
367 Args::ddump() const
368 {
369  dump(std::cerr);
370 }
371 
372 
373 //***************************************************************************
~Args()
Definition: Args.cpp:173
bool isOpt(const char swShort) const
void printUsage(std::ostream &os) const
Definition: Args.cpp:186
const std::string & getOptArg(const char swShort) const
const std::string & getCmd() const
static const char * usage_details
Definition: Args.cpp:96
EventList_t listEvents
Definition: Args.hpp:111
#define DIAG_EMsg(...)
Definition: diagnostics.h:251
static const char * usage_summary1
Definition: Args.cpp:90
virtual const std::string & what() const
Definition: Exception.hpp:126
bool isOptArg(const char swShort) const
void Ctor()
Definition: Args.cpp:162
void parse(const OptArgDesc *optArgDescs, int argc, const char *const argv[])
CmdLineParser parser
Definition: Args.hpp:120
#define ARG_ERROR(streamArgs)
Definition: Args.cpp:80
std::string profThread
Definition: Args.hpp:116
unsigned int getNumArgs() const
void printVersion(std::ostream &os) const
Definition: Args.cpp:179
void parse(int argc, const char *const argv[])
Definition: Args.cpp:208
virtual std::string message() const
Definition: Exception.hpp:134
exit
Definition: names.cpp:1
unsigned int uint
Definition: uint.h:124
std::vector< std::string > profArgV
Definition: Args.hpp:122
std::string profOutput
Definition: Args.hpp:118
std::string profRecursive
Definition: Args.hpp:115
std::string profPAPIFlag
Definition: Args.hpp:119
Args()
Definition: Args.cpp:150
static const char * version_info
Definition: Args.cpp:88
void ddump() const
Definition: Args.cpp:305
#define CmdLineParser_OptArgDesc_NULL_MACRO
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
bool printPaths
Definition: Args.hpp:112
const std::string & getCmd() const
Definition: Args.hpp:102
static const char * usage_summary2
Definition: Args.cpp:93
std::string profEvents
Definition: Args.hpp:117
void dump(std::ostream &os=std::cerr) const
Definition: Args.cpp:296
static long toLong(const std::string &str)