00001
00002
00003 #ifndef OSL_SEARCHTIMER_H
00004 #define OSL_SEARCHTIMER_H
00005 #include "osl/misc/milliSeconds.h"
00006 #include "osl/misc/lightMutex.h"
00007 #include "osl/stl/vector.h"
00008 #include "osl/oslConfig.h"
00009 #include <boost/shared_ptr.hpp>
00010 #include <boost/cstdint.hpp>
00011 #include <limits>
00012
00013 namespace osl
00014 {
00015 namespace search
00016 {
00017 struct TimeAssigned
00018 {
00019 MilliSeconds::Interval standard, max;
00020 TimeAssigned()
00021 : standard(MilliSeconds::Interval::infinity()),
00022 max(MilliSeconds::Interval::infinity())
00023 {
00024 }
00025 explicit TimeAssigned(MilliSeconds::Interval assign)
00026 : standard(assign), max(assign)
00027 {
00028 }
00029 TimeAssigned(MilliSeconds::Interval s, MilliSeconds::Interval m)
00030 : standard(s), max(m)
00031 {
00032 }
00033 };
00034 class SearchMonitor;
00035 struct SearchTimerCommon
00036 {
00037 enum StopReason { NotStopped, NoMoreTime, NoMoreMemory, StopByOutside };
00039 MilliSeconds start_time;
00041 TimeAssigned assigned;
00043 volatile double next_iteration_coefficient;
00044 volatile bool stop_all;
00045 volatile StopReason stop_reason;
00046 uint64_t node_count_hard_limit;
00047
00048
00049 MilliSeconds last_tested;
00050 uint64_t next_node_count;
00051 double nps;
00052 volatile bool stable;
00053 vector<boost::shared_ptr<SearchMonitor> > monitors;
00054 typedef LightMutex Mutex;
00055 mutable Mutex mutex;
00056
00057 SearchTimerCommon()
00058 : start_time(MilliSeconds::now()),
00059 next_iteration_coefficient(4.0), stop_all(0), stop_reason(NotStopped),
00060 node_count_hard_limit(std::numeric_limits<uint64_t>::max()),
00061 stable(true)
00062 {
00063 }
00064 };
00065 class SearchTimer
00066 {
00067 boost::shared_ptr<SearchTimerCommon> shared_timer;
00068 typedef SearchTimerCommon::Mutex Mutex;
00069 public:
00070 SearchTimer() : shared_timer(new SearchTimerCommon) {}
00071 SearchTimer(const SearchTimer& src) : shared_timer(src.shared_timer) {}
00072 virtual ~SearchTimer();
00073 void setTimeAssign(const TimeAssigned& a) {
00074 SCOPED_LOCK(lk,shared_timer->mutex);
00075 shared_timer->assigned = a;
00076 }
00077 void setStartTime(MilliSeconds start) {
00078 SCOPED_LOCK(lk,shared_timer->mutex);
00079 shared_timer->start_time = start;
00080 shared_timer->next_node_count = 0;
00081 shared_timer->nps = 0.0;
00082 shared_timer->last_tested = start;
00083 shared_timer->stop_all = false;
00084 }
00085 void setStable(bool new_stable) { shared_timer->stable = new_stable; }
00086 bool isStableNow() const { return shared_timer->stable; }
00087 bool hasSchedule() const {
00088 SCOPED_LOCK(lk,shared_timer->mutex);
00089 return ! shared_timer->assigned.standard.isInfinity();
00090 }
00091 const TimeAssigned& timeAssigned() const
00092 {
00093 SCOPED_LOCK(lk,shared_timer->mutex);
00094 return shared_timer->assigned;
00095 }
00096 const MilliSeconds startTime() const {
00097 SCOPED_LOCK(lk,shared_timer->mutex);
00098 return shared_timer->start_time;
00099 }
00100 double elapsed(MilliSeconds now) const
00101 {
00102 return (now - shared_timer->start_time).toSeconds();
00103 }
00104 double elapsed() const { return elapsed(MilliSeconds::now()); }
00105
00106 void setNextIterationCoefficient(double new_value) {
00107 SCOPED_LOCK(lk,shared_timer->mutex);
00108 shared_timer->next_iteration_coefficient = new_value;
00109 }
00110 void setNodeCountHardLimit(uint64_t new_value) {
00111 SCOPED_LOCK(lk,shared_timer->mutex);
00112 shared_timer->node_count_hard_limit = new_value;
00113 }
00114 double nextIterationCoefficient() const {
00115 SCOPED_LOCK(lk,shared_timer->mutex);
00116 return shared_timer->next_iteration_coefficient;
00117 }
00118
00119 bool stopping() const { return shared_timer->stop_all; }
00120 void stopNow()
00121 {
00122 shared_timer->stop_reason = SearchTimerCommon::StopByOutside;
00123 shared_timer->stop_all = true;
00124 }
00125 SearchTimerCommon::StopReason stopReason() { return shared_timer->stop_reason; }
00126 void throwIfNoMoreTime(uint64_t node_count)
00127 {
00128 SearchTimerCommon& shared = *shared_timer;
00129 if (! shared.stop_all) {
00130 uint64_t next_node_count;
00131 {
00132 #ifdef OSL_USE_RACE_DETECTOR
00133 SCOPED_LOCK(lk,shared_timer->mutex);
00134 #endif
00135 next_node_count = shared.next_node_count;
00136 }
00137 if (next_node_count > node_count || ! hasSchedule())
00138 return;
00139 }
00140 testAndUpdateNextTimeTest(node_count);
00141 }
00142 int nodeAffordable() const
00143 {
00144 const MilliSeconds now = MilliSeconds::now();
00145 #ifdef OSL_USE_RACE_DETECTOR
00146 SCOPED_LOCK(lk,shared_timer->mutex);
00147 #endif
00148 const double nps = shared_timer->nps;
00149 const double left
00150 = (shared_timer->start_time + shared_timer->assigned.max - now).toSeconds();
00151 return std::max(0, static_cast<int>(nps * left));
00152 }
00154 static void adjustMemoryUseLimit(double scale=0.9);
00155 void addMonitor(const boost::shared_ptr<SearchMonitor>&);
00156 bool hasMonitor() const
00157 {
00158 return ! shared_timer->monitors.empty();
00159 }
00160 const vector<boost::shared_ptr<SearchMonitor> >& monitors() const
00161 {
00162 return shared_timer->monitors;
00163 }
00164 private:
00165 void testAndUpdateNextTimeTest(uint64_t node_count);
00166 void throwStop();
00167 };
00168 }
00169 }
00170
00171
00172 #endif
00173
00174
00175
00176