14 #ifndef OR_TOOLS_UTIL_TIME_LIMIT_H_
15 #define OR_TOOLS_UTIL_TIME_LIMIT_H_
25 #include "absl/base/port.h"
26 #include "absl/container/flat_hash_map.h"
27 #include "absl/flags/declare.h"
28 #include "absl/synchronization/mutex.h"
29 #include "absl/time/clock.h"
34 #ifdef HAS_PERF_SUBSYSTEM
35 #include "exegesis/exegesis/itineraries/perf_subsystem.h"
123 double limit_in_seconds,
124 double deterministic_limit = std::numeric_limits<double>::infinity(),
125 double instruction_limit = std::numeric_limits<double>::infinity());
136 return std::make_unique<TimeLimit>(std::numeric_limits<double>::infinity(),
137 std::numeric_limits<double>::infinity(),
138 std::numeric_limits<double>::infinity());
145 double deterministic_limit) {
146 return std::make_unique<TimeLimit>(std::numeric_limits<double>::infinity(),
148 std::numeric_limits<double>::infinity());
158 template <
typename Parameters>
161 return std::make_unique<TimeLimit>(
parameters.max_time_in_seconds(),
163 std::numeric_limits<double>::infinity());
172 instruction_limit_ = instruction_limit;
213 return std::max(0.0, deterministic_limit_ - elapsed_deterministic_time_);
227 DCHECK_LE(0.0, deterministic_duration);
228 elapsed_deterministic_time_ += deterministic_duration;
241 const char* counter_name) {
244 deterministic_counters_[counter_name] += deterministic_duration;
252 return 1e-9 * (absl::GetCurrentTimeNanos() - start_ns_);
261 return elapsed_deterministic_time_;
274 std::atomic<bool>* external_boolean_as_limit) {
275 external_boolean_as_limit_ = external_boolean_as_limit;
282 return external_boolean_as_limit_;
289 template <
typename Parameters>
297 deterministic_limit_ = new_limit;
311 void ResetTimers(
double limit_in_seconds,
double deterministic_limit,
312 double instruction_limit);
314 std::string GetInstructionRetiredEventName()
const {
315 return "inst_retired:any_p:u";
318 mutable int64_t start_ns_;
322 const int64_t safety_buffer_ns_;
323 RunningMax<int64_t> running_max_;
327 double limit_in_seconds_;
329 double deterministic_limit_;
330 double elapsed_deterministic_time_;
332 std::atomic<bool>* external_boolean_as_limit_;
334 #ifdef HAS_PERF_SUBSYSTEM
336 exegesis::PerfSubsystem perf_subsystem_;
339 double instruction_limit_;
343 absl::flat_hash_map<std::string, double> deterministic_counters_;
354 : time_limit_(
time_limit), stopped_boolean_(false) {
356 stopped_ =
time_limit->ExternalBooleanAsLimit();
357 if (stopped_ ==
nullptr) {
358 stopped_ = &stopped_boolean_;
359 time_limit->RegisterExternalBooleanAsLimit(stopped_);
364 if (stopped_ == &stopped_boolean_) {
365 time_limit_->RegisterExternalBooleanAsLimit(
nullptr);
372 absl::MutexLock lock(&mutex_);
373 return time_limit_->LimitReached();
377 absl::MutexLock lock(&mutex_);
382 absl::MutexLock lock(&mutex_);
387 absl::MutexLock lock(&mutex_);
388 time_limit_->AdvanceDeterministicTime(deterministic_duration);
392 absl::ReaderMutexLock lock(&mutex_);
393 return time_limit_->GetTimeLeft();
397 absl::ReaderMutexLock lock(&mutex_);
398 return time_limit_->GetElapsedDeterministicTime();
402 absl::ReaderMutexLock lock(&mutex_);
405 return time_limit_->ExternalBooleanAsLimit();
409 mutable absl::Mutex mutex_;
410 TimeLimit* time_limit_ ABSL_GUARDED_BY(mutex_);
411 std::atomic<bool> stopped_boolean_ ABSL_GUARDED_BY(mutex_);
412 std::atomic<bool>* stopped_ ABSL_GUARDED_BY(mutex_);
452 double deterministic_limit);
466 template <
typename Parameters>
469 return std::make_unique<NestedTimeLimit>(
492 double instruction_limit)
493 : safety_buffer_ns_(static_cast<int64_t>(kSafetyBufferSeconds * 1e9)),
494 running_max_(kHistorySize),
495 external_boolean_as_limit_(nullptr) {
496 ResetTimers(limit_in_seconds, deterministic_limit, instruction_limit);
499 inline void TimeLimit::ResetTimers(
double limit_in_seconds,
500 double deterministic_limit,
501 double instruction_limit) {
502 elapsed_deterministic_time_ = 0.0;
503 deterministic_limit_ = deterministic_limit;
504 instruction_limit_ = instruction_limit;
506 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
508 limit_in_seconds_ = limit_in_seconds;
510 #ifdef HAS_PERF_SUBSYSTEM
511 if (absl::GetFlag(FLAGS_time_limit_use_instruction_count)) {
512 perf_subsystem_.CleanUp();
513 perf_subsystem_.AddEvent(GetInstructionRetiredEventName());
514 perf_subsystem_.StartCollecting();
517 start_ns_ = absl::GetCurrentTimeNanos();
518 last_ns_ = start_ns_;
520 limit_ns_ = (absl::Seconds(limit_in_seconds) + absl::Nanoseconds(start_ns_)) /
521 absl::Nanoseconds(1);
524 template <
typename Parameters>
528 std::numeric_limits<double>::infinity());
532 if (other ==
nullptr)
return;
536 std::numeric_limits<double>::infinity());
543 #ifdef HAS_PERF_SUBSYSTEM
544 if (absl::GetFlag(FLAGS_time_limit_use_instruction_count)) {
545 return perf_subsystem_.ReadCounters().GetScaledOrDie(
546 GetInstructionRetiredEventName());
553 if (external_boolean_as_limit_ !=
nullptr &&
554 external_boolean_as_limit_->load()) {
562 #ifdef HAS_PERF_SUBSYSTEM
568 const int64_t current_ns = absl::GetCurrentTimeNanos();
569 running_max_.
Add(
std::max(safety_buffer_ns_, current_ns - last_ns_));
570 last_ns_ = current_ns;
571 if (current_ns + running_max_.
GetCurrentMax() >= limit_ns_) {
572 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
576 const double time_left_s = limit_in_seconds_ - user_timer_.
Get();
578 limit_ns_ =
static_cast<int64_t
>(time_left_s * 1e9) + last_ns_;
591 if (limit_ns_ ==
kint64max)
return std::numeric_limits<double>::infinity();
592 const int64_t delta_ns = limit_ns_ - absl::GetCurrentTimeNanos();
593 if (delta_ns < 0)
return 0.0;
594 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
595 return std::max(limit_in_seconds_ - user_timer_.
Get(), 0.0);
597 return delta_ns * 1e-9;
Provides a way to nest time limits for algorithms where a certain part of the computation is bounded ...
static std::unique_ptr< NestedTimeLimit > FromBaseTimeLimitAndParameters(TimeLimit *time_limit, const Parameters ¶meters)
Creates a time limit object initialized from a base time limit and an object that provides methods ma...
TimeLimit * GetTimeLimit()
Returns a time limit object that represents the combination of the overall time limit and the part-sp...
~NestedTimeLimit()
Updates elapsed deterministic time in the base time limit object.
NestedTimeLimit(TimeLimit *base_time_limit, double limit_in_seconds, double deterministic_limit)
Creates the nested time limit.
std::atomic< bool > * ExternalBooleanAsLimit() const
void UpdateLocalLimit(TimeLimit *local_limit)
double GetTimeLeft() const
SharedTimeLimit(TimeLimit *time_limit)
double GetElapsedDeterministicTime() const
bool LimitReached() const
void AdvanceDeterministicTime(double deterministic_duration)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
double GetInstructionsLeft()
Returns the number of instructions left to reach the limit.
static const double kSafetyBufferSeconds
std::atomic< bool > * ExternalBooleanAsLimit() const
Returns the current external Boolean limit.
void ResetLimitFromParameters(const Parameters ¶meters)
Sets new time limits.
double GetDeterministicTimeLeft() const
Returns the remaining deterministic time before LimitReached() returns true due to the deterministic ...
double GetTimeLeft() const
Returns the time left on this limit, or 0 if the limit was reached (it never returns a negative value...
void SetInstructionLimit(double instruction_limit)
Sets the instruction limit.
friend class ParallelTimeLimit
double ReadInstructionCounter()
Returns the number of instructions executed since the creation of this object.
static std::unique_ptr< TimeLimit > Infinite()
Creates a time limit object that uses infinite time for wall time, deterministic time and instruction...
void RegisterExternalBooleanAsLimit(std::atomic< bool > *external_boolean_as_limit)
Registers the external Boolean to check when LimitReached() is called.
static std::unique_ptr< TimeLimit > FromDeterministicTime(double deterministic_limit)
Creates a time limit object that puts limit only on the deterministic time.
double GetDeterministicLimit() const
Queries the deterministic time limit.
std::string DebugString() const
Returns information about the time limit object in a human-readable form.
bool LimitReached()
Returns true when the external limit is true, or the deterministic time is over the deterministic lim...
static std::unique_ptr< TimeLimit > FromParameters(const Parameters ¶meters)
Creates a time limit object initialized from an object that provides methods max_time_in_seconds() an...
TimeLimit & operator=(const TimeLimit &)=delete
TimeLimit(const TimeLimit &)=delete
static const int kHistorySize
double GetElapsedDeterministicTime() const
Returns the elapsed deterministic time since the construction of this object.
void AdvanceDeterministicTime(double deterministic_duration, const char *counter_name)
Advances the deterministic time.
void MergeWithGlobalTimeLimit(TimeLimit *other)
double GetElapsedTime() const
Returns the time elapsed in seconds since the construction of this object.
void ChangeDeterministicLimit(double new_limit)
Overwrites the deterministic time limit with the new value.
void AdvanceDeterministicTime(double deterministic_duration)
Advances the deterministic time.
ModelSharedTimeLimit * time_limit
static const int64_t kint64max
Collection of objects used to extend the Constraint Solver library.
ABSL_DECLARE_FLAG(bool, time_limit_use_usertime)
Enables changing the behavior of the TimeLimit class to use -b usertime instead of walltime.