14#ifndef ORTOOLS_UTIL_TIME_LIMIT_H_
15#define ORTOOLS_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"
111 double limit_in_seconds,
112 double deterministic_limit = std::numeric_limits<double>::infinity());
123 return std::make_unique<TimeLimit>(std::numeric_limits<double>::infinity(),
124 std::numeric_limits<double>::infinity());
131 double deterministic_limit) {
132 return std::make_unique<TimeLimit>(std::numeric_limits<double>::infinity(),
133 deterministic_limit);
142 template <
typename Parameters>
144 const Parameters& parameters) {
145 return std::make_unique<TimeLimit>(parameters.max_time_in_seconds(),
146 parameters.max_deterministic_time());
169 double GetTimeLeft()
const;
178 return std::max(0.0, deterministic_limit_ - elapsed_deterministic_time_);
187 DCHECK_LE(0.0, deterministic_duration);
188 elapsed_deterministic_time_ += deterministic_duration;
201 const char* counter_name) {
204 deterministic_counters_[counter_name] += deterministic_duration;
212 return 1e-9 * (absl::GetCurrentTimeNanos() - start_ns_);
221 return elapsed_deterministic_time_;
234 std::atomic<bool>* external_boolean_as_limit) {
235 external_boolean_as_limit_ = external_boolean_as_limit;
247 std::atomic<bool>* external_boolean_as_limit) {
248 secondary_external_boolean_as_limit_ = external_boolean_as_limit;
255 return external_boolean_as_limit_;
262 template <
typename Parameters>
263 void ResetLimitFromParameters(
const Parameters& parameters);
270 void MergeWithGlobalTimeLimit(
const TimeLimit* other);
276 deterministic_limit_ = new_limit;
295 std::string DebugString()
const;
298 void ResetTimers(
double limit_in_seconds,
double deterministic_limit);
300 mutable int64_t start_ns_;
304 const int64_t safety_buffer_ns_;
309 double limit_in_seconds_;
311 double deterministic_limit_;
312 double elapsed_deterministic_time_;
314 std::atomic<bool>* external_boolean_as_limit_ =
nullptr;
315 std::atomic<bool>* secondary_external_boolean_as_limit_ =
nullptr;
319 absl::flat_hash_map<std::string, double> deterministic_counters_;
330 : time_limit_(time_limit), stopped_boolean_(false) {
333 if (stopped_ ==
nullptr) {
334 stopped_ = &stopped_boolean_;
340 if (stopped_ == &stopped_boolean_) {
341 time_limit_->RegisterExternalBooleanAsLimit(
nullptr);
348 absl::MutexLock lock(mutex_);
349 return time_limit_->LimitReached();
353 absl::MutexLock lock(mutex_);
358 absl::MutexLock lock(mutex_);
363 absl::MutexLock lock(mutex_);
364 time_limit_->AdvanceDeterministicTime(deterministic_duration);
368 absl::ReaderMutexLock lock(mutex_);
369 return time_limit_->GetTimeLeft();
373 absl::ReaderMutexLock lock(mutex_);
374 return time_limit_->GetElapsedDeterministicTime();
378 absl::ReaderMutexLock lock(mutex_);
381 return time_limit_->ExternalBooleanAsLimit();
385 mutable absl::Mutex mutex_;
386 TimeLimit* time_limit_ ABSL_GUARDED_BY(mutex_);
387 std::atomic<bool> stopped_boolean_ ABSL_GUARDED_BY(mutex_);
388 std::atomic<bool>* stopped_ ABSL_GUARDED_BY(mutex_);
428 double deterministic_limit);
446 template <
typename Parameters>
448 TimeLimit* time_limit,
const Parameters& parameters) {
449 return std::make_unique<NestedTimeLimit>(
450 time_limit, parameters.max_time_in_seconds(),
451 parameters.max_deterministic_time());
470 : time_limit_(time_limit), frequency_(N) {}
473 if (count_++ == frequency_) {
474 if (time_limit_->LimitReached()) {
485 bool stopped_ =
false;
487 const int frequency_;
492inline void TimeLimit::ResetTimers(
double limit_in_seconds,
493 double deterministic_limit) {
494 elapsed_deterministic_time_ = 0.0;
495 deterministic_limit_ = deterministic_limit;
497 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
499 limit_in_seconds_ = limit_in_seconds;
501 start_ns_ = absl::GetCurrentTimeNanos();
502 last_ns_ = start_ns_;
504 limit_ns_ = (absl::Seconds(limit_in_seconds) + absl::Nanoseconds(start_ns_)) /
505 absl::Nanoseconds(1);
508template <
typename Parameters>
510 ResetTimers(parameters.max_time_in_seconds(),
511 parameters.max_deterministic_time());
515 if (other ==
nullptr)
return;
525 if (external_boolean_as_limit_ !=
nullptr &&
526 external_boolean_as_limit_->load()) {
529 if (secondary_external_boolean_as_limit_ !=
nullptr &&
530 secondary_external_boolean_as_limit_->load()) {
538 const int64_t current_ns = absl::GetCurrentTimeNanos();
539 running_max_.Add(std::max(safety_buffer_ns_, current_ns - last_ns_));
540 last_ns_ = current_ns;
541 if (current_ns + running_max_.GetCurrentMax() >= limit_ns_) {
542 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
546 const double time_left_s = limit_in_seconds_ - user_timer_.Get();
548 limit_ns_ =
static_cast<int64_t
>(time_left_s * 1e9) + last_ns_;
561 if (limit_ns_ ==
kint64max)
return std::numeric_limits<double>::infinity();
562 const int64_t delta_ns = limit_ns_ - absl::GetCurrentTimeNanos();
563 if (delta_ns < 0)
return 0.0;
564 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
565 return std::max(limit_in_seconds_ - user_timer_.Get(), 0.0);
567 return delta_ns * 1e-9;
static std::unique_ptr< NestedTimeLimit > FromBaseTimeLimitAndParameters(TimeLimit *time_limit, const Parameters ¶meters)
NestedTimeLimit(const NestedTimeLimit &)=delete
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
void ResetLimitFromParameters(const Parameters ¶meters)
void ChangeDeterministicLimit(double new_limit)
double GetElapsedTime() const
OR_DLL ABSL_DECLARE_FLAG(bool, time_limit_use_usertime)
static const int64_t kint64max