14 #ifndef OR_TOOLS_UTIL_TIME_LIMIT_H_
15 #define OR_TOOLS_UTIL_TIME_LIMIT_H_
24 #include "absl/container/flat_hash_map.h"
25 #include "absl/memory/memory.h"
26 #include "absl/synchronization/mutex.h"
27 #include "absl/time/clock.h"
33 #ifdef HAS_PERF_SUBSYSTEM
34 #include "exegesis/exegesis/itineraries/perf_subsystem.h"
35 #endif // HAS_PERF_SUBSYSTEM
122 double limit_in_seconds,
123 double deterministic_limit = std::numeric_limits<double>::infinity(),
124 double instruction_limit = std::numeric_limits<double>::infinity());
135 return absl::make_unique<TimeLimit>(
136 std::numeric_limits<double>::infinity(),
137 std::numeric_limits<double>::infinity(),
138 std::numeric_limits<double>::infinity());
145 double deterministic_limit) {
146 return absl::make_unique<TimeLimit>(
147 std::numeric_limits<double>::infinity(), deterministic_limit,
148 std::numeric_limits<double>::infinity());
158 template <
typename Parameters>
161 return absl::make_unique<TimeLimit>(
163 std::numeric_limits<double>::infinity());
172 instruction_limit_ = instruction_limit;
213 return std::max(0.0, deterministic_limit_ - elapsed_deterministic_time_);
228 elapsed_deterministic_time_ += deterministic_duration;
241 const char* counter_name) {
244 deterministic_counters_[counter_name] += deterministic_duration;
252 return 1e-9 * (absl::GetCurrentTimeNanos() - start_ns_);
261 return elapsed_deterministic_time_;
273 std::atomic<bool>* external_boolean_as_limit) {
274 external_boolean_as_limit_ = external_boolean_as_limit;
281 return external_boolean_as_limit_;
288 template <
typename Parameters>
298 void ResetTimers(
double limit_in_seconds,
double deterministic_limit,
299 double instruction_limit);
301 std::string GetInstructionRetiredEventName()
const {
302 return "inst_retired:any_p:u";
305 mutable int64 start_ns_;
309 const int64 safety_buffer_ns_;
310 RunningMax<int64> running_max_;
314 double limit_in_seconds_;
316 double deterministic_limit_;
317 double elapsed_deterministic_time_;
319 std::atomic<bool>* external_boolean_as_limit_;
321 #ifdef HAS_PERF_SUBSYSTEM
323 exegesis::PerfSubsystem perf_subsystem_;
324 #endif // HAS_PERF_SUBSYSTEM
326 double instruction_limit_;
330 absl::flat_hash_map<std::string, double> deterministic_counters_;
341 : time_limit_(
time_limit), stopped_boolean_(false) {
343 stopped_ =
time_limit->ExternalBooleanAsLimit();
344 if (stopped_ ==
nullptr) {
345 stopped_ = &stopped_boolean_;
346 time_limit->RegisterExternalBooleanAsLimit(stopped_);
351 if (stopped_ == &stopped_boolean_) {
352 time_limit_->RegisterExternalBooleanAsLimit(
nullptr);
359 absl::MutexLock lock(&mutex_);
360 return time_limit_->LimitReached();
364 absl::MutexLock lock(&mutex_);
369 absl::MutexLock lock(&mutex_);
374 absl::MutexLock lock(&mutex_);
375 time_limit_->AdvanceDeterministicTime(deterministic_duration);
379 absl::ReaderMutexLock lock(&mutex_);
380 return time_limit_->GetTimeLeft();
384 absl::ReaderMutexLock lock(&mutex_);
385 return time_limit_->GetElapsedDeterministicTime();
389 mutable absl::Mutex mutex_;
390 TimeLimit* time_limit_ ABSL_GUARDED_BY(mutex_);
391 std::atomic<bool> stopped_boolean_ ABSL_GUARDED_BY(mutex_);
392 std::atomic<bool>* stopped_ ABSL_GUARDED_BY(mutex_);
432 double deterministic_limit);
446 template <
typename Parameters>
449 return absl::make_unique<NestedTimeLimit>(
472 double instruction_limit)
473 : safety_buffer_ns_(static_cast<
int64>(kSafetyBufferSeconds * 1e9)),
474 running_max_(kHistorySize),
475 external_boolean_as_limit_(nullptr) {
476 ResetTimers(limit_in_seconds, deterministic_limit, instruction_limit);
479 inline void TimeLimit::ResetTimers(
double limit_in_seconds,
480 double deterministic_limit,
481 double instruction_limit) {
482 elapsed_deterministic_time_ = 0.0;
483 deterministic_limit_ = deterministic_limit;
484 instruction_limit_ = instruction_limit;
486 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
488 limit_in_seconds_ = limit_in_seconds;
490 #ifdef HAS_PERF_SUBSYSTEM
491 if (absl::GetFlag(FLAGS_time_limit_use_instruction_count)) {
492 perf_subsystem_.CleanUp();
493 perf_subsystem_.AddEvent(GetInstructionRetiredEventName());
494 perf_subsystem_.StartCollecting();
496 #endif // HAS_PERF_SUBSYSTEM
497 start_ns_ = absl::GetCurrentTimeNanos();
498 last_ns_ = start_ns_;
499 limit_ns_ = limit_in_seconds >= 1e-9 * (
kint64max - start_ns_)
501 :
static_cast<int64>(limit_in_seconds * 1e9) + start_ns_;
504 template <
typename Parameters>
508 std::numeric_limits<double>::infinity());
512 if (other ==
nullptr)
return;
516 std::numeric_limits<double>::infinity());
523 #ifdef HAS_PERF_SUBSYSTEM
524 if (absl::GetFlag(FLAGS_time_limit_use_instruction_count)) {
525 return perf_subsystem_.ReadCounters().GetScaledOrDie(
526 GetInstructionRetiredEventName());
528 #endif // HAS_PERF_SUBSYSTEM
533 if (external_boolean_as_limit_ !=
nullptr &&
534 external_boolean_as_limit_->load()) {
542 #ifdef HAS_PERF_SUBSYSTEM
546 #endif // HAS_PERF_SUBSYSTEM
548 const int64 current_ns = absl::GetCurrentTimeNanos();
549 running_max_.
Add(
std::max(safety_buffer_ns_, current_ns - last_ns_));
550 last_ns_ = current_ns;
551 if (current_ns + running_max_.
GetCurrentMax() >= limit_ns_) {
552 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
556 const double time_left_s = limit_in_seconds_ - user_timer_.
Get();
558 limit_ns_ =
static_cast<int64>(time_left_s * 1e9) + last_ns_;
571 if (limit_ns_ ==
kint64max)
return std::numeric_limits<double>::infinity();
572 const int64 delta_ns = limit_ns_ - absl::GetCurrentTimeNanos();
573 if (delta_ns < 0)
return 0.0;
574 if (absl::GetFlag(FLAGS_time_limit_use_usertime)) {
575 return std::max(limit_in_seconds_ - user_timer_.
Get(), 0.0);
577 return delta_ns * 1e-9;
587 #endif // OR_TOOLS_UTIL_TIME_LIMIT_H_