|
Teuchos - Trilinos Tools Package
Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Teuchos: Common Tools Package 00005 // Copyright (2004) Sandia Corporation 00006 // 00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00008 // license for use of this work by or on behalf of the U.S. Government. 00009 // 00010 // Redistribution and use in source and binary forms, with or without 00011 // modification, are permitted provided that the following conditions are 00012 // met: 00013 // 00014 // 1. Redistributions of source code must retain the above copyright 00015 // notice, this list of conditions and the following disclaimer. 00016 // 00017 // 2. Redistributions in binary form must reproduce the above copyright 00018 // notice, this list of conditions and the following disclaimer in the 00019 // documentation and/or other materials provided with the distribution. 00020 // 00021 // 3. Neither the name of the Corporation nor the names of the 00022 // contributors may be used to endorse or promote products derived from 00023 // this software without specific prior written permission. 00024 // 00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00036 // 00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00038 // 00039 // *********************************************************************** 00040 // @HEADER 00041 00042 00043 #include <iostream> 00044 #include <fstream> 00045 #include <cstring> 00046 #include <cstdlib> 00047 #include <Teuchos_XMLObject.hpp> 00048 #include <Teuchos_FileInputSource.hpp> 00049 #include <Teuchos_XMLPerfTestArchive.hpp> 00050 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 00051 #include <Winsock2.h> 00052 #pragma comment(lib, "ws2_32.lib") 00053 #else 00054 #include <unistd.h> 00055 #endif 00056 00057 namespace Teuchos { 00058 00059 ValueTolerance::ValueTolerance() { 00060 value = 0; 00061 lower = 0; 00062 upper = 0; 00063 tolerance = 0; 00064 use_tolerance = true; 00065 } 00066 00067 ValueTolerance::ValueTolerance(double val, double tol) { 00068 value = val; 00069 lower = 0; 00070 upper = 0; 00071 tolerance = tol; 00072 use_tolerance = true; 00073 } 00074 00075 ValueTolerance::ValueTolerance(double val, double low, double up) { 00076 value = val; 00077 upper = up; 00078 lower = low; 00079 tolerance = 0; 00080 use_tolerance = false; 00081 } 00082 00083 ValueTolerance::ValueTolerance(std::string str) { 00084 from_string(str); 00085 } 00086 00087 bool ValueTolerance::operator ==(ValueTolerance& rhs) { 00088 return (value == rhs.value) && 00089 (tolerance == rhs.tolerance) && 00090 (lower == rhs.lower) && 00091 (upper == rhs.upper) && 00092 (use_tolerance == rhs.use_tolerance); 00093 } 00094 00095 std::string ValueTolerance::as_string(){ 00096 std::ostringstream strs; 00097 if(use_tolerance) 00098 strs << value << " , " << tolerance; 00099 else 00100 strs << value << " , " << lower << " , " << upper; 00101 return strs.str(); 00102 } 00103 00104 void ValueTolerance::from_string(const std::string& valtol_str) { 00105 std::string value_str = valtol_str.substr(0,valtol_str.find(",")); 00106 value = atof(value_str.c_str()); 00107 std::string tol_str = valtol_str.substr(valtol_str.find(",")+1); 00108 if(tol_str.find(",")<=tol_str.length()) { 00109 use_tolerance = false; 00110 std::string lower_str = tol_str.substr(0,tol_str.find(",")); 00111 lower = atof(lower_str.c_str()); 00112 std::string upper_str = tol_str.substr(tol_str.find(",")+1); 00113 upper = atof(upper_str.c_str()); 00114 } else { 00115 use_tolerance = true; 00116 tolerance = atof(tol_str.c_str()); 00117 } 00118 } 00119 00120 XMLTestNode::XMLTestNode():XMLObject() {} 00121 00122 XMLTestNode::XMLTestNode(const std::string &tag):XMLObject(tag) {} 00123 00124 XMLTestNode::XMLTestNode(XMLObjectImplem *ptr):XMLObject(ptr) {} 00125 00126 XMLTestNode::XMLTestNode(XMLObject obj):XMLObject(obj) {} 00127 00128 void XMLTestNode::addDouble (const std::string &name, double val) { 00129 addAttribute<double>(name,val); 00130 } 00131 00132 void XMLTestNode::addInt (const std::string &name, int val) { 00133 addAttribute<int>(name,val); 00134 } 00135 00136 void XMLTestNode::addBool (const std::string &name, bool val) { 00137 addAttribute<bool>(name,val); 00138 } 00139 00140 void XMLTestNode::addValueTolerance(const std::string &name, ValueTolerance val){ 00141 addAttribute<std::string>(name,val.as_string()); 00142 } 00143 00144 void XMLTestNode::addString (const std::string &name, std::string val) { 00145 addAttribute<std::string>(name,val); 00146 } 00147 00148 bool XMLTestNode::hasChild(const std::string &name) const { 00149 bool found = false; 00150 for(int i = 0; i < numChildren(); i++) { 00151 if(name.compare(XMLObject::getChild(i).getTag()) == 0) { 00152 found = true; 00153 i = numChildren(); 00154 } 00155 } 00156 return found; 00157 } 00158 00159 void XMLTestNode::appendContentLine(const size_t& i, const std::string &str) { 00160 ptr_->appendContentLine(i,str); 00161 } 00162 00163 XMLTestNode XMLTestNode::getChild(const std::string &name) const { 00164 XMLTestNode child; 00165 for(int i = 0; i < numChildren(); i++) { 00166 if(name.compare(XMLObject::getChild(i).getTag()) == 0) 00167 child = XMLObject::getChild(i); 00168 } 00169 return child; 00170 } 00171 00172 XMLTestNode XMLTestNode::getChild(const int &i) const { 00173 return XMLObject::getChild(i); 00174 } 00175 00176 const XMLObject* XMLTestNode::xml_object() const { 00177 return (XMLObject*) this; 00178 } 00179 00180 bool XMLTestNode::hasSameElements(XMLTestNode const & lhs) const { 00181 00182 if((numChildren()!=lhs.numChildren()) || 00183 (numContentLines()!= lhs.numContentLines()) || 00184 (getTag().compare(lhs.getTag())!=0)) return false; 00185 00186 for(int i = 0; i<numChildren(); i++) { 00187 const XMLTestNode child = XMLObject::getChild(i); 00188 if( (!lhs.hasChild(child.getTag())) || 00189 (!child.hasSameElements(lhs.getChild(child.getTag()))) ) return false; 00190 } 00191 00192 for(int i = 0; i<numContentLines(); i++) 00193 if(getContentLine(i).compare(lhs.getContentLine(i))!=0) return false; 00194 00195 return true; 00196 } 00197 00198 XMLTestNode PerfTest_MachineConfig() { 00199 00200 // Get CPUName, Number of Sockets, Number of Cores, Number of Hyperthreads 00201 std::string cpuname("Undefined"); 00202 unsigned int threads = 0; 00203 unsigned int cores_per_socket = 0; 00204 unsigned int highest_socketid = 0; 00205 00206 { 00207 std::ifstream cpuinfo("/proc/cpuinfo"); 00208 std::string line; 00209 if((cpuinfo.rdstate()&cpuinfo.failbit)) std::cout<<"Failed to open filen\n"; 00210 while (!cpuinfo.eof() && !(cpuinfo.rdstate()&cpuinfo.failbit)) { 00211 getline (cpuinfo,line); 00212 if (line.find("model name") < line.size()) { 00213 cpuname = line.substr(line.find(":")+2); 00214 threads++; 00215 } 00216 if (line.find("physical id") < line.size()) { 00217 unsigned int socketid = atoi(line.substr(line.find(":")+2).c_str()); 00218 highest_socketid = highest_socketid>socketid?highest_socketid:socketid; 00219 } 00220 if (line.find("cpu cores") < line.size()) { 00221 cores_per_socket = atoi(line.substr(line.find(":")+2).c_str()); 00222 } 00223 } 00224 } 00225 00226 00227 XMLTestNode machine_config("MachineConfiguration"); 00228 00229 machine_config.addString("Compiler", TEUCHOS_COMPILER_NAME); 00230 machine_config.addInt("Compiler_Version", TEUCHOS_COMPILER_VERSION); 00231 machine_config.addString("CPU_Name", cpuname); 00232 machine_config.addInt("CPU_Sockets", highest_socketid+1); 00233 machine_config.addInt("CPU_Cores_Per_Socket", cores_per_socket); 00234 machine_config.addInt("CPU_Total_HyperThreads", threads); 00235 return machine_config; 00236 } 00237 00238 PerfTestResult 00239 PerfTest_CheckOrAdd_Test (XMLTestNode machine_config, 00240 XMLTestNode new_test, 00241 const std::string filename, 00242 const std::string ext_hostname) 00243 { 00244 XMLTestNode database; 00245 PerfTestResult return_value = PerfTestPassed; 00246 bool is_new_config = true; 00247 00248 // Open Database File 00249 // 00250 // FIXME (mfh 09 Apr 2014) This actually opens the file twice. 00251 if (std::ifstream (filename.c_str ())) { 00252 database = FileInputSource (filename).getObject (); 00253 } 00254 00255 // Get Current Hostname 00256 char hostname[256]; 00257 memset (hostname, 0, 256); 00258 if (ext_hostname.empty ()) { 00259 gethostname (hostname, 255); 00260 } else { 00261 strncat (hostname, ext_hostname.c_str (), 255); 00262 } 00263 00264 XMLTestNode new_test_entry = new_test.getChild ("TestEntry"); 00265 00266 if (database.isEmpty ()) { 00267 database = XMLTestNode ("PerfTests"); 00268 } 00269 // Does hostname exist? 00270 if (database.hasChild (hostname)) { 00271 XMLTestNode machine = database.getChild (hostname); 00272 00273 // Find matching machine configuration 00274 for (int i = 0; i < machine.numChildren (); ++i) { 00275 XMLTestNode configuration = machine.getChild (i); 00276 TEUCHOS_TEST_FOR_EXCEPTION( 00277 configuration.getTag ().compare ("Configuration") != 0, 00278 std::runtime_error, "Unexpected Tag \"" << configuration.getTag () 00279 << "\"; only children with Tag = \"Configuration\" are allowed in a " 00280 "MachineEntry."); 00281 00282 TEUCHOS_TEST_FOR_EXCEPTION( 00283 ! configuration.hasChild ("MachineConfiguration") || 00284 ! configuration.hasChild ("Tests"), 00285 std::runtime_error, 00286 "A Configuration needs to have a child \"MachineConfiguration\" and a " 00287 "child \"Tests\"."); 00288 00289 XMLTestNode machine_configuration = configuration.getChild ("MachineConfiguration"); 00290 XMLTestNode old_tests = configuration.getChild ("Tests"); 00291 00292 if (machine_configuration.hasSameElements (machine_config)) { 00293 is_new_config = false; 00294 00295 // Find existing test with same tag as the new test 00296 if (old_tests.hasChild (new_test.getTag ())) { 00297 00298 XMLTestNode old_test = old_tests.getChild (new_test.getTag ()); 00299 00300 int new_test_config = -1; 00301 for (int k = 0; k < old_test.numChildren (); ++k) { 00302 XMLTestNode old_test_entry = old_test.getChild (k); 00303 00304 TEUCHOS_TEST_FOR_EXCEPTION( 00305 ! old_test_entry.hasChild ("TestConfiguration") || 00306 ! new_test_entry.hasChild ("TestResults"), 00307 std::runtime_error, "A TestEntry needs to have a child " 00308 "\"TestConfiguration\" and a child \"TestResults\"."); 00309 00310 if (old_test_entry.getChild ("TestConfiguration").hasSameElements (new_test_entry.getChild ("TestConfiguration"))) { 00311 new_test_config = k; 00312 } 00313 } 00314 00315 if (new_test_config < 0) { 00316 old_test.addChild (new_test_entry); 00317 return_value = PerfTestNewTestConfiguration; 00318 } else { 00319 bool deviation = false; 00320 XMLTestNode old_test_entry = old_test.getChild (new_test_config); 00321 XMLTestNode old_results = old_test_entry.getChild ("TestResults"); 00322 XMLTestNode new_results = new_test_entry.getChild ("TestResults"); 00323 00324 // Compare all entries 00325 for (int old_r = 0; old_r < old_results.numChildren (); ++old_r) { 00326 XMLTestNode result_entry = old_results.getChild (old_r); 00327 00328 // Finding entry with same name 00329 bool exists = new_results.hasChild (result_entry.getTag ()); 00330 00331 if (exists) { 00332 std::string oldv_str = result_entry.getContentLine (0); 00333 00334 // If it is a time or result compare numeric values with tolerance 00335 if((result_entry.getTag().find("Time")==0) || (result_entry.getTag().find("Result")==0)) { 00336 ValueTolerance old_valtol(oldv_str); 00337 ValueTolerance new_valtol(new_results.getChild(result_entry.getTag()).getContentLine(0)); 00338 00339 if(old_valtol.use_tolerance) { 00340 double diff = old_valtol.value - new_valtol.value; 00341 diff*=diff; 00342 00343 double normalization = old_valtol.value; 00344 normalization*=normalization; 00345 00346 if(normalization==0?diff>0:diff/normalization>old_valtol.tolerance*old_valtol.tolerance) { 00347 deviation = true; 00348 std::cout << std::endl 00349 << "DeviationA in Test: \"" << old_test.getTag() 00350 << "\" for entry \"" << result_entry.getTag() << "\"" << std::endl; 00351 std::cout << " Existing Value: \"" << oldv_str << "\"" << std::endl; 00352 std::cout << " New Value: \"" << new_results.getChild(result_entry.getTag()).getContentLine(0) << "\"" << std::endl << std::endl; 00353 } 00354 } else { 00355 if( (old_valtol.lower>new_valtol.value) || (old_valtol.upper<new_valtol.value)) { 00356 deviation = true; 00357 std::cout << std::endl 00358 << "DeviationB in Test: \"" << old_test.getTag() 00359 << "\" for entry \"" << result_entry.getTag() << "\"" << std::endl; 00360 std::cout << " Existing Value: \"" << oldv_str << "\"" << std::endl; 00361 std::cout << " New Value: \"" << new_results.getChild(result_entry.getTag()).getContentLine(0) << "\"" << std::endl << std::endl; 00362 } 00363 } 00364 } else { 00365 // Compare exact match for every other type of entry 00366 if(oldv_str.compare(new_results.getChild(result_entry.getTag()).getContentLine(0))!=0) { 00367 deviation = true; 00368 std::cout << std::endl 00369 << "DeviationC in Test: \"" << old_test.getTag() 00370 << "\" for entry \"" << result_entry.getTag() << "\"" << std::endl; 00371 std::cout << " Existing Value: \"" << oldv_str << "\"" << std::endl; 00372 std::cout << " New Value: \"" << new_results.getChild(result_entry.getTag()).getContentLine(0) << "\"" << std::endl << std::endl; 00373 } 00374 } 00375 } 00376 // An old value was not given in the new test: this is an error; 00377 if(!exists) { 00378 std::cout << "Error New test has same name as an existing one, but one of the old entries is missing." << std::endl; 00379 deviation = true; 00380 } 00381 } 00382 00383 if(deviation) { return_value = PerfTestFailed; } 00384 else { 00385 // Did someone add new values to the test? 00386 if(new_results.numChildren()!=old_results.numChildren()) { 00387 for(int new_r = 0; new_r < new_results.numChildren() ; new_r++) { 00388 if(!old_results.hasChild(new_results.getChild(new_r).getTag())) { 00389 old_results.addChild(new_results.getChild(new_r)); 00390 } 00391 } 00392 00393 return_value = PerfTestUpdatedTest; 00394 } 00395 } 00396 } 00397 } else { // End Test Exists 00398 // Add new test if no match was found 00399 old_tests.addChild(new_test); 00400 return_value = PerfTestNewTest; 00401 } 00402 } // End MachineConfiguration Exists 00403 } // End loop over MachineConfigurations 00404 00405 // Did not find matching MachineConfiguration 00406 if(is_new_config) { 00407 XMLTestNode config("Configuration"); 00408 config.addChild(machine_config); 00409 XMLTestNode tests("Tests"); 00410 tests.addChild(new_test); 00411 00412 config.addChild(tests); 00413 machine.addChild(config); 00414 00415 return_value = PerfTestNewConfiguration; 00416 } 00417 } else { // Machine Entry does not exist 00418 XMLTestNode machine(hostname); 00419 00420 XMLTestNode config("Configuration"); 00421 config.addChild(machine_config); 00422 XMLTestNode tests("Tests"); 00423 tests.addChild(new_test); 00424 config.addChild(tests); 00425 00426 machine.addChild(config); 00427 00428 database.addChild(machine); 00429 00430 return_value = PerfTestNewMachine; 00431 } 00432 00433 00434 if(return_value>PerfTestPassed) { 00435 std::ofstream fout(filename.c_str()); 00436 fout << database << std::endl; 00437 } 00438 00439 return return_value; 00440 } 00441 }
1.7.6.1