14#ifndef OR_TOOLS_UTIL_TIME_LIMIT_H_
15#define OR_TOOLS_UTIL_TIME_LIMIT_H_
24#include "absl/base/port.h"
25#include "absl/container/flat_hash_map.h"
26#include "absl/memory/memory.h"
27#include "absl/synchronization/mutex.h"
28#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 absl::make_unique<TimeLimit>(
137 std::numeric_limits<double>::infinity(),
138 std::numeric_limits<double>::infinity(),
139 std::numeric_limits<double>::infinity());
146 double deterministic_limit) {
147 return absl::make_unique<TimeLimit>(
148 std::numeric_limits<double>::infinity(), deterministic_limit,
149 std::numeric_limits<double>::infinity());
159 template <
typename Parameters>
162 return absl::make_unique<TimeLimit>(
164 std::numeric_limits<double>::infinity());
173 instruction_limit_ = instruction_limit;
214 return std::max(0.0, deterministic_limit_ - elapsed_deterministic_time_);
229 elapsed_deterministic_time_ += deterministic_duration;
242 const char* counter_name) {
245 deterministic_counters_[counter_name] += deterministic_duration;
253 return 1e-9 * (absl::GetCurrentTimeNanos() - start_ns_);
262 return elapsed_deterministic_time_;
275 std::atomic<bool>* external_boolean_as_limit) {
276 external_boolean_as_limit_ = external_boolean_as_limit;
283 return external_boolean_as_limit_;
290 template <
typename Parameters>
300 void ResetTimers(
double limit_in_seconds,
double deterministic_limit,
301 double instruction_limit);
303 std::string GetInstructionRetiredEventName()
const {
304 return "inst_retired:any_p:u";
307 mutable int64_t start_ns_;
311 const int64_t safety_buffer_ns_;
312 RunningMax<int64_t> running_max_;
316 double limit_in_seconds_;
318 double deterministic_limit_;
319 double elapsed_deterministic_time_;
321 std::atomic<bool>* external_boolean_as_limit_;
323#ifdef HAS_PERF_SUBSYSTEM
325 exegesis::PerfSubsystem perf_subsystem_;
328 double instruction_limit_;
332 absl::flat_hash_map<std::string, double> deterministic_counters_;
343 : time_limit_(
time_limit), stopped_boolean_(false) {
345 stopped_ =
time_limit->ExternalBooleanAsLimit();
346 if (stopped_ ==
nullptr) {
347 stopped_ = &stopped_boolean_;
348 time_limit->RegisterExternalBooleanAsLimit(stopped_);
353 if (stopped_ == &stopped_boolean_) {
354 time_limit_->RegisterExternalBooleanAsLimit(
nullptr);
361 absl::MutexLock lock(&mutex_);
362 return time_limit_->LimitReached();
366 absl::MutexLock lock(&mutex_);
371 absl::MutexLock lock(&mutex_);
376 absl::MutexLock lock(&mutex_);
377 time_limit_->AdvanceDeterministicTime(deterministic_duration);
381 absl::ReaderMutexLock lock(&mutex_);
382 return time_limit_->GetTimeLeft();
386 absl::ReaderMutexLock lock(&mutex_);
387 return time_limit_->GetElapsedDeterministicTime();
391 mutable absl::Mutex mutex_;
392 TimeLimit* time_limit_ ABSL_GUARDED_BY(mutex_);
393 std::atomic<bool> stopped_boolean_ ABSL_GUARDED_BY(mutex_);
394 std::atomic<bool>* stopped_ ABSL_GUARDED_BY(mutex_);
434 double deterministic_limit);
448 template <
typename Parameters>
451 return absl::make_unique<NestedTimeLimit>(
474 double instruction_limit)
475 : safety_buffer_ns_(static_cast<int64_t>(kSafetyBufferSeconds * 1e9)),
476 running_max_(kHistorySize),
477 external_boolean_as_limit_(nullptr) {
478 ResetTimers(limit_in_seconds, deterministic_limit, instruction_limit);
481inline void TimeLimit::ResetTimers(
double limit_in_seconds,
482 double deterministic_limit,
483 double instruction_limit) {
484 elapsed_deterministic_time_ = 0.0;
485 deterministic_limit_ = deterministic_limit;
486 instruction_limit_ = instruction_limit;
488 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
490 limit_in_seconds_ = limit_in_seconds;
492#ifdef HAS_PERF_SUBSYSTEM
493 if (absl::GetFlag(FLAGS_time_limit_use_instruction_count)) {
494 perf_subsystem_.CleanUp();
495 perf_subsystem_.AddEvent(GetInstructionRetiredEventName());
496 perf_subsystem_.StartCollecting();
499 start_ns_ = absl::GetCurrentTimeNanos();
500 last_ns_ = start_ns_;
501 limit_ns_ = limit_in_seconds >= 1e-9 * (
kint64max - start_ns_)
503 :
static_cast<int64_t
>(limit_in_seconds * 1e9) + start_ns_;
506template <
typename Parameters>
510 std::numeric_limits<double>::infinity());
514 if (other ==
nullptr)
return;
518 std::numeric_limits<double>::infinity());
525#ifdef HAS_PERF_SUBSYSTEM
526 if (absl::GetFlag(FLAGS_time_limit_use_instruction_count)) {
527 return perf_subsystem_.ReadCounters().GetScaledOrDie(
528 GetInstructionRetiredEventName());
535 if (external_boolean_as_limit_ !=
nullptr &&
536 external_boolean_as_limit_->load()) {
544#ifdef HAS_PERF_SUBSYSTEM
550 const int64_t current_ns = absl::GetCurrentTimeNanos();
551 running_max_.Add(
std::max(safety_buffer_ns_, current_ns - last_ns_));
552 last_ns_ = current_ns;
553 if (current_ns + running_max_.GetCurrentMax() >= limit_ns_) {
554 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
558 const double time_left_s = limit_in_seconds_ - user_timer_.
Get();
560 limit_ns_ =
static_cast<int64_t
>(time_left_s * 1e9) + last_ns_;
573 if (limit_ns_ ==
kint64max)
return std::numeric_limits<double>::infinity();
574 const int64_t delta_ns = limit_ns_ - absl::GetCurrentTimeNanos();
575 if (delta_ns < 0)
return 0.0;
576 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
577 return std::max(limit_in_seconds_ - user_timer_.
Get(), 0.0);
579 return delta_ns * 1e-9;
#define DCHECK_LE(val1, val2)
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.
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 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...
static const double kSafetyBufferSeconds
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.
std::atomic< bool > * ExternalBooleanAsLimit() const
Returns the current external Boolean limit.
friend class ParallelTimeLimit
double ReadInstructionCounter()
Returns the number of instructions executed since the creation of this object.
void RegisterExternalBooleanAsLimit(std::atomic< bool > *external_boolean_as_limit)
Registers the external Boolean to check when LimitReached() is called.
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 > Infinite()
Creates a time limit object that uses infinite time for wall time, deterministic time and instruction...
static std::unique_ptr< TimeLimit > FromDeterministicTime(double deterministic_limit)
Creates a time limit object that puts limit only on the deterministic time.
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)
TimeLimit & operator=(const TimeLimit &)=delete
double GetElapsedTime() const
Returns the time elapsed in seconds since the construction of this object.
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.