Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
Teuchos_XMLPerfTestArchive.cpp
1// @HEADER
2// *****************************************************************************
3// Teuchos: Common Tools Package
4//
5// Copyright 2004 NTESS and the Teuchos contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#include <iostream>
11#include <fstream>
12#include <cstring>
13#include <cstdlib>
14#include <Teuchos_XMLObject.hpp>
17#ifdef _WIN32
18#include <winsock2.h>
19#else
20#include <unistd.h>
21#endif
22
23namespace Teuchos {
24
25ValueTolerance::ValueTolerance() {
26 value = 0;
27 lower = 0;
28 upper = 0;
29 tolerance = 0;
30 use_tolerance = true;
31}
32
33ValueTolerance::ValueTolerance(double val, double tol) {
34 value = val;
35 lower = 0;
36 upper = 0;
37 tolerance = tol;
38 use_tolerance = true;
39}
40
41ValueTolerance::ValueTolerance(double val, double low, double up) {
42 value = val;
43 upper = up;
44 lower = low;
45 tolerance = 0;
46 use_tolerance = false;
47}
48
49ValueTolerance::ValueTolerance(std::string str) {
50 from_string(str);
51}
52
53bool ValueTolerance::operator ==(ValueTolerance& rhs) {
54 return (value == rhs.value) &&
55 (tolerance == rhs.tolerance) &&
56 (lower == rhs.lower) &&
57 (upper == rhs.upper) &&
58 (use_tolerance == rhs.use_tolerance);
59}
60
61std::string ValueTolerance::as_string(){
62 std::ostringstream strs;
63 if(use_tolerance)
64 strs << value << " , " << tolerance;
65 else
66 strs << value << " , " << lower << " , " << upper;
67 return strs.str();
68}
69
70void ValueTolerance::from_string(const std::string& valtol_str) {
71 std::string value_str = valtol_str.substr(0,valtol_str.find(","));
72 value = atof(value_str.c_str());
73 std::string tol_str = valtol_str.substr(valtol_str.find(",")+1);
74 if(tol_str.find(",")<=tol_str.length()) {
75 use_tolerance = false;
76 std::string lower_str = tol_str.substr(0,tol_str.find(","));
77 lower = atof(lower_str.c_str());
78 std::string upper_str = tol_str.substr(tol_str.find(",")+1);
79 upper = atof(upper_str.c_str());
80 } else {
81 use_tolerance = true;
82 tolerance = atof(tol_str.c_str());
83 }
84}
85
86 XMLTestNode::XMLTestNode():XMLObject() {}
87
88 XMLTestNode::XMLTestNode(const std::string &tag):XMLObject(tag) {}
89
90 XMLTestNode::XMLTestNode(XMLObjectImplem *ptr):XMLObject(ptr) {}
91
92 XMLTestNode::XMLTestNode(XMLObject obj):XMLObject(obj) {}
93
94 void XMLTestNode::addDouble (const std::string &name, double val) {
95 addAttribute<double>(name,val);
96 }
97
98 void XMLTestNode::addInt (const std::string &name, int val) {
99 addAttribute<int>(name,val);
100 }
101
102 void XMLTestNode::addBool (const std::string &name, bool val) {
103 addAttribute<bool>(name,val);
104 }
105
106 void XMLTestNode::addValueTolerance(const std::string &name, ValueTolerance val){
107 addAttribute<std::string>(name,val.as_string());
108 }
109
110 void XMLTestNode::addString (const std::string &name, std::string val) {
111 addAttribute<std::string>(name,val);
112 }
113
114 bool XMLTestNode::hasChild(const std::string &name) const {
115 bool found = false;
116 for(int i = 0; i < numChildren(); i++) {
117 if(name.compare(XMLObject::getChild(i).getTag()) == 0) {
118 found = true;
119 i = numChildren();
120 }
121 }
122 return found;
123 }
124
125 void XMLTestNode::appendContentLine(const size_t& i, const std::string &str) {
126 ptr_->appendContentLine(i,str);
127 }
128
129 XMLTestNode XMLTestNode::getChild(const std::string &name) const {
130 XMLTestNode child;
131 for(int i = 0; i < numChildren(); i++) {
132 if(name.compare(XMLObject::getChild(i).getTag()) == 0)
133 child = XMLObject::getChild(i);
134 }
135 return child;
136 }
137
138 XMLTestNode XMLTestNode::getChild(const int &i) const {
139 return XMLObject::getChild(i);
140 }
141
142 const XMLObject* XMLTestNode::xml_object() const {
143 return (XMLObject*) this;
144 }
145
146 bool XMLTestNode::hasSameElements(XMLTestNode const & lhs) const {
147
148 if((numChildren()!=lhs.numChildren()) ||
149 (numContentLines()!= lhs.numContentLines()) ||
150 (getTag().compare(lhs.getTag())!=0)) return false;
151
152 for(int i = 0; i<numChildren(); i++) {
153 const XMLTestNode child = XMLObject::getChild(i);
154 if( (!lhs.hasChild(child.getTag())) ||
155 (!child.hasSameElements(lhs.getChild(child.getTag()))) ) return false;
156 }
157
158 for(int i = 0; i<numContentLines(); i++)
159 if(getContentLine(i).compare(lhs.getContentLine(i))!=0) return false;
160
161 return true;
162 }
163
165
166 // Get CPUName, Number of Sockets, Number of Cores, Number of Hyperthreads
167 std::string cpuname("Undefined");
168 unsigned int threads = 0;
169 unsigned int cores_per_socket = 0;
170 unsigned int highest_socketid = 0;
171
172 {
173 std::ifstream cpuinfo("/proc/cpuinfo");
174 std::string line;
175 if((cpuinfo.rdstate()&cpuinfo.failbit)) std::cout<<"Failed to open filen\n";
176 while (!cpuinfo.eof() && !(cpuinfo.rdstate()&cpuinfo.failbit)) {
177 getline (cpuinfo,line);
178 if (line.find("model name") < line.size()) {
179 cpuname = line.substr(line.find(":")+2);
180 threads++;
181 }
182 if (line.find("physical id") < line.size()) {
183 unsigned int socketid = atoi(line.substr(line.find(":")+2).c_str());
185 }
186 if (line.find("cpu cores") < line.size()) {
187 cores_per_socket = atoi(line.substr(line.find(":")+2).c_str());
188 }
189 }
190 }
191
192
193 XMLTestNode machine_config("MachineConfiguration");
194
195 machine_config.addString("Compiler", TEUCHOS_COMPILER_NAME);
196 machine_config.addInt("Compiler_Version", TEUCHOS_COMPILER_VERSION);
197 machine_config.addString("CPU_Name", cpuname);
198 machine_config.addInt("CPU_Sockets", highest_socketid+1);
199 machine_config.addInt("CPU_Cores_Per_Socket", cores_per_socket);
200 machine_config.addInt("CPU_Total_HyperThreads", threads);
201 return machine_config;
202}
203
204PerfTestResult
207 const std::string filename,
208 const std::string ext_hostname)
209{
211 PerfTestResult return_value = PerfTestPassed;
212 bool is_new_config = true;
213
214 // Open Database File
215 //
216 // FIXME (mfh 09 Apr 2014) This actually opens the file twice.
217 if (std::ifstream (filename.c_str ())) {
219 }
220
221 // Get Current Hostname
222 char hostname[256];
223 memset (hostname, 0, 256);
224 if (ext_hostname.empty ()) {
225 gethostname (hostname, 255);
226 } else {
227 strncat (hostname, ext_hostname.c_str (), 255);
228 }
229
230 XMLTestNode new_test_entry = new_test.getChild ("TestEntry");
231
232 if (database.isEmpty ()) {
233 database = XMLTestNode ("PerfTests");
234 }
235 // Does hostname exist?
236 if (database.hasChild (hostname)) {
238
239 // Find matching machine configuration
240 for (int i = 0; i < machine.numChildren (); ++i) {
241 XMLTestNode configuration = machine.getChild (i);
243 configuration.getTag ().compare ("Configuration") != 0,
244 std::runtime_error, "Unexpected Tag \"" << configuration.getTag ()
245 << "\"; only children with Tag = \"Configuration\" are allowed in a "
246 "MachineEntry.");
247
249 ! configuration.hasChild ("MachineConfiguration") ||
250 ! configuration.hasChild ("Tests"),
251 std::runtime_error,
252 "A Configuration needs to have a child \"MachineConfiguration\" and a "
253 "child \"Tests\".");
254
255 XMLTestNode machine_configuration = configuration.getChild ("MachineConfiguration");
256 XMLTestNode old_tests = configuration.getChild ("Tests");
257
258 if (machine_configuration.hasSameElements (machine_config)) {
259 is_new_config = false;
260
261 // Find existing test with same tag as the new test
262 if (old_tests.hasChild (new_test.getTag ())) {
263
264 XMLTestNode old_test = old_tests.getChild (new_test.getTag ());
265
266 int new_test_config = -1;
267 for (int k = 0; k < old_test.numChildren (); ++k) {
269
271 ! old_test_entry.hasChild ("TestConfiguration") ||
272 ! new_test_entry.hasChild ("TestResults"),
273 std::runtime_error, "A TestEntry needs to have a child "
274 "\"TestConfiguration\" and a child \"TestResults\".");
275
276 if (old_test_entry.getChild ("TestConfiguration").hasSameElements (new_test_entry.getChild ("TestConfiguration"))) {
278 }
279 }
280
281 if (new_test_config < 0) {
282 old_test.addChild (new_test_entry);
283 return_value = PerfTestNewTestConfiguration;
284 } else {
285 bool deviation = false;
287 XMLTestNode old_results = old_test_entry.getChild ("TestResults");
288 XMLTestNode new_results = new_test_entry.getChild ("TestResults");
289
290 // Compare all entries
291 for (int old_r = 0; old_r < old_results.numChildren (); ++old_r) {
293
294 // Finding entry with same name
295 bool exists = new_results.hasChild (result_entry.getTag ());
296
297 if (exists) {
298 std::string oldv_str = result_entry.getContentLine (0);
299
300 // If it is a time or result compare numeric values with tolerance
301 if((result_entry.getTag().find("Time")==0) || (result_entry.getTag().find("Result")==0)) {
303 ValueTolerance new_valtol(new_results.getChild(result_entry.getTag()).getContentLine(0));
304
305 if(old_valtol.use_tolerance) {
306 double diff = old_valtol.value - new_valtol.value;
307 diff*=diff;
308
309 double normalization = old_valtol.value;
311
312 if(normalization==0?diff>0:diff/normalization>old_valtol.tolerance*old_valtol.tolerance) {
313 deviation = true;
314 std::cout << std::endl
315 << "DeviationA in Test: \"" << old_test.getTag()
316 << "\" for entry \"" << result_entry.getTag() << "\"" << std::endl;
317 std::cout << " Existing Value: \"" << oldv_str << "\"" << std::endl;
318 std::cout << " New Value: \"" << new_results.getChild(result_entry.getTag()).getContentLine(0) << "\"" << std::endl << std::endl;
319 }
320 } else {
321 if( (old_valtol.lower>new_valtol.value) || (old_valtol.upper<new_valtol.value)) {
322 deviation = true;
323 std::cout << std::endl
324 << "DeviationB in Test: \"" << old_test.getTag()
325 << "\" for entry \"" << result_entry.getTag() << "\"" << std::endl;
326 std::cout << " Existing Value: \"" << oldv_str << "\"" << std::endl;
327 std::cout << " New Value: \"" << new_results.getChild(result_entry.getTag()).getContentLine(0) << "\"" << std::endl << std::endl;
328 }
329 }
330 } else {
331 // Compare exact match for every other type of entry
332 if(oldv_str.compare(new_results.getChild(result_entry.getTag()).getContentLine(0))!=0) {
333 deviation = true;
334 std::cout << std::endl
335 << "DeviationC in Test: \"" << old_test.getTag()
336 << "\" for entry \"" << result_entry.getTag() << "\"" << std::endl;
337 std::cout << " Existing Value: \"" << oldv_str << "\"" << std::endl;
338 std::cout << " New Value: \"" << new_results.getChild(result_entry.getTag()).getContentLine(0) << "\"" << std::endl << std::endl;
339 }
340 }
341 }
342 // An old value was not given in the new test: this is an error;
343 if(!exists) {
344 std::cout << "Error New test has same name as an existing one, but one of the old entries is missing." << std::endl;
345 deviation = true;
346 }
347 }
348
349 if(deviation) { return_value = PerfTestFailed; }
350 else {
351 // Did someone add new values to the test?
352 if(new_results.numChildren()!=old_results.numChildren()) {
353 for(int new_r = 0; new_r < new_results.numChildren() ; new_r++) {
354 if(!old_results.hasChild(new_results.getChild(new_r).getTag())) {
355 old_results.addChild(new_results.getChild(new_r));
356 }
357 }
358
359 return_value = PerfTestUpdatedTest;
360 }
361 }
362 }
363 } else { // End Test Exists
364 // Add new test if no match was found
365 old_tests.addChild(new_test);
366 return_value = PerfTestNewTest;
367 }
368 } // End MachineConfiguration Exists
369 } // End loop over MachineConfigurations
370
371 // Did not find matching MachineConfiguration
372 if(is_new_config) {
373 XMLTestNode config("Configuration");
374 config.addChild(machine_config);
375 XMLTestNode tests("Tests");
376 tests.addChild(new_test);
377
378 config.addChild(tests);
379 machine.addChild(config);
380
381 return_value = PerfTestNewConfiguration;
382 }
383 } else { // Machine Entry does not exist
385
386 XMLTestNode config("Configuration");
387 config.addChild(machine_config);
388 XMLTestNode tests("Tests");
389 tests.addChild(new_test);
390 config.addChild(tests);
391
392 machine.addChild(config);
393
394 database.addChild(machine);
395
396 return_value = PerfTestNewMachine;
397 }
398
399
400 if(return_value>PerfTestPassed) {
401 std::ofstream fout(filename.c_str());
402 fout << database << std::endl;
403 }
404
405 return return_value;
406}
407}
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.
Instantiation of XMLInputSource class for reading XML from a file.
Smart reference counting pointer class for automatic garbage collection.
XMLObject getObject() const
Get an object by invoking the TreeBuildingXMLHandler on the input data.
Subclass of XMLObject used by the performance archive.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
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...