HPCToolkit
ConfigParser.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 //************************ System Include Files ******************************
48 
49 #include <iostream>
50 using std::cerr;
51 using std::endl;
52 
53 #include <string>
54 using std::string;
55 
56 #ifdef NO_STD_CHEADERS
57 # include <stdlib.h>
58 #else
59 # include <cstdlib> // for 'exit'
60 using std::exit; // For compatibility with non-std C headers
61 #endif
62 
63 //*********************** Xerces Include Files *******************************
64 
65 #include <xercesc/util/XMLString.hpp>
66 using XERCES_CPP_NAMESPACE::XMLString;
67 
68 #include <xercesc/parsers/XercesDOMParser.hpp>
69 using XERCES_CPP_NAMESPACE::XercesDOMParser;
70 
71 #include <xercesc/dom/DOMNamedNodeMap.hpp>
72 using XERCES_CPP_NAMESPACE::DOMNamedNodeMap;
73 
74 
75 //************************* User Include Files *******************************
76 
77 #include <include/gcc-attr.h>
78 
79 #include "ConfigParser.hpp"
80 
82 
85 
86 #include <lib/support/Trace.hpp>
87 
88 
89 //************************ Forward Declarations ******************************
90 
91 #define DBG 0
92 
93 //****************************************************************************
94 
95 static void
97 
98 
99 //***************************************************************************
100 //
101 //***************************************************************************
102 
103 ConfigParser::ConfigParser(const string& inputFile,
104  XercesErrorHandler& errHndlr)
105 {
106  DIAG_DevMsgIf(DBG, "CONFIG: " << inputFile);
107 
108  m_parser = new XercesDOMParser;
109  m_parser->setValidationScheme(XercesDOMParser::Val_Auto);
110  m_parser->setErrorHandler(&errHndlr);
111  m_parser->parse(inputFile.c_str());
112  if (m_parser->getErrorCount() > 0) {
113  ConfigParser_Throw("terminating because of previously reported CONFIGURATION file parse errors.");
114  }
115 
116  m_doc = m_parser->getDocument();
117  DIAG_DevMsgIf(DBG, "CONFIG: "<< "document: " << m_doc);
118 }
119 
120 
122 {
123  delete m_parser;
124 }
125 
126 
127 void
129 {
130  ProcessDOCUMENT(m_doc, args, mMgr);
131 }
132 
133 
134 //***************************************************************************
135 //
136 //***************************************************************************
137 
138 static void ProcessHPCPROF(DOMNode *node, Analysis::Args& args, Prof::Metric::Mgr& mMgr);
139 static void ProcessELEMENT(DOMNode *node, Analysis::Args& args, Prof::Metric::Mgr& mMgr);
140 static void ProcessMETRIC(DOMNode *node, Analysis::Args& args, Prof::Metric::Mgr& mMgr);
141 static void ProcessFILE(DOMNode *fileNode, Analysis::Args& args, Prof::Metric::Mgr& mMgr,
142  const string& metricNm, bool metricDoDisp,
143  bool metricDoPercent, bool metricDoSortBy,
144  const string& metricDispNm);
145 
146 static Prof::Metric::AExpr*
147 makeMathMLExpr(const char* nm, DOMNode* mathMLExpr,
148  Prof::Metric::Mgr& mMgr);
149 
150 static string
151 getAttr(DOMNode *node, const XMLCh *attrName);
152 
153 static void
154 canonicalizePaths(string& inPath, string& outPath);
155 
156 static void GCC_ATTR_UNUSED
157 printName(DOMNode *node)
158 {
159  const XMLCh *nodeName = node->getNodeName();
160  const XMLCh *nodeValue = node->getNodeValue();
161  cerr << "name=" << XMLString::transcode(nodeName)
162  << " value=" << XMLString::transcode(nodeValue) << endl;
163 }
164 
165 
166 static void
168 {
169  DOMNode *child = node->getFirstChild();
170  ProcessHPCPROF(child, args, mMgr);
171 }
172 
173 
174 static void
176 {
177  DIAG_DevMsgIf(DBG, "CONFIG: " << node);
178 
179  if ((node == NULL) ||
180  (node->getNodeType() != DOMNode::DOCUMENT_TYPE_NODE)) {
181  ConfigParser_Throw("CONFIGURATION file does not begin with <HPCPROF>");
182  };
183 
184  node = node->getNextSibling();
185  DIAG_DevMsgIf(DBG, "CONFIG: " << node);
186 
187  if ((node == NULL)
188  || (node->getNodeType() != DOMNode::ELEMENT_NODE)) {
189  ConfigParser_Throw("No DOCUMENT_NODE found in CONFIGURATION file.");
190  };
191 
192  // process each child
193  DOMNode *child = node->getFirstChild();
194  for (; child != NULL; child = child->getNextSibling()) {
195  ProcessELEMENT(child, args, mMgr);
196  }
197 }
198 
199 
200 static void
202 {
203  static XMLCh* METRIC = XMLString::transcode("METRIC");
204  static XMLCh* PATH = XMLString::transcode("PATH");
205  static XMLCh* REPLACE = XMLString::transcode("REPLACE");
206  static XMLCh* TITLE = XMLString::transcode("TITLE");
207  static XMLCh* STRUCTURE = XMLString::transcode("STRUCTURE");
208  static XMLCh* GROUP = XMLString::transcode("GROUP");
209  static XMLCh* NAMEATTR = XMLString::transcode("name");
210  static XMLCh* VIEWNAMEATTR = XMLString::transcode("viewname");
211  static XMLCh* INATTR = XMLString::transcode("in");
212  static XMLCh* OUTATTR = XMLString::transcode("out");
213 
214  const XMLCh *nodeName = node->getNodeName();
215 
216  // Verify node type
217  if (node->getNodeType() == DOMNode::TEXT_NODE) {
218  return; // DTD ensures this can't contain anything but white space
219  }
220  else if (node->getNodeType() == DOMNode::COMMENT_NODE) {
221  return;
222  }
223  else if (node->getNodeType() != DOMNode::ELEMENT_NODE) {
224  ConfigParser_Throw("Unexpected XML object found: '" << XMLString::transcode(nodeName) << "'");
225  }
226 
227  // Parse ELEMENT nodes
228  if (XMLString::equals(nodeName, TITLE)) {
229  string title = getAttr(node, NAMEATTR);
230  DIAG_DevMsgIf(DBG, "CONFIG: " << "TITLE: " << title);
231  args.title = title;
232  }
233  else if (XMLString::equals(nodeName, PATH)) {
234  string path = getAttr(node, NAMEATTR);
235  string viewname = getAttr(node, VIEWNAMEATTR);
236  DIAG_DevMsgIf(DBG, "CONFIG: " << "PATH: " << path << ", v=" << viewname);
237 
238  if (path.empty()) {
239  ConfigParser_Throw("PATH name attribute cannot be empty.");
240  }
241  else if (args.db_copySrcFiles && viewname.empty()) {
242  ConfigParser_Throw("PATH '" << path << "': viewname attribute cannot be empty when source files are to be copied.");
243  } // there could be many other nefarious values of these attributes
244 
245  args.searchPathTpls.push_back(Analysis::PathTuple(path, viewname));
246  }
247  else if (XMLString::equals(nodeName, STRUCTURE)) {
248  string fnm = getAttr(node, NAMEATTR); // file name
249  DIAG_DevMsgIf(DBG, "CONFIG: " << "STRUCTURE file: " << fnm);
250 
251  if (fnm.empty()) {
252  ConfigParser_Throw("STRUCTURE file name is empty.");
253  }
254  else {
255  args.structureFiles.push_back(fnm);
256  }
257  }
258  else if (XMLString::equals(nodeName, GROUP)) {
259  string fnm = getAttr(node, NAMEATTR); // file name
260  DIAG_DevMsgIf(DBG, "CONFIG: " << "GROUP file: " << fnm);
261 
262  if (fnm.empty()) {
263  ConfigParser_Throw("GROUP file name is empty.");
264  }
265  else {
266  args.groupFiles.push_back(fnm);
267  }
268  }
269  else if (XMLString::equals(nodeName, REPLACE)) {
270  string inPath = getAttr(node, INATTR);
271  string outPath = getAttr(node, OUTATTR);
272  DIAG_DevMsgIf(DBG, "CONFIG: " << "REPLACE: " << inPath << " -to- " << outPath);
273 
274  bool addPath = true;
275  if (inPath == outPath) {
276  cerr << "WARNING: REPLACE: Identical 'in' and 'out' paths: '"
277  << inPath << "'! No action will be performed." << endl;
278  addPath = false;
279  }
280  else if (inPath.empty() && !outPath.empty()) {
281  cerr << "WARNING: REPLACE: 'in' path is empty; 'out' path '" << outPath
282  << "' will be prepended to every file path!" << endl;
283  }
284 
285  if (addPath) {
286  canonicalizePaths(inPath, outPath);
287  args.replaceInPath.push_back(inPath);
288  args.replaceOutPath.push_back(outPath);
289  }
290  }
291  else if (XMLString::equals(nodeName, METRIC)) {
292  ProcessMETRIC(node, args, mMgr);
293  }
294  else {
295  ConfigParser_Throw("Unexpected ELEMENT type encountered: '" << XMLString::transcode(nodeName) << "'");
296  }
297 }
298 
299 
300 static void
302 {
303  static XMLCh* FILE = XMLString::transcode("FILE");
304  static XMLCh* COMPUTE = XMLString::transcode("COMPUTE");
305  static XMLCh* NAMEATTR = XMLString::transcode("name");
306  static XMLCh* DISPLAYATTR = XMLString::transcode("display");
307  static XMLCh* PERCENTATTR = XMLString::transcode("percent");
308  //static XMLCh* PROPAGATEATTR = XMLString::transcode("propagate");
309  static XMLCh* DISPLAYNAMEATTR = XMLString::transcode("displayName");
310  static XMLCh* SORTBYATTR = XMLString::transcode("sortBy");
311 
312  // get metric attributes
313  string metricNm = getAttr(node, NAMEATTR);
314  string metricDispNm = getAttr(node, DISPLAYNAMEATTR);
315  bool metricDoDisp = (getAttr(node, DISPLAYATTR) == "true");
316  bool metricDoPercent = (getAttr(node,PERCENTATTR) == "true");
317  bool metricDoSortBy = (getAttr(node,SORTBYATTR) == "true");
318 
319  if (metricNm.empty()) {
320  ConfigParser_Throw("METRIC: Invalid name: '" << metricNm << "'.");
321  }
322  else if (mMgr.metric(metricNm) != NULL) {
323  ConfigParser_Throw("METRIC: Metric name '" << metricNm << "' was previously defined.");
324  }
325 
326  if (metricDispNm.empty()) {
327  ConfigParser_Throw("METRIC: Invalid displayName: '" << metricDispNm << "'.");
328  }
329 
330  DIAG_DevMsgIf(DBG, "CONFIG: " << "METRIC: name=" << metricNm
331  << " display=" << ((metricDoDisp) ? "true" : "false")
332  << " doPercent=" << ((metricDoPercent) ? "true" : "false")
333  << " sortBy=" << ((metricDoSortBy) ? "true" : "false")
334  << " metricDispNm=" << metricDispNm);
335 
336  // should have exactly one child
337  DOMNode* metricImpl = node->getFirstChild();
338 
339  for ( ; metricImpl != NULL; metricImpl = metricImpl->getNextSibling()) {
340 
341  if (metricImpl->getNodeType() == DOMNode::TEXT_NODE) {
342  // DTD ensures this can't contain anything but white space
343  continue;
344  }
345  else if (metricImpl->getNodeType() == DOMNode::COMMENT_NODE) {
346  continue;
347  }
348 
349  const XMLCh* metricType = metricImpl->getNodeName();
350 
351  if (XMLString::equals(metricType, FILE)) {
352 
353  ProcessFILE(metricImpl, args, mMgr, metricNm,
354  metricDoDisp, metricDoPercent, metricDoSortBy,
355  metricDispNm);
356  }
357  else if (XMLString::equals(metricType,COMPUTE)) {
358 
359  //bool propagateComputed = false; // tallent
360  // (getAttr(metricImpl, PROPAGATEATTR) == "computed");
361 
362  DOMNode* child = metricImpl->getFirstChild();
363  for (; child != NULL; child = child->getNextSibling()) {
364  if (child->getNodeType() == DOMNode::TEXT_NODE) {
365  // DTD ensures this can't contain anything but white space
366  continue;
367  }
368  else if (child->getNodeType() == DOMNode::COMMENT_NODE) {
369  continue;
370  }
371 
372  using namespace Prof;
373  Metric::AExpr* expr = makeMathMLExpr(metricNm.c_str(), child, mMgr);
374  mMgr.insert(new Metric::DerivedDesc(metricNm, metricNm, expr,
375  metricDoDisp, metricDoSortBy,
376  metricDoPercent,
377  false/*isPercent*/));
378  }
379  }
380  else {
381  ConfigParser_Throw("Unexpected METRIC type '" << XMLString::transcode(metricType) << "'.");
382  }
383  }
384 }
385 
386 
387 static Prof::Metric::AExpr*
388 makeMathMLExpr(const char* nm, DOMNode* mathMLExpr,
389  Prof::Metric::Mgr& mMgr)
390 {
391  Prof::Metric::AExpr* expr = NULL;
392 
393  try {
394  expr = MathMLExprParser::parse(mathMLExpr, mMgr);
395  }
396  catch (const MathMLExprException& e) {
397  DIAG_Throw("Could not construct METRIC '" << nm << "'. XML exception encountered when processing MathML expression: " << e.what() << ".");
398  }
399  catch (...) {
400  DIAG_Throw("Could not construct METRIC '" << nm << "'.");
401  }
402 
403  if (expr != NULL) {
404  DIAG_Msg(1, "Computed METRIC " << nm << ": " << nm << " = "
405  << expr->toString());
406  }
407 
408  return expr;
409 }
410 
411 
412 static void
413 ProcessFILE(DOMNode* fileNode,
415  const string& metricNm, bool metricDoDisp,
416  bool metricDoPercent, bool metricDoSortBy,
417  const string& GCC_ATTR_UNUSED metricDispNm)
418 {
419  static XMLCh* TYPEATTR = XMLString::transcode("type");
420  static XMLCh* NAMEATTR = XMLString::transcode("name");
421  static XMLCh* SELECTATTR = XMLString::transcode("select");
422 
423  string metricFile = getAttr(fileNode, NAMEATTR);
424  string metricFileType = getAttr(fileNode, TYPEATTR);
425  string nativeNm = getAttr(fileNode, SELECTATTR);
426 
427  if (nativeNm.empty()) {
428  // string error = "FILE: Invalid select attribute '" + nativeNm + "'";
429  // throw DocException(error);
430  // Default is to select "0"
431  nativeNm = "0";
432  }
433 
434  if (!metricFile.empty()) {
435  using namespace Prof;
436  mMgr.insert(new Metric::SampledDesc(metricNm, metricNm,
437  0/*period*/, true /*isUnitsEvents*/,
438  metricFile, nativeNm, metricFileType,
439  metricDoDisp, metricDoSortBy,
440  metricDoPercent));
441  }
442  else {
443  ConfigParser_Throw("METRIC '" << metricNm << "' FILE name empty.");
444  }
445 }
446 
447 // -------------------------------------------------------------------------
448 
449 // Returns the attribute value or an empty string if the attribute
450 // does not exist.
451 static string
452 getAttr(DOMNode *node, const XMLCh *attrName)
453 {
454  DOMNamedNodeMap* attributes = node->getAttributes();
455  DOMNode* attrNode = attributes->getNamedItem(attrName);
456  DIAG_DevMsgIf(DBG, "CONFIG: " << "getAttr(): attrNode" << attrNode);
457 
458  const XMLCh* attrNodeValue = NULL;
459  if (attrNode) {
460  attrNodeValue = attrNode->getNodeValue();
461  }
462  return make_string(attrNodeValue);
463 }
464 
465 // -------------------------------------------------------------------------
466 
467 static void
468 canonicalizePaths(string& inPath, string& outPath)
469 {
470  // Add a '/' at the end of the in path; it's good when testing for
471  // equality, to make sure that the last directory in the path is not
472  // a prefix of the tested path.
473  // If we need to add a '/' to the in path, then add one to the out
474  // path, too because when it is time to replace we don't know if we
475  // added one or not to the IN path.
476  if (!inPath.empty() && inPath[inPath.length()-1] != '/') {
477  inPath += '/';
478  outPath += '/';
479  }
480 }
481 
std::vector< std::string > groupFiles
Definition: Args.hpp:131
static void ProcessELEMENT(DOMNode *node, Analysis::Args &args, Prof::Metric::Mgr &mMgr)
PathTupleVec searchPathTpls
Definition: Args.hpp:125
DOMNode * m_doc
static void GCC_ATTR_UNUSED printName(DOMNode *node)
bool insert(Metric::ADesc *m)
Definition: Metric-Mgr.cpp:460
static Prof::Metric::AExpr * parse(DOMNode *mathMLExpr, const Prof::Metric::Mgr &mMgr)
virtual const std::string & what() const
Definition: Exception.hpp:126
std::vector< std::string > structureFiles
Definition: Args.hpp:128
cct_node_t * node
Definition: cct.c:128
virtual std::string toString() const
static std::string make_string(const XMLCh *const xmlStr)
Definition: XercesUtil.hpp:78
XercesDOMParser * m_parser
static void ProcessFILE(DOMNode *fileNode, Analysis::Args &args, Prof::Metric::Mgr &mMgr, const string &metricNm, bool metricDoDisp, bool metricDoPercent, bool metricDoSortBy, const string &metricDispNm)
static void ProcessDOCUMENT(DOMNode *node, Analysis::Args &args, Prof::Metric::Mgr &mMgr)
void parse(Analysis::Args &args, Prof::Metric::Mgr &metricMgr)
exit
Definition: names.cpp:1
std::vector< std::string > replaceInPath
Definition: Args.hpp:134
#define ConfigParser_Throw(streamArgs)
ConfigParser(const std::string &inputFile, XercesErrorHandler &errHndlr)
static string getAttr(DOMNode *node, const XMLCh *attrName)
#define DIAG_Msg(level,...)
Definition: diagnostics.h:241
static Prof::Metric::AExpr * makeMathMLExpr(const char *nm, DOMNode *mathMLExpr, Prof::Metric::Mgr &mMgr)
#define NULL
Definition: ElfHelper.cpp:85
static void ProcessHPCPROF(DOMNode *node, Analysis::Args &args, Prof::Metric::Mgr &mMgr)
std::string title
Definition: Args.hpp:121
static void ProcessMETRIC(DOMNode *node, Analysis::Args &args, Prof::Metric::Mgr &mMgr)
static void canonicalizePaths(string &inPath, string &outPath)
std::vector< std::string > replaceOutPath
Definition: Args.hpp:135
Metric::ADesc * metric(uint i)
Definition: Metric-Mgr.hpp:131
bool db_copySrcFiles
Definition: Args.hpp:200
#define GCC_ATTR_UNUSED
Definition: gcc-attr.h:80
std::pair< std::string, std::string > PathTuple
Definition: Args.hpp:82
#define DBG