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>
298 deterministic_limit_ = new_limit;
312 void ResetTimers(
double limit_in_seconds,
double deterministic_limit,
313 double instruction_limit);
315 std::string GetInstructionRetiredEventName()
const {
316 return "inst_retired:any_p:u";
319 mutable int64_t start_ns_;
323 const int64_t safety_buffer_ns_;
324 RunningMax<int64_t> running_max_;
328 double limit_in_seconds_;
330 double deterministic_limit_;
331 double elapsed_deterministic_time_;
333 std::atomic<bool>* external_boolean_as_limit_;
335#ifdef HAS_PERF_SUBSYSTEM
337 exegesis::PerfSubsystem perf_subsystem_;
340 double instruction_limit_;
344 absl::flat_hash_map<std::string, double> deterministic_counters_;
355 : time_limit_(
time_limit), stopped_boolean_(false) {
357 stopped_ =
time_limit->ExternalBooleanAsLimit();
358 if (stopped_ ==
nullptr) {
359 stopped_ = &stopped_boolean_;
360 time_limit->RegisterExternalBooleanAsLimit(stopped_);
365 if (stopped_ == &stopped_boolean_) {
366 time_limit_->RegisterExternalBooleanAsLimit(
nullptr);
373 absl::MutexLock lock(&mutex_);
374 return time_limit_->LimitReached();
378 absl::MutexLock lock(&mutex_);
383 absl::MutexLock lock(&mutex_);
388 absl::MutexLock lock(&mutex_);
389 time_limit_->AdvanceDeterministicTime(deterministic_duration);
393 absl::ReaderMutexLock lock(&mutex_);
394 return time_limit_->GetTimeLeft();
398 absl::ReaderMutexLock lock(&mutex_);
399 return time_limit_->GetElapsedDeterministicTime();
403 mutable absl::Mutex mutex_;
404 TimeLimit* time_limit_ ABSL_GUARDED_BY(mutex_);
405 std::atomic<bool> stopped_boolean_ ABSL_GUARDED_BY(mutex_);
406 std::atomic<bool>* stopped_ ABSL_GUARDED_BY(mutex_);
446 double deterministic_limit);
460 template <
typename Parameters>
463 return absl::make_unique<NestedTimeLimit>(
486 double instruction_limit)
487 : safety_buffer_ns_(static_cast<int64_t>(kSafetyBufferSeconds * 1e9)),
488 running_max_(kHistorySize),
489 external_boolean_as_limit_(nullptr) {
490 ResetTimers(limit_in_seconds, deterministic_limit, instruction_limit);
493inline void TimeLimit::ResetTimers(
double limit_in_seconds,
494 double deterministic_limit,
495 double instruction_limit) {
496 elapsed_deterministic_time_ = 0.0;
497 deterministic_limit_ = deterministic_limit;
498 instruction_limit_ = instruction_limit;
500 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
502 limit_in_seconds_ = limit_in_seconds;
504#ifdef HAS_PERF_SUBSYSTEM
505 if (absl::GetFlag(FLAGS_time_limit_use_instruction_count)) {
506 perf_subsystem_.CleanUp();
507 perf_subsystem_.AddEvent(GetInstructionRetiredEventName());
508 perf_subsystem_.StartCollecting();
511 start_ns_ = absl::GetCurrentTimeNanos();
512 last_ns_ = start_ns_;
513 limit_ns_ = limit_in_seconds >= 1e-9 * (
kint64max - start_ns_)
515 :
static_cast<int64_t
>(limit_in_seconds * 1e9) + start_ns_;
518template <
typename Parameters>
522 std::numeric_limits<double>::infinity());
526 if (other ==
nullptr)
return;
530 std::numeric_limits<double>::infinity());
537#ifdef HAS_PERF_SUBSYSTEM
538 if (absl::GetFlag(FLAGS_time_limit_use_instruction_count)) {
539 return perf_subsystem_.ReadCounters().GetScaledOrDie(
540 GetInstructionRetiredEventName());
547 if (external_boolean_as_limit_ !=
nullptr &&
548 external_boolean_as_limit_->load()) {
556#ifdef HAS_PERF_SUBSYSTEM
562 const int64_t current_ns = absl::GetCurrentTimeNanos();
563 running_max_.
Add(
std::max(safety_buffer_ns_, current_ns - last_ns_));
564 last_ns_ = current_ns;
565 if (current_ns + running_max_.
GetCurrentMax() >= limit_ns_) {
566 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
570 const double time_left_s = limit_in_seconds_ - user_timer_.
Get();
572 limit_ns_ =
static_cast<int64_t
>(time_left_s * 1e9) + last_ns_;
585 if (limit_ns_ ==
kint64max)
return std::numeric_limits<double>::infinity();
586 const int64_t delta_ns = limit_ns_ - absl::GetCurrentTimeNanos();
587 if (delta_ns < 0)
return 0.0;
588 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
589 return std::max(limit_in_seconds_ - user_timer_.
Get(), 0.0);
591 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.
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 > 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 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.