OR-Tools  9.6
stats.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #include "ortools/util/stats.h"
15 
16 #include <algorithm>
17 #include <cmath>
18 #include <string>
19 #include <vector>
20 
21 #include "absl/log/check.h"
22 #include "absl/strings/str_format.h"
24 #include "ortools/base/logging.h"
25 #include "ortools/base/stl_util.h"
26 #include "ortools/port/sysinfo.h"
27 #include "ortools/port/utf8.h"
28 
29 namespace operations_research {
30 
31 std::string MemoryUsage() {
33  static const int64_t kDisplayThreshold = 2;
34  static const int64_t kKiloByte = 1024;
35  static const int64_t kMegaByte = kKiloByte * kKiloByte;
36  static const int64_t kGigaByte = kMegaByte * kKiloByte;
37  if (mem > kDisplayThreshold * kGigaByte) {
38  return absl::StrFormat("%.2lf GB", mem * 1.0 / kGigaByte);
39  } else if (mem > kDisplayThreshold * kMegaByte) {
40  return absl::StrFormat("%.2lf MB", mem * 1.0 / kMegaByte);
41  } else if (mem > kDisplayThreshold * kKiloByte) {
42  return absl::StrFormat("%2lf KB", mem * 1.0 / kKiloByte);
43  } else {
44  return absl::StrFormat("%d", mem);
45  }
46 }
47 
48 Stat::Stat(absl::string_view name, StatsGroup* group) : name_(name) {
49  group->Register(this);
50 }
51 
52 std::string Stat::StatString() const { return name_ + ": " + ValueAsString(); }
53 
54 StatsGroup::~StatsGroup() { gtl::STLDeleteValues(&time_distributions_); }
55 
56 void StatsGroup::Register(Stat* stat) { stats_.push_back(stat); }
57 
59  for (int i = 0; i < stats_.size(); ++i) {
60  stats_[i]->Reset();
61  }
62 }
63 
64 namespace {
65 
66 bool CompareStatPointers(const Stat* s1, const Stat* s2) {
67  if (s1->Priority() == s2->Priority()) {
68  if (s1->Sum() == s2->Sum()) return s1->Name() < s2->Name();
69  return (s1->Sum() > s2->Sum());
70  } else {
71  return (s1->Priority() > s2->Priority());
72  }
73 }
74 
75 } // namespace
76 
77 std::string StatsGroup::StatString() const {
78  // Computes the longest name of all the stats we want to display.
79  // Also create a temporary vector so we can sort the stats by names.
80  int longest_name_size = 0;
81  std::vector<Stat*> sorted_stats;
82  for (int i = 0; i < stats_.size(); ++i) {
83  if (!stats_[i]->WorthPrinting()) continue;
84  // We support UTF8 characters in the stat names.
85  const int size = operations_research::utf8::UTF8StrLen(stats_[i]->Name());
86  longest_name_size = std::max(longest_name_size, size);
87  sorted_stats.push_back(stats_[i]);
88  }
89  switch (print_order_) {
91  std::sort(sorted_stats.begin(), sorted_stats.end(), CompareStatPointers);
92  break;
93  case SORT_BY_NAME:
94  std::sort(sorted_stats.begin(), sorted_stats.end(),
95  [](const Stat* s1, const Stat* s2) -> bool {
96  return s1->Name() < s2->Name();
97  });
98  break;
99  default:
100  LOG(FATAL) << "Unknown print order: " << print_order_;
101  }
102 
103  // Do not display groups without print-worthy stats.
104  if (sorted_stats.empty()) return "";
105 
106  // Pretty-print all the stats.
107  std::string result(name_ + " {\n");
108  for (int i = 0; i < sorted_stats.size(); ++i) {
109  result += " ";
110  result += sorted_stats[i]->Name();
111  result.append(longest_name_size - operations_research::utf8::UTF8StrLen(
112  sorted_stats[i]->Name()),
113  ' ');
114  result += " : " + sorted_stats[i]->ValueAsString();
115  }
116  result += "}\n";
117  return result;
118 }
119 
121  TimeDistribution*& ref = time_distributions_[name];
122  if (ref == nullptr) {
123  ref = new TimeDistribution(name);
124  Register(ref);
125  }
126  return ref;
127 }
128 
130  : Stat(name),
131  sum_(0.0),
132  average_(0.0),
133  sum_squares_from_average_(0.0),
134  min_(0.0),
135  max_(0.0),
136  num_(0) {}
137 
139  : Stat(name, group),
140  sum_(0.0),
141  average_(0.0),
142  sum_squares_from_average_(0.0),
143  min_(0.0),
144  max_(0.0),
145  num_(0) {}
146 
148  sum_ = 0.0;
149  average_ = 0.0;
151  min_ = 0.0;
152  max_ = 0.0;
153  num_ = 0;
154 }
155 
157  if (num_ == 0) {
158  min_ = value;
159  max_ = value;
160  sum_ = value;
161  average_ = value;
162  num_ = 1;
163  return;
164  }
165  min_ = std::min(min_, value);
166  max_ = std::max(max_, value);
167  sum_ += value;
168  ++num_;
169  const double delta = value - average_;
170  average_ = sum_ / num_;
172 }
173 
174 double DistributionStat::Average() const { return average_; }
175 
177  if (num_ == 0) return 0.0;
178  return sqrt(sum_squares_from_average_ / num_);
179 }
180 
181 double TimeDistribution::CyclesToSeconds(double cycles) {
182  const double seconds_per_cycles = CycleTimerBase::CyclesToSeconds(1);
183  return cycles * seconds_per_cycles;
184 }
185 
186 std::string TimeDistribution::PrintCyclesAsTime(double cycles) {
187  DCHECK_GE(cycles, 0.0);
188  // This epsilon is just to avoid displaying 1000.00ms instead of 1.00s.
189  double eps1 = 1 + 1e-3;
190  double sec = CyclesToSeconds(cycles);
191  if (sec * eps1 >= 3600.0) return absl::StrFormat("%.2fh", sec / 3600.0);
192  if (sec * eps1 >= 60.0) return absl::StrFormat("%.2fm", sec / 60.0);
193  if (sec * eps1 >= 1.0) return absl::StrFormat("%.2fs", sec);
194  if (sec * eps1 >= 1e-3) return absl::StrFormat("%.2fms", sec * 1e3);
195  if (sec * eps1 >= 1e-6) return absl::StrFormat("%.2fus", sec * 1e6);
196  return absl::StrFormat("%.2fns", sec * 1e9);
197 }
198 
199 void TimeDistribution::AddTimeInSec(double seconds) {
200  DCHECK_GE(seconds, 0.0);
201  const double cycles_per_seconds = 1.0 / CycleTimerBase::CyclesToSeconds(1);
202  AddToDistribution(seconds * cycles_per_seconds);
203 }
204 
206  DCHECK_GE(cycles, 0.0);
207  AddToDistribution(cycles);
208 }
209 
210 std::string TimeDistribution::ValueAsString() const {
211  return absl::StrFormat(
212  "%8u [%8s, %8s] %8s %8s %8s\n", num_, PrintCyclesAsTime(min_),
213  PrintCyclesAsTime(max_), PrintCyclesAsTime(Average()),
214  PrintCyclesAsTime(StdDeviation()), PrintCyclesAsTime(sum_));
215 }
216 
218  DCHECK_GE(value, 0.0);
220 }
221 
222 std::string RatioDistribution::ValueAsString() const {
223  return absl::StrFormat("%8u [%7.2f%%, %7.2f%%] %7.2f%% %7.2f%%\n", num_,
224  100.0 * min_, 100.0 * max_, 100.0 * Average(),
225  100.0 * StdDeviation());
226 }
227 
229 
231  return absl::StrFormat("%8u [%8.1e, %8.1e] %8.1e %8.1e\n", num_, min_, max_,
232  Average(), StdDeviation());
233 }
234 
236  AddToDistribution(static_cast<double>(value));
237 }
238 
240  return absl::StrFormat("%8u [%8.f, %8.f] %8.2f %8.2f %8.f\n", num_, min_,
241  max_, Average(), StdDeviation(), sum_);
242 }
243 
244 #ifdef HAS_PERF_SUBSYSTEM
245 EnabledScopedInstructionCounter::EnabledScopedInstructionCounter(
246  absl::string_view name, TimeLimit* time_limit)
247  : time_limit_(time_limit), name_(name) {
248  starting_count_ =
249  time_limit_ != nullptr ? time_limit_->ReadInstructionCounter() : 0;
250 }
251 
252 EnabledScopedInstructionCounter::~EnabledScopedInstructionCounter() {
253  ending_count_ =
254  time_limit_ != nullptr ? time_limit_->ReadInstructionCounter() : 0;
255  LOG(INFO) << name_ << ", Instructions: " << ending_count_ - starting_count_;
256 }
257 #endif // HAS_PERF_SUBSYSTEM
258 
259 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
static double CyclesToSeconds(int64_t c)
Definition: timer.h:88
void AddToDistribution(double value)
Definition: stats.cc:156
std::string ValueAsString() const override
Definition: stats.cc:230
std::string ValueAsString() const override
Definition: stats.cc:239
std::string ValueAsString() const override
Definition: stats.cc:222
virtual std::string ValueAsString() const =0
std::string Name() const
Definition: stats.h:104
virtual double Sum() const
Definition: stats.h:117
virtual int Priority() const
Definition: stats.h:113
Stat(absl::string_view name)
Definition: stats.h:97
std::string StatString() const
Definition: stats.cc:52
void Register(Stat *stat)
Definition: stats.cc:56
TimeDistribution * LookupOrCreateTimeDistribution(std::string name)
Definition: stats.cc:120
std::string StatString() const
Definition: stats.cc:77
static double CyclesToSeconds(double num_cycles)
Definition: stats.cc:181
void AddTimeInCycles(double cycles)
Definition: stats.cc:205
void AddTimeInSec(double seconds)
Definition: stats.cc:199
std::string ValueAsString() const override
Definition: stats.cc:210
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
ModelSharedTimeLimit * time_limit
const std::string name
int64_t value
void STLDeleteValues(T *v)
Definition: stl_util.h:382
int UTF8StrLen(StrType str_type)
Definition: utf8.h:28
Collection of objects used to extend the Constraint Solver library.
std::string MemoryUsage()
Definition: stats.cc:31
int64_t delta
Definition: resource.cc:1695