|
dlvhex
2.1.0
|
00001 /* dlvhex -- Answer-Set Programming with external interfaces. 00002 * Copyright (C) 2005, 2006, 2007 Roman Schindlauer 00003 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Thomas Krennwallner 00004 * Copyright (C) 2009, 2010 Peter Schüller 00005 * 00006 * This file is part of dlvhex. 00007 * 00008 * dlvhex is free software; you can redistribute it and/or modify it 00009 * under the terms of the GNU Lesser General Public License as 00010 * published by the Free Software Foundation; either version 2.1 of 00011 * the License, or (at your option) any later version. 00012 * 00013 * dlvhex is distributed in the hope that it will be useful, but 00014 * WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with dlvhex; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00021 * 02110-1301 USA. 00022 */ 00023 00024 00033 #ifndef DLVHEX_H_BENCHMARKING_INCLUDED_1555 00034 #define DLVHEX_H_BENCHMARKING_INCLUDED_1555 00035 00036 #include "dlvhex2/PlatformDefinitions.h" 00037 00038 #include <boost/scope_exit.hpp> 00039 #include <boost/typeof/typeof.hpp> // seems to be required for scope_exit 00040 #include <boost/date_time/posix_time/posix_time.hpp> 00041 #include <boost/thread/mutex.hpp> 00042 #include <vector> 00043 #include <ostream> 00044 00045 // Benchmarking is always compiled into dlvhex, 00046 // but benchmarking of dlvhex itself is only 00047 // activated if you configure with --enable-debug 00048 // 00049 // Plugins can use benchmarking of dlvhex by doing 00050 // #define DLVHEX_BENCHMARK 00051 // #include <dlvhex2/Benchmarking.h> 00052 // in a .cpp file that wants to use benchmarking. 00053 // 00054 // usage example: 00055 // 00056 // DLVHEX_BENCHMARK_REGISTER(sid1,"calling dlv"); 00057 // DLVHEX_BENCHMARK_REGISTER(sid2,"fork+exec dlv"); 00058 // DLVHEX_BENCHMARK_REGISTER(sid3,"parse dlv result"); 00059 // 00060 // DLVHEX_BENCHMARK_START(sid1) 00061 // DLVHEX_BENCHMARK_START(sid2) 00062 // // fork and exec 00063 // DLVHEX_BENCHMARK_STOP(sid2) 00064 // 00065 // { 00066 // DLVHEX_BENCHMARK_SCOPE(sid3) 00067 // parse result 00068 // ... 00069 // } 00070 // DLVHEX_BENCHMARK_STOP(sid1) 00071 // DLVHEX_BENCHMARK_COUNT(sid4,someinteger) 00072 // DLVHEX_BENCHMARK_REGISTER_AND_START(sid6,"reg start") 00073 // { 00074 // DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid5,"reg scope") 00075 // ... 00076 // } 00077 // DLVHEX_BENCHMARK_STOP(sid6) 00078 // 00079 // if you want to have a benchmark scope within a template, you need to use 00080 // DLVHEX_BENCHMARK_REGISTER_AND_SCOPE_TPL(sid7,"reg scope in template") 00081 // 00082 // you can also manage the stat IDs yourself 00083 // (e.g., for creating one instrumentation per custom external atom, 00084 // not only one for some base class) 00085 // #if defined(DLVHEX_BENCHMARK) 00086 // dlvhex::benchmark::ID myStoredSid = 00087 // dlvhex::benchmark::BenchmarkController::Instance().getInstrumentationID("my message"); 00088 // #endif 00089 00090 #if defined(DLVHEX_BENCHMARK) 00091 # define DLVHEX_BENCHMARK_REGISTER(sid,msg) \ 00092 static DLVHEX_NAMESPACE benchmark::ID sid = DLVHEX_NAMESPACE benchmark::BenchmarkController::Instance().getInstrumentationID(msg) 00093 # define DLVHEX_BENCHMARK_START(sid) \ 00094 DLVHEX_NAMESPACE benchmark::BenchmarkController::Instance().start(sid) 00095 # define DLVHEX_BENCHMARK_STOP(sid) \ 00096 DLVHEX_NAMESPACE benchmark::BenchmarkController::Instance().stop(sid) 00097 # define DLVHEX_BENCHMARK_COUNT(sid,num) \ 00098 DLVHEX_NAMESPACE benchmark::BenchmarkController::Instance().count(sid,num) 00099 # define DLVHEX_BENCHMARK_SCOPE(sid) \ 00100 DLVHEX_NAMESPACE benchmark::BenchmarkController::Instance().start(sid); \ 00101 BOOST_SCOPE_EXIT( (sid) ) { \ 00102 DLVHEX_NAMESPACE benchmark::BenchmarkController::Instance().stop(sid); \ 00103 } BOOST_SCOPE_EXIT_END 00104 # define DLVHEX_BENCHMARK_SCOPE_TPL(sid) \ 00105 DLVHEX_NAMESPACE benchmark::BenchmarkController::Instance().start(sid); \ 00106 BOOST_SCOPE_EXIT_TPL( (sid) ) { \ 00107 DLVHEX_NAMESPACE benchmark::BenchmarkController::Instance().stop(sid); \ 00108 } BOOST_SCOPE_EXIT_END 00109 # define DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,msg) \ 00110 DLVHEX_BENCHMARK_REGISTER(sid,msg); DLVHEX_BENCHMARK_SCOPE(sid); 00111 # define DLVHEX_BENCHMARK_REGISTER_AND_SCOPE_TPL(sid,msg) \ 00112 DLVHEX_BENCHMARK_REGISTER(sid,msg); DLVHEX_BENCHMARK_SCOPE_TPL(sid); 00113 # define DLVHEX_BENCHMARK_REGISTER_AND_START(sid,msg) \ 00114 DLVHEX_BENCHMARK_REGISTER(sid,msg); DLVHEX_BENCHMARK_START(sid); 00115 # define DLVHEX_BENCHMARK_REGISTER_AND_COUNT(sid,msg,num) \ 00116 DLVHEX_BENCHMARK_REGISTER(sid,msg); DLVHEX_BENCHMARK_COUNT(sid,num); 00117 #else 00118 # define DLVHEX_BENCHMARK_REGISTER(sid,msg) do { } while(0) 00119 # define DLVHEX_BENCHMARK_START(sid) do { } while(0) 00120 # define DLVHEX_BENCHMARK_STOP(sid) do { } while(0) 00121 # define DLVHEX_BENCHMARK_COUNT(sid,num) do { } while(0) 00122 # define DLVHEX_BENCHMARK_SCOPE(sid) do { } while(0) 00123 # define DLVHEX_BENCHMARK_SCOPE_TPL(sid) do { } while(0) 00124 # define DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,msg) do { } while(0) 00125 # define DLVHEX_BENCHMARK_REGISTER_AND_SCOPE_TPL(sid,msg) do { } while(0) 00126 # define DLVHEX_BENCHMARK_REGISTER_AND_START(sid,msg) do { } while(0) 00127 # define DLVHEX_BENCHMARK_REGISTER_AND_COUNT(sid,msg,num) do { } while(0) 00128 00129 #endif // defined(DLVHEX_BENCHMARK) 00130 00131 DLVHEX_NAMESPACE_BEGIN 00132 00133 namespace benchmark 00134 { 00135 00136 typedef unsigned ID; 00137 typedef unsigned Count; 00138 typedef boost::posix_time::ptime Time; 00139 typedef boost::posix_time::time_duration Duration; 00140 00141 class BenchmarkController 00142 { 00143 public: 00144 struct Stat 00145 { 00146 std::string name; 00147 Count count; 00148 Count prints; 00149 Time start; 00150 Duration duration; 00151 00152 Stat(const std::string& name); 00153 }; 00154 00155 00156 public: 00157 inline std::ostream& printInSecs(std::ostream& o, const Duration& d, int width=0) const; 00158 00159 // print information about stat 00160 inline void printInformation(const Stat& st); // inline for performance 00161 // print continuous information about stat 00162 inline void printInformationContinous( 00163 Stat& st, const Duration& dur); // inline for performance 00164 00165 public: 00166 // singleton access 00167 static BenchmarkController& Instance(); 00168 00169 // delete singleton-> causes destructor to be called 00170 static void finish(); 00171 00172 // output benchmark results, destruct 00173 ~BenchmarkController(); 00174 00175 // 00176 // configure 00177 // 00178 00179 // output stream 00180 void setOutput(std::ostream* o); 00181 // amount of accumulated output (default: each call) 00182 void setPrintInterval(Count skip); 00183 00184 // 00185 // instrumentation points 00186 // 00187 00188 // get ID or register new one 00189 ID getInstrumentationID(const std::string& name); 00190 // print information about ID 00191 inline void printInformation(ID id); // inline for performance 00192 // print only count of ID 00193 inline std::ostream& printCount(std::ostream& out, ID id); // inline for performance 00194 // print only duration of ID 00195 inline std::ostream& printDuration(std::ostream& out, ID id); // inline for performance 00196 inline const Stat& getStat(ID id) { return instrumentations[id]; } 00197 00198 // 00199 // record measured things 00200 // 00201 00202 // start timer 00203 inline void start(ID id); // inline for performance 00204 // stop and record elapsed time, print stats 00205 inline void stop(ID id); // inline for performance 00206 // record count (no time), print stats 00207 inline void count(ID id, Count increment=1); // inline for performance 00208 00209 private: 00210 // init, display start of benchmarking 00211 BenchmarkController(); 00212 00213 ID myID; 00214 ID maxID; 00215 std::vector<Stat> instrumentations; 00216 std::map<std::string, ID> name2id; 00217 00218 std::ostream* output; 00219 Count printSkip; 00220 00221 boost::mutex mutex; 00222 }; 00223 00224 //inline 00225 std::ostream& BenchmarkController::printInSecs(std::ostream& out, const Duration& td, int width) const 00226 { 00227 long in_secs = td.total_milliseconds(); 00228 00229 long secs = in_secs / 1000; 00230 long rest = in_secs % 1000; 00231 00232 out << std::setw(width) << secs << "."; 00233 00234 if (rest < 10) 00235 { 00236 out << "00"; 00237 } 00238 else if (rest < 100) 00239 { 00240 out << "0"; 00241 } 00242 00243 return out << rest; 00244 } 00245 00246 // print information about stat 00247 // inline for performance 00248 void BenchmarkController::printInformation(const Stat& st) 00249 { 00250 if( output ) 00251 { 00252 (*output) << 00253 "BM:" << std::setw(30) << st.name << 00254 ": count:" << std::setw(6) << st.count << 00255 " avg:"; 00256 if( st.count > 0 ) 00257 { 00258 printInSecs(*output, st.duration/st.count, 4); 00259 } 00260 else 00261 { 00262 (*output) << " -.---"; 00263 } 00264 (*output) << "s" << " total:"; 00265 printInSecs(*output, st.duration, 6) << "s" << std::endl; 00266 } 00267 } 00268 00269 // print only count of ID 00270 std::ostream& BenchmarkController::printCount(std::ostream& out, ID id) 00271 { 00272 boost::mutex::scoped_lock lock(mutex); 00273 Stat& st = instrumentations[id]; 00274 return out << st.count; 00275 } 00276 00277 std::ostream& BenchmarkController::printDuration(std::ostream& out, ID id) 00278 { 00279 boost::mutex::scoped_lock lock(mutex); 00280 Stat& st = instrumentations[id]; 00281 return printInSecs(out, st.duration); 00282 } 00283 00284 // print continuous information about stat 00285 // inline for performance 00286 void BenchmarkController::printInformationContinous(Stat& st, const Duration& dur) 00287 { 00288 if( st.prints >= printSkip ) 00289 { 00290 st.prints = 0; 00291 if( output ) 00292 { 00293 (*output) << 00294 "BM:" << std::setw(30) << st.name << 00295 ": count:" << std::setw(6) << st.count << 00296 " total:"; 00297 printInSecs(*output, st.duration, 6) << "s" << 00298 " last:"; 00299 printInSecs(*output, dur, 2) << "s" << std::endl; 00300 } 00301 } 00302 else 00303 { 00304 st.prints++; 00305 } 00306 } 00307 00308 // inline for performance 00309 // start timer 00310 void BenchmarkController::start(ID id) 00311 { 00312 boost::mutex::scoped_lock lock(mutex); 00313 Stat& st = instrumentations[id]; 00314 st.start = boost::posix_time::microsec_clock::local_time(); 00315 } 00316 00317 // inline for performance 00318 // stop and record elapsed time, print stats 00319 void BenchmarkController::stop(ID id) 00320 { 00321 boost::mutex::scoped_lock lock(mutex); 00322 Stat& st = instrumentations[id]; 00323 00324 Duration dur = boost::posix_time::microsec_clock::local_time() - st.start; 00325 st.count++; 00326 st.duration += dur; 00327 printInformationContinous(st,dur); 00328 } 00329 00330 // record count (no time), print stats 00331 // inline for performance 00332 void BenchmarkController::count(ID id, Count increment) 00333 { 00334 boost::mutex::scoped_lock lock(mutex); 00335 Stat& s = instrumentations[id]; 00336 s.count += increment; 00337 s.prints += increment - 1; 00338 printInformationContinous(s,Duration()); 00339 } 00340 00341 } // namespace benchmark 00342 00343 DLVHEX_NAMESPACE_END 00344 00345 #endif // DLVHEX_H_BENCHMARKING_INCLUDED_1555 00346 00347 00348 // Local Variables: 00349 // mode: C++ 00350 // End: