14#ifndef OR_TOOLS_UTIL_TIME_LIMIT_H_
15#define OR_TOOLS_UTIL_TIME_LIMIT_H_
25#include "absl/base/thread_annotations.h"
26#include "absl/container/flat_hash_map.h"
27#include "absl/flags/declare.h"
28#include "absl/flags/flag.h"
29#include "absl/log/check.h"
30#include "absl/synchronization/mutex.h"
31#include "absl/time/clock.h"
32#include "absl/time/time.h"
109 double limit_in_seconds,
110 double deterministic_limit = std::numeric_limits<double>::infinity());
121 return std::make_unique<TimeLimit>(std::numeric_limits<double>::infinity(),
122 std::numeric_limits<double>::infinity());
129 double deterministic_limit) {
130 return std::make_unique<TimeLimit>(std::numeric_limits<double>::infinity(),
131 deterministic_limit);
140 template <
typename Parameters>
142 const Parameters& parameters) {
143 return std::make_unique<TimeLimit>(parameters.max_time_in_seconds(),
144 parameters.max_deterministic_time());
167 double GetTimeLeft()
const;
176 return std::max(0.0, deterministic_limit_ - elapsed_deterministic_time_);
185 DCHECK_LE(0.0, deterministic_duration);
186 elapsed_deterministic_time_ += deterministic_duration;
199 const char* counter_name) {
202 deterministic_counters_[counter_name] += deterministic_duration;
210 return 1e-9 * (absl::GetCurrentTimeNanos() - start_ns_);
219 return elapsed_deterministic_time_;
232 std::atomic<bool>* external_boolean_as_limit) {
233 external_boolean_as_limit_ = external_boolean_as_limit;
245 std::atomic<bool>* external_boolean_as_limit) {
246 secondary_external_boolean_as_limit_ = external_boolean_as_limit;
253 return external_boolean_as_limit_;
260 template <
typename Parameters>
261 void ResetLimitFromParameters(
const Parameters& parameters);
268 void MergeWithGlobalTimeLimit(
const TimeLimit* other);
274 deterministic_limit_ = new_limit;
293 std::string DebugString()
const;
296 void ResetTimers(
double limit_in_seconds,
double deterministic_limit);
298 mutable int64_t start_ns_;
302 const int64_t safety_buffer_ns_;
307 double limit_in_seconds_;
309 double deterministic_limit_;
310 double elapsed_deterministic_time_;
312 std::atomic<bool>* external_boolean_as_limit_ =
nullptr;
313 std::atomic<bool>* secondary_external_boolean_as_limit_ =
nullptr;
317 absl::flat_hash_map<std::string, double> deterministic_counters_;
328 : time_limit_(
time_limit), stopped_boolean_(false) {
330 stopped_ =
time_limit->ExternalBooleanAsLimit();
331 if (stopped_ ==
nullptr) {
332 stopped_ = &stopped_boolean_;
333 time_limit->RegisterExternalBooleanAsLimit(stopped_);
338 if (stopped_ == &stopped_boolean_) {
339 time_limit_->RegisterExternalBooleanAsLimit(
nullptr);
346 absl::MutexLock lock(&mutex_);
347 return time_limit_->LimitReached();
351 absl::MutexLock lock(&mutex_);
356 absl::MutexLock lock(&mutex_);
361 absl::MutexLock lock(&mutex_);
362 time_limit_->AdvanceDeterministicTime(deterministic_duration);
366 absl::ReaderMutexLock lock(&mutex_);
367 return time_limit_->GetTimeLeft();
371 absl::ReaderMutexLock lock(&mutex_);
372 return time_limit_->GetElapsedDeterministicTime();
376 absl::ReaderMutexLock lock(&mutex_);
379 return time_limit_->ExternalBooleanAsLimit();
383 mutable absl::Mutex mutex_;
384 TimeLimit* time_limit_ ABSL_GUARDED_BY(mutex_);
385 std::atomic<bool> stopped_boolean_ ABSL_GUARDED_BY(mutex_);
386 std::atomic<bool>* stopped_ ABSL_GUARDED_BY(mutex_);
426 double deterministic_limit);
444 template <
typename Parameters>
447 return std::make_unique<NestedTimeLimit>(
449 parameters.max_deterministic_time());
471 if (count_++ == frequency_) {
472 if (time_limit_->LimitReached()) {
483 bool stopped_ =
false;
485 const int frequency_;
490inline void TimeLimit::ResetTimers(
double limit_in_seconds,
491 double deterministic_limit) {
492 elapsed_deterministic_time_ = 0.0;
493 deterministic_limit_ = deterministic_limit;
495 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
497 limit_in_seconds_ = limit_in_seconds;
499 start_ns_ = absl::GetCurrentTimeNanos();
500 last_ns_ = start_ns_;
502 limit_ns_ = (absl::Seconds(limit_in_seconds) + absl::Nanoseconds(start_ns_)) /
503 absl::Nanoseconds(1);
506template <
typename Parameters>
508 ResetTimers(parameters.max_time_in_seconds(),
509 parameters.max_deterministic_time());
513 if (other ==
nullptr)
return;
523 if (external_boolean_as_limit_ !=
nullptr &&
524 external_boolean_as_limit_->load()) {
527 if (secondary_external_boolean_as_limit_ !=
nullptr &&
528 secondary_external_boolean_as_limit_->load()) {
536 const int64_t current_ns = absl::GetCurrentTimeNanos();
537 running_max_.Add(std::max(safety_buffer_ns_, current_ns - last_ns_));
538 last_ns_ = current_ns;
539 if (current_ns + running_max_.GetCurrentMax() >= limit_ns_) {
540 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
544 const double time_left_s = limit_in_seconds_ - user_timer_.Get();
546 limit_ns_ =
static_cast<int64_t
>(time_left_s * 1e9) + last_ns_;
559 if (limit_ns_ ==
kint64max)
return std::numeric_limits<double>::infinity();
560 const int64_t delta_ns = limit_ns_ - absl::GetCurrentTimeNanos();
561 if (delta_ns < 0)
return 0.0;
562 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
563 return std::max(limit_in_seconds_ - user_timer_.Get(), 0.0);
565 return delta_ns * 1e-9;
void Start()
When Start() is called multiple times, only the most recent is used.
static std::unique_ptr< NestedTimeLimit > FromBaseTimeLimitAndParameters(TimeLimit *time_limit, const Parameters ¶meters)
NestedTimeLimit(const NestedTimeLimit &)=delete
This type is neither copyable nor movable.
NestedTimeLimit(TimeLimit *base_time_limit, double limit_in_seconds, double deterministic_limit)
TimeLimit * GetTimeLimit()
NestedTimeLimit & operator=(const NestedTimeLimit &)=delete
double GetElapsedDeterministicTime() const
void UpdateLocalLimit(TimeLimit *local_limit)
void AdvanceDeterministicTime(double deterministic_duration)
std::atomic< bool > * ExternalBooleanAsLimit() const
double GetTimeLeft() const
bool LimitReached() const
SharedTimeLimit(TimeLimit *time_limit)
TimeLimitCheckEveryNCalls(int N, TimeLimit *time_limit)
TimeLimit & operator=(const TimeLimit &)=delete
static std::unique_ptr< TimeLimit > FromParameters(const Parameters ¶meters)
double GetTimeLeft() const
TimeLimit(const TimeLimit &)=delete
TimeLimit(double limit_in_seconds, double deterministic_limit=std::numeric_limits< double >::infinity())
void MergeWithGlobalTimeLimit(const TimeLimit *other)
friend class ParallelTimeLimit
double GetDeterministicLimit() const
void AdvanceDeterministicTime(double deterministic_duration)
friend class NestedTimeLimit
std::atomic< bool > * ExternalBooleanAsLimit() const
double GetElapsedDeterministicTime() const
static std::unique_ptr< TimeLimit > Infinite()
void AdvanceDeterministicTime(double deterministic_duration, const char *counter_name)
void RegisterExternalBooleanAsLimit(std::atomic< bool > *external_boolean_as_limit)
void RegisterSecondaryExternalBooleanAsLimit(std::atomic< bool > *external_boolean_as_limit)
double GetDeterministicTimeLeft() const
static const int kHistorySize
static std::unique_ptr< TimeLimit > FromDeterministicTime(double deterministic_limit)
static const double kSafetyBufferSeconds
static constants.
void ResetLimitFromParameters(const Parameters ¶meters)
void ChangeDeterministicLimit(double new_limit)
double GetElapsedTime() const
In SWIG mode, we don't want anything besides these top-level includes.
OR_DLL ABSL_DECLARE_FLAG(bool, time_limit_use_usertime)
static const int64_t kint64max