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"
108 double limit_in_seconds,
109 double deterministic_limit = std::numeric_limits<double>::infinity());
120 return std::make_unique<TimeLimit>(std::numeric_limits<double>::infinity(),
121 std::numeric_limits<double>::infinity());
128 double deterministic_limit) {
129 return std::make_unique<TimeLimit>(std::numeric_limits<double>::infinity(),
130 deterministic_limit);
139 template <
typename Parameters>
142 return std::make_unique<TimeLimit>(
parameters.max_time_in_seconds(),
175 return std::max(0.0, deterministic_limit_ - elapsed_deterministic_time_);
184 DCHECK_LE(0.0, deterministic_duration);
185 elapsed_deterministic_time_ += deterministic_duration;
198 const char* counter_name) {
201 deterministic_counters_[counter_name] += deterministic_duration;
209 return 1e-9 * (absl::GetCurrentTimeNanos() - start_ns_);
218 return elapsed_deterministic_time_;
231 std::atomic<bool>* external_boolean_as_limit) {
232 external_boolean_as_limit_ = external_boolean_as_limit;
244 std::atomic<bool>* external_boolean_as_limit) {
245 secondary_external_boolean_as_limit_ = external_boolean_as_limit;
252 return external_boolean_as_limit_;
259 template <
typename Parameters>
273 deterministic_limit_ = new_limit;
287 void ResetTimers(
double limit_in_seconds,
double deterministic_limit);
289 mutable int64_t start_ns_;
293 const int64_t safety_buffer_ns_;
298 double limit_in_seconds_;
300 double deterministic_limit_;
301 double elapsed_deterministic_time_;
303 std::atomic<bool>* external_boolean_as_limit_ =
nullptr;
304 std::atomic<bool>* secondary_external_boolean_as_limit_ =
nullptr;
308 absl::flat_hash_map<std::string, double> deterministic_counters_;
319 : time_limit_(
time_limit), stopped_boolean_(false) {
321 stopped_ =
time_limit->ExternalBooleanAsLimit();
322 if (stopped_ ==
nullptr) {
323 stopped_ = &stopped_boolean_;
324 time_limit->RegisterExternalBooleanAsLimit(stopped_);
329 if (stopped_ == &stopped_boolean_) {
330 time_limit_->RegisterExternalBooleanAsLimit(
nullptr);
337 absl::MutexLock lock(&mutex_);
338 return time_limit_->LimitReached();
342 absl::MutexLock lock(&mutex_);
347 absl::MutexLock lock(&mutex_);
352 absl::MutexLock lock(&mutex_);
353 time_limit_->AdvanceDeterministicTime(deterministic_duration);
357 absl::ReaderMutexLock lock(&mutex_);
358 return time_limit_->GetTimeLeft();
362 absl::ReaderMutexLock lock(&mutex_);
363 return time_limit_->GetElapsedDeterministicTime();
367 absl::ReaderMutexLock lock(&mutex_);
370 return time_limit_->ExternalBooleanAsLimit();
374 mutable absl::Mutex mutex_;
375 TimeLimit* time_limit_ ABSL_GUARDED_BY(mutex_);
376 std::atomic<bool> stopped_boolean_ ABSL_GUARDED_BY(mutex_);
377 std::atomic<bool>* stopped_ ABSL_GUARDED_BY(mutex_);
417 double deterministic_limit);
435 template <
typename Parameters>
438 return std::make_unique<NestedTimeLimit>(
459 : safety_buffer_ns_(static_cast<int64_t>(kSafetyBufferSeconds * 1e9)),
460 running_max_(kHistorySize),
461 external_boolean_as_limit_(nullptr) {
462 ResetTimers(limit_in_seconds, deterministic_limit);
465inline void TimeLimit::ResetTimers(
double limit_in_seconds,
466 double deterministic_limit) {
467 elapsed_deterministic_time_ = 0.0;
468 deterministic_limit_ = deterministic_limit;
470 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
472 limit_in_seconds_ = limit_in_seconds;
474 start_ns_ = absl::GetCurrentTimeNanos();
475 last_ns_ = start_ns_;
477 limit_ns_ = (absl::Seconds(limit_in_seconds) + absl::Nanoseconds(start_ns_)) /
478 absl::Nanoseconds(1);
481template <
typename Parameters>
488 if (other ==
nullptr)
return;
498 if (external_boolean_as_limit_ !=
nullptr &&
499 external_boolean_as_limit_->load()) {
502 if (secondary_external_boolean_as_limit_ !=
nullptr &&
503 secondary_external_boolean_as_limit_->load()) {
511 const int64_t current_ns = absl::GetCurrentTimeNanos();
512 running_max_.
Add(std::max(safety_buffer_ns_, current_ns - last_ns_));
513 last_ns_ = current_ns;
514 if (current_ns + running_max_.
GetCurrentMax() >= limit_ns_) {
515 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
519 const double time_left_s = limit_in_seconds_ - user_timer_.
Get();
521 limit_ns_ =
static_cast<int64_t
>(time_left_s * 1e9) + last_ns_;
534 if (limit_ns_ ==
kint64max)
return std::numeric_limits<double>::infinity();
535 const int64_t delta_ns = limit_ns_ - absl::GetCurrentTimeNanos();
536 if (delta_ns < 0)
return 0.0;
537 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
538 return std::max(limit_in_seconds_ - user_timer_.
Get(), 0.0);
540 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
void Add(Number value)
Processes a new element from the stream.
Wrapper around TimeLimit to make it thread safe and add Stop() support.
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)
TimeLimit & operator=(const TimeLimit &)=delete
static std::unique_ptr< TimeLimit > FromParameters(const Parameters ¶meters)
double GetTimeLeft() const
TimeLimit(const TimeLimit &)=delete
friend class ParallelTimeLimit
double GetDeterministicLimit() const
void AdvanceDeterministicTime(double deterministic_duration)
std::atomic< bool > * ExternalBooleanAsLimit() const
void MergeWithGlobalTimeLimit(TimeLimit *other)
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
std::string DebugString() const
In SWIG mode, we don't want anything besides these top-level includes.
ABSL_DECLARE_FLAG(bool, time_limit_use_usertime)
static const int64_t kint64max