Teuchos Package Browser (Single Doxygen Collection) Version of the Day
Loading...
Searching...
No Matches
Teuchos_XMLPerfTestArchive.cpp
Go to the documentation of this file.
1// @HEADER
2// ***********************************************************************
3//
4// Teuchos: Common Tools Package
5// Copyright (2004) Sandia Corporation
6//
7// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8// license for use of this work by or on behalf of the U.S. Government.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions are
12// met:
13//
14// 1. Redistributions of source code must retain the above copyright
15// notice, this list of conditions and the following disclaimer.
16//
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// 3. Neither the name of the Corporation nor the names of the
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36//
37// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38//
39// ***********************************************************************
40// @HEADER
41
42
43#include <iostream>
44#include <fstream>
45#include <cstring>
46#include <cstdlib>
47#include <Teuchos_XMLObject.hpp>
50#ifdef _WIN32
51#include <winsock2.h>
52#else
53#include <unistd.h>
54#endif
55
56namespace Teuchos {
57
59 value = 0;
60 lower = 0;
61 upper = 0;
62 tolerance = 0;
63 use_tolerance = true;
64}
65
67 value = val;
68 lower = 0;
69 upper = 0;
70 tolerance = tol;
71 use_tolerance = true;
72}
73
74ValueTolerance::ValueTolerance(double val, double low, double up) {
75 value = val;
76 upper = up;
77 lower = low;
78 tolerance = 0;
79 use_tolerance = false;
80}
81
85
87 return (value == rhs.value) &&
88 (tolerance == rhs.tolerance) &&
89 (lower == rhs.lower) &&
90 (upper == rhs.upper) &&
91 (use_tolerance == rhs.use_tolerance);
92}
93
95 std::ostringstream strs;
97 strs << value << " , " << tolerance;
98 else
99 strs << value << " , " << lower << " , " << upper;
100 return strs.str();
101}
102
103void ValueTolerance::from_string(const std::string& valtol_str) {
104 std::string value_str = valtol_str.substr(0,valtol_str.find(","));
105 value = atof(value_str.c_str());
106 std::string tol_str = valtol_str.substr(valtol_str.find(",")+1);
107 if(tol_str.find(",")<=tol_str.length()) {
108 use_tolerance = false;
109 std::string lower_str = tol_str.substr(0,tol_str.find(","));
110 lower = atof(lower_str.c_str());
111 std::string upper_str = tol_str.substr(tol_str.find(",")+1);
112 upper = atof(upper_str.c_str());
113 } else {
114 use_tolerance = true;
115 tolerance = atof(tol_str.c_str());
116 }
117}
118
120
122
124
126
127 void XMLTestNode::addDouble (const std::string &name, double val) {
129 }
130
131 void XMLTestNode::addInt (const std::string &name, int val) {
133 }
134
135 void XMLTestNode::addBool (const std::string &name, bool val) {
137 }
138
139 void XMLTestNode::addValueTolerance(const std::string &name, ValueTolerance val){
140 addAttribute<std::string>(name,val.as_string());
141 }
142
143 void XMLTestNode::addString (const std::string &name, std::string val) {
145 }
146
147 bool XMLTestNode::hasChild(const std::string &name) const {
148 bool found = false;
149 for(int i = 0; i < numChildren(); i++) {
150 if(name.compare(XMLObject::getChild(i).getTag()) == 0) {
151 found = true;
152 i = numChildren();
153 }
154 }
155 return found;
156 }
157
158 void XMLTestNode::appendContentLine(const size_t& i, const std::string &str) {
159 ptr_->appendContentLine(i,str);
160 }
161
162 XMLTestNode XMLTestNode::getChild(const std::string &name) const {
164 for(int i = 0; i < numChildren(); i++) {
165 if(name.compare(XMLObject::getChild(i).getTag()) == 0)
167 }
168 return child;
169 }
170
172 return XMLObject::getChild(i);
173 }
174
176 return (XMLObject*) this;
177 }
178
180
181 if((numChildren()!=lhs.numChildren()) ||
182 (numContentLines()!= lhs.numContentLines()) ||
183 (getTag().compare(lhs.getTag())!=0)) return false;
184
185 for(int i = 0; i<numChildren(); i++) {
187 if( (!lhs.hasChild(child.getTag())) ||
188 (!child.hasSameElements(lhs.getChild(child.getTag()))) ) return false;
189 }
190
191 for(int i = 0; i<numContentLines(); i++)
192 if(getContentLine(i).compare(lhs.getContentLine(i))!=0) return false;
193
194 return true;
195 }
196
198
199 // Get CPUName, Number of Sockets, Number of Cores, Number of Hyperthreads
200 std::string cpuname("Undefined");
201 unsigned int threads = 0;
202 unsigned int cores_per_socket = 0;
203 unsigned int highest_socketid = 0;
204
205 {
206 std::ifstream cpuinfo("/proc/cpuinfo");
207 std::string line;
208 if((cpuinfo.rdstate()&cpuinfo.failbit)) std::cout<<"Failed to open filen\n";
209 while (!cpuinfo.eof() && !(cpuinfo.rdstate()&cpuinfo.failbit)) {
211 if (line.find("model name") < line.size()) {
212 cpuname = line.substr(line.find(":")+2);
213 threads++;
214 }
215 if (line.find("physical id") < line.size()) {
216 unsigned int socketid = atoi(line.substr(line.find(":")+2).c_str());
218 }
219 if (line.find("cpu cores") < line.size()) {
220 cores_per_socket = atoi(line.substr(line.find(":")+2).c_str());
221 }
222 }
223 }
224
225
226 XMLTestNode machine_config("MachineConfiguration");
227
228 machine_config.addString("Compiler", TEUCHOS_COMPILER_NAME);
229 machine_config.addInt("Compiler_Version", TEUCHOS_COMPILER_VERSION);
230 machine_config.addString("CPU_Name", cpuname);
231 machine_config.addInt("CPU_Sockets", highest_socketid+1);
232 machine_config.addInt("CPU_Cores_Per_Socket", cores_per_socket);
233 machine_config.addInt("CPU_Total_HyperThreads", threads);
234 return machine_config;
235}
236
240 const std::string filename,
241 const std::string ext_hostname)
242{
245 bool is_new_config = true;
246
247 // Open Database File
248 //
249 // FIXME (mfh 09 Apr 2014) This actually opens the file twice.
250 if (std::ifstream (filename.c_str ())) {
252 }
253
254 // Get Current Hostname
255 char hostname[256];
256 memset (hostname, 0, 256);
257 if (ext_hostname.empty ()) {
258 gethostname (hostname, 255);
259 } else {
260 strncat (hostname, ext_hostname.c_str (), 255);
261 }
262
263 XMLTestNode new_test_entry = new_test.getChild ("TestEntry");
264
265 if (database.isEmpty ()) {
266 database = XMLTestNode ("PerfTests");
267 }
268 // Does hostname exist?
269 if (database.hasChild (hostname)) {
271
272 // Find matching machine configuration
273 for (int i = 0; i < machine.numChildren (); ++i) {
274 XMLTestNode configuration = machine.getChild (i);
276 configuration.getTag ().compare ("Configuration") != 0,
277 std::runtime_error, "Unexpected Tag \"" << configuration.getTag ()
278 << "\"; only children with Tag = \"Configuration\" are allowed in a "
279 "MachineEntry.");
280
282 ! configuration.hasChild ("MachineConfiguration") ||
283 ! configuration.hasChild ("Tests"),
284 std::runtime_error,
285 "A Configuration needs to have a child \"MachineConfiguration\" and a "
286 "child \"Tests\".");
287
288 XMLTestNode machine_configuration = configuration.getChild ("MachineConfiguration");
289 XMLTestNode old_tests = configuration.getChild ("Tests");
290
291 if (machine_configuration.hasSameElements (machine_config)) {
292 is_new_config = false;
293
294 // Find existing test with same tag as the new test
295 if (old_tests.hasChild (new_test.getTag ())) {
296
298
299 int new_test_config = -1;
300 for (int k = 0; k < old_test.numChildren (); ++k) {
302
304 ! old_test_entry.hasChild ("TestConfiguration") ||
305 ! new_test_entry.hasChild ("TestResults"),
306 std::runtime_error, "A TestEntry needs to have a child "
307 "\"TestConfiguration\" and a child \"TestResults\".");
308
309 if (old_test_entry.getChild ("TestConfiguration").hasSameElements (new_test_entry.getChild ("TestConfiguration"))) {
311 }
312 }
313
314 if (new_test_config < 0) {
315 old_test.addChild (new_test_entry);
317 } else {
318 bool deviation = false;
320 XMLTestNode old_results = old_test_entry.getChild ("TestResults");
321 XMLTestNode new_results = new_test_entry.getChild ("TestResults");
322
323 // Compare all entries
324 for (int old_r = 0; old_r < old_results.numChildren (); ++old_r) {
326
327 // Finding entry with same name
328 bool exists = new_results.hasChild (result_entry.getTag ());
329
330 if (exists) {
331 std::string oldv_str = result_entry.getContentLine (0);
332
333 // If it is a time or result compare numeric values with tolerance
334 if((result_entry.getTag().find("Time")==0) || (result_entry.getTag().find("Result")==0)) {
336 ValueTolerance new_valtol(new_results.getChild(result_entry.getTag()).getContentLine(0));
337
338 if(old_valtol.use_tolerance) {
339 double diff = old_valtol.value - new_valtol.value;
340 diff*=diff;
341
342 double normalization = old_valtol.value;
344
345 if(normalization==0?diff>0:diff/normalization>old_valtol.tolerance*old_valtol.tolerance) {
346 deviation = true;
347 std::cout << std::endl
348 << "DeviationA in Test: \"" << old_test.getTag()
349 << "\" for entry \"" << result_entry.getTag() << "\"" << std::endl;
350 std::cout << " Existing Value: \"" << oldv_str << "\"" << std::endl;
351 std::cout << " New Value: \"" << new_results.getChild(result_entry.getTag()).getContentLine(0) << "\"" << std::endl << std::endl;
352 }
353 } else {
354 if( (old_valtol.lower>new_valtol.value) || (old_valtol.upper<new_valtol.value)) {
355 deviation = true;
356 std::cout << std::endl
357 << "DeviationB in Test: \"" << old_test.getTag()
358 << "\" for entry \"" << result_entry.getTag() << "\"" << std::endl;
359 std::cout << " Existing Value: \"" << oldv_str << "\"" << std::endl;
360 std::cout << " New Value: \"" << new_results.getChild(result_entry.getTag()).getContentLine(0) << "\"" << std::endl << std::endl;
361 }
362 }
363 } else {
364 // Compare exact match for every other type of entry
365 if(oldv_str.compare(new_results.getChild(result_entry.getTag()).getContentLine(0))!=0) {
366 deviation = true;
367 std::cout << std::endl
368 << "DeviationC in Test: \"" << old_test.getTag()
369 << "\" for entry \"" << result_entry.getTag() << "\"" << std::endl;
370 std::cout << " Existing Value: \"" << oldv_str << "\"" << std::endl;
371 std::cout << " New Value: \"" << new_results.getChild(result_entry.getTag()).getContentLine(0) << "\"" << std::endl << std::endl;
372 }
373 }
374 }
375 // An old value was not given in the new test: this is an error;
376 if(!exists) {
377 std::cout << "Error New test has same name as an existing one, but one of the old entries is missing." << std::endl;
378 deviation = true;
379 }
380 }
381
383 else {
384 // Did someone add new values to the test?
385 if(new_results.numChildren()!=old_results.numChildren()) {
386 for(int new_r = 0; new_r < new_results.numChildren() ; new_r++) {
387 if(!old_results.hasChild(new_results.getChild(new_r).getTag())) {
388 old_results.addChild(new_results.getChild(new_r));
389 }
390 }
391
393 }
394 }
395 }
396 } else { // End Test Exists
397 // Add new test if no match was found
398 old_tests.addChild(new_test);
400 }
401 } // End MachineConfiguration Exists
402 } // End loop over MachineConfigurations
403
404 // Did not find matching MachineConfiguration
405 if(is_new_config) {
406 XMLTestNode config("Configuration");
407 config.addChild(machine_config);
408 XMLTestNode tests("Tests");
409 tests.addChild(new_test);
410
411 config.addChild(tests);
412 machine.addChild(config);
413
415 }
416 } else { // Machine Entry does not exist
418
419 XMLTestNode config("Configuration");
420 config.addChild(machine_config);
421 XMLTestNode tests("Tests");
422 tests.addChild(new_test);
423 config.addChild(tests);
424
425 machine.addChild(config);
426
427 database.addChild(machine);
428
430 }
431
432
434 std::ofstream fout(filename.c_str());
435 fout << database << std::endl;
436 }
437
438 return return_value;
439}
440}
Definition of XMLInputSource derived class for reading XML from a file.
An object representation of a subset of XML data.
Tools for an XML-based performance test archive.
#define TEUCHOS_COMPILER_NAME
#define TEUCHOS_COMPILER_VERSION
int size(const Comm< Ordinal > &comm)
Get the number of processes in the communicator.
Instantiation of XMLInputSource class for reading XML from a file.
Concrete serial communicator subclass.
int getTag() const
The current tag.
XMLObject getObject() const
Get an object by invoking the TreeBuildingXMLHandler on the input data.
The XMLObjectImplem class takes care of the low-level implementation details of XMLObject.
Representation of an XML data tree. XMLObject is a ref-counted handle to a XMLObjectImplem object,...
RCP< XMLObjectImplem > ptr_
const std::string & getTag() const
Return the tag of the current node.
int numContentLines() const
Return the number of lines of character content stored in this node.
const XMLObject & getChild(int i) const
Return the i-th child node.
const std::string & getContentLine(int i) const
Return the i-th line of character content stored in this node.
int numChildren() const
Return the number of child nodes owned by this node.
Subclass of XMLObject used by the performance archive.
const XMLObject * xml_object() const
void addBool(const std::string &name, bool val)
bool hasSameElements(XMLTestNode const &lhs) const
void appendContentLine(const size_t &i, const std::string &str)
void addInt(const std::string &name, int val)
void addValueTolerance(const std::string &name, ValueTolerance val)
bool hasChild(const std::string &name) const
XMLTestNode getChild(const std::string &name) const
void addDouble(const std::string &name, double val)
void addString(const std::string &name, std::string val)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
XMLTestNode PerfTest_MachineConfig()
PerfTest_MachineConfig generates a basic machine configuration XMLTestNode.
PerfTestResult
ReturnValues for PerfTest_CheckOrAdd_Test.
PerfTestResult PerfTest_CheckOrAdd_Test(XMLTestNode machine_config, XMLTestNode new_test, const std::string filename, const std::string ext_hostname)
Check whether a test is present and match an existing test in an archive.
ValueTolerance is a struct to keep a tuple of value and a tolerance. The tolerance can be either expr...
void from_string(const std::string &valtol_str)
bool operator==(ValueTolerance &rhs)