Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
stats.cc
Go to the documentation of this file.
1// Copyright 2010-2025 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 <memory>
19#include <string>
20#include <vector>
21
22#include "absl/log/check.h"
23#include "absl/strings/str_format.h"
24#include "absl/strings/string_view.h"
27#include "ortools/base/types.h"
29#include "ortools/port/utf8.h"
30
31namespace operations_research {
32
33std::string MemoryUsage() {
35 static const int64_t kDisplayThreshold = 2;
36 static const int64_t kKiloByte = 1024;
37 static const int64_t kMegaByte = kKiloByte * kKiloByte;
38 static const int64_t kGigaByte = kMegaByte * kKiloByte;
39 if (mem > kDisplayThreshold * kGigaByte) {
40 return absl::StrFormat("%.2lf GB", mem * 1.0 / kGigaByte);
41 } else if (mem > kDisplayThreshold * kMegaByte) {
42 return absl::StrFormat("%.2lf MB", mem * 1.0 / kMegaByte);
43 } else if (mem > kDisplayThreshold * kKiloByte) {
44 return absl::StrFormat("%2lf KB", mem * 1.0 / kKiloByte);
45 } else {
46 return absl::StrFormat("%d", mem);
47 }
48}
49
50Stat::Stat(absl::string_view name, StatsGroup* group) : name_(name) {
51 group->Register(this);
52}
53
54std::string Stat::StatString() const { return name_ + ": " + ValueAsString(); }
55
56void 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
64namespace {
65
66bool 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
77std::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 absl::string_view name) {
122 std::unique_ptr<TimeDistribution>& ref = time_distributions_[name];
123 if (ref == nullptr) {
124 ref = std::make_unique<TimeDistribution>(name);
125 Register(ref.get());
126 }
127 return ref.get();
128}
129
131 : Stat(name),
132 sum_(0.0),
133 average_(0.0),
135 min_(0.0),
136 max_(0.0),
137 num_(0) {}
138
139DistributionStat::DistributionStat(absl::string_view name, StatsGroup* group)
140 : Stat(name, group),
141 sum_(0.0),
142 average_(0.0),
144 min_(0.0),
145 max_(0.0),
146 num_(0) {}
147
149 sum_ = 0.0;
150 average_ = 0.0;
152 min_ = 0.0;
153 max_ = 0.0;
154 num_ = 0;
155}
156
158 if (num_ == 0) {
159 min_ = value;
160 max_ = value;
161 sum_ = value;
162 average_ = value;
163 num_ = 1;
164 return;
165 }
166 min_ = std::min(min_, value);
167 max_ = std::max(max_, value);
168 sum_ += value;
169 ++num_;
170 const double delta = value - average_;
171 average_ = sum_ / num_;
172 sum_squares_from_average_ += delta * (value - average_);
173}
174
175double DistributionStat::Average() const { return average_; }
176
178 if (num_ == 0) return 0.0;
179 return sqrt(sum_squares_from_average_ / num_);
180}
181
183 const double seconds_per_cycles = CycleTimerBase::CyclesToSeconds(1);
184 return cycles * seconds_per_cycles;
185}
186
187std::string TimeDistribution::PrintCyclesAsTime(double cycles) {
188 DCHECK_GE(cycles, 0.0);
189 // This epsilon is just to avoid displaying 1000.00ms instead of 1.00s.
190 double eps1 = 1 + 1e-3;
191 double sec = CyclesToSeconds(cycles);
192 if (sec * eps1 >= 3600.0) return absl::StrFormat("%.2fh", sec / 3600.0);
193 if (sec * eps1 >= 60.0) return absl::StrFormat("%.2fm", sec / 60.0);
194 if (sec * eps1 >= 1.0) return absl::StrFormat("%.2fs", sec);
195 if (sec * eps1 >= 1e-3) return absl::StrFormat("%.2fms", sec * 1e3);
196 if (sec * eps1 >= 1e-6) return absl::StrFormat("%.2fus", sec * 1e6);
197 return absl::StrFormat("%.2fns", sec * 1e9);
198}
199
200void TimeDistribution::AddTimeInSec(double seconds) {
201 DCHECK_GE(seconds, 0.0);
202 const double cycles_per_seconds = 1.0 / CycleTimerBase::CyclesToSeconds(1);
203 AddToDistribution(seconds * cycles_per_seconds);
204}
205
207 DCHECK_GE(cycles, 0.0);
208 AddToDistribution(cycles);
209}
210
212 return absl::StrFormat(
213 "%8u [%8s, %8s] %8s %8s %8s\n", num_, PrintCyclesAsTime(min_),
214 PrintCyclesAsTime(max_), PrintCyclesAsTime(Average()),
215 PrintCyclesAsTime(StdDeviation()), PrintCyclesAsTime(sum_));
216}
217
218void RatioDistribution::Add(double value) {
219 DCHECK_GE(value, 0.0);
220 AddToDistribution(value);
221}
222
224 return absl::StrFormat("%8u [%7.2f%%, %7.2f%%] %7.2f%% %7.2f%%\n", num_,
225 100.0 * min_, 100.0 * max_, 100.0 * Average(),
226 100.0 * StdDeviation());
227}
228
229void DoubleDistribution::Add(double value) { AddToDistribution(value); }
230
232 return absl::StrFormat("%8u [%8.1e, %8.1e] %8.1e %8.1e\n", num_, min_, max_,
233 Average(), StdDeviation());
234}
235
236void IntegerDistribution::Add(int64_t value) {
237 AddToDistribution(static_cast<double>(value));
238}
239
241 return absl::StrFormat("%8u [%8.f, %8.f] %8.2f %8.2f %8.f\n", num_, min_,
243}
244
245} // namespace operations_research
static double CyclesToSeconds(int64_t c)
Definition timer.h:90
double Average() const
Get the average of the distribution or 0.0 if empty.
Definition stats.cc:175
void AddToDistribution(double value)
Adds a value to this sequence and updates the stats.
Definition stats.cc:157
void Reset() override
Reset this statistic to the same state as if it was newly created.
Definition stats.cc:148
std::string ValueAsString() const override
Implemented by the subclasses.
Definition stats.cc:231
std::string ValueAsString() const override
Implemented by the subclasses.
Definition stats.cc:240
std::string ValueAsString() const override
Implemented by the subclasses.
Definition stats.cc:223
Base class for a statistic that can be pretty-printed.
Definition stats.h:93
std::string Name() const
Only used for display purposes.
Definition stats.h:102
virtual int Priority() const
Definition stats.h:111
virtual std::string ValueAsString() const =0
Prints information about this statistic.
Stat(absl::string_view name)
Definition stats.h:95
std::string StatString() const
Definition stats.cc:54
virtual double Sum() const
Definition stats.h:115
Base class to print a nice summary of a group of statistics.
Definition stats.h:131
TimeDistribution * LookupOrCreateTimeDistribution(absl::string_view name)
Definition stats.cc:120
std::string StatString() const
Definition stats.cc:77
void Reset()
Calls Reset() on all the statistics registered with this group.
Definition stats.cc:58
void Register(Stat *stat)
Definition stats.cc:56
std::string ValueAsString() const override
Implemented by the subclasses.
Definition stats.cc:211
void AddTimeInSec(double seconds)
Adds a time in seconds to this distribution.
Definition stats.cc:200
static double CyclesToSeconds(double num_cycles)
Definition stats.cc:182
void AddTimeInCycles(double cycles)
Adds a time in CPU cycles to this distribution.
Definition stats.cc:206
int UTF8StrLen(StrType str_type)
str_type should be string/StringPiece/Cord
Definition utf8.h:28
In SWIG mode, we don't want anything besides these top-level includes.
std::string MemoryUsage()
Returns the current thread's total memory usage in an human-readable string.
Definition stats.cc:33