dlvhex  2.1.0
include/dlvhex2/Benchmarking.h
Go to the documentation of this file.
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: