-
Notifications
You must be signed in to change notification settings - Fork 186
/
limit.cpp
277 lines (236 loc) · 8.49 KB
/
limit.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
// Copyright 2015, 2016 Carnegie Mellon University. See LICENSE file for terms.
#include <boost/format.hpp>
#include "limit.hpp"
#include "misc.hpp"
namespace pharos {
namespace {
// A couple of global variables. It's unclear that there's a better way to do this...
bool first_ts_set = false;
ResourceLimit::time_point first_ts;
// A few private helper routines.
inline double total_cpu_time(const rusage& ru) {
double secs = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
double usecs = ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
return (secs + (usecs / 1000000.0));
}
inline void get_resource_usage(rusage& ru) {
if (getrusage(RUSAGE_SELF, &ru) != 0) {
assert(false);
}
}
} // unnamed namespace
// ResourceLimit class methods
ResourceLimit::ResourceLimit() {
counter = 0;
counter_limit = 0;
set_cpu_limits(0.0, 0.0);
set_memory_limits(0.0, 0.0);
set_clock_limits(duration(), duration());
get_resource_usage(start_ru);
start_ts = clock::now();
if (!first_ts_set) {
first_ts_set = true;
first_ts = start_ts;
}
}
LimitCode ResourceLimit::check() {
// Counters are the easiest, check them first.
if (counter_limit > 0) {
if (counter >= counter_limit) {
msg = "count limit exceeded";
return LimitCounter;
}
}
// Then relative and absolute wall clock limits.
if (relative_clock_limit > duration() || absolute_clock_limit > duration()) {
time_point now_ts = clock::now();
// Check the relative wall clock limit if there is one.
if (relative_clock_limit > duration()) {
duration relative_clock_delta = now_ts - start_ts;
if (relative_clock_delta >= relative_clock_limit) {
msg = "relative wall clock exceeded";
return LimitRelativeClock;
}
}
// Check the absolute wall clock limit if there is one.
if (absolute_clock_limit > duration()) {
duration absolute_clock_delta = now_ts - first_ts;
if (absolute_clock_delta >= absolute_clock_limit) {
msg = "absolute wall clock exceeded";
return LimitAbsoluteClock;
}
}
}
// Check limits that require calling getrusage()...
if (relative_cpu_limit > 0 || absolute_cpu_limit > 0 ||
relative_memory_limit > 0 || absolute_memory_limit > 0) {
rusage now_ru;
get_resource_usage(now_ru);
// Check the relative memory limit if there is one.
if (relative_memory_limit > 0) {
long relative_memory_long = now_ru.ru_maxrss - start_ru.ru_maxrss;
// Convert from internal "memory units" (KB) to our API of mibibytes
double relative_memory_delta = relative_memory_long / 1024.0;
if (relative_memory_delta >= relative_memory_limit) {
msg = "relative memory exceeded";
return LimitRelativeMemory;
}
}
// Check the absolute memory limit if there is one.
if (absolute_memory_limit > 0) {
// Convert from internal "memory units" (KB) to our API of mibibytes
double absolute_memory_delta = now_ru.ru_maxrss / 1024.0;
if (absolute_memory_delta >= absolute_memory_limit) {
msg = "absolute memory exceeded";
return LimitAbsoluteMemory;
}
}
// Check the relative CPU limit if there is one.
if (relative_cpu_limit > 0) {
double total_now_cpu = total_cpu_time(now_ru);
double total_start_cpu = total_cpu_time(start_ru);
double relative_cpu_delta = total_start_cpu - total_now_cpu;
if (relative_cpu_delta >= relative_cpu_limit) {
msg = "relative CPU time exceeded";
return LimitRelativeCPU;
}
}
// Check the absolute CPU limit if there is one.
if (absolute_cpu_limit > 0) {
double total_now_cpu = total_cpu_time(now_ru);
if (total_now_cpu >= absolute_cpu_limit) {
msg = "absolute CPU time exceeded";
return LimitAbsoluteCPU;
}
}
}
// Either there were no limits, or we haven't reached any of them.
return LimitSuccess;
}
ResourceLimit::duration ResourceLimit::get_relative_clock() const {
time_point now_ts = clock::now();
return now_ts - start_ts;
}
double ResourceLimit::get_relative_cpu() const {
rusage now_ru;
get_resource_usage(now_ru);
double total_now_cpu = total_cpu_time(now_ru);
double total_start_cpu = total_cpu_time(now_ru);
return (total_start_cpu - total_now_cpu);
}
double ResourceLimit::get_relative_memory() const {
rusage now_ru;
get_resource_usage(now_ru);
long relative_memory_long = now_ru.ru_maxrss - start_ru.ru_maxrss;
// Convert from internal "memory units" (KB) to our API of mibibytes
return (relative_memory_long / 1024.0);
}
ResourceLimit::duration ResourceLimit::get_absolute_clock() const {
time_point now_ts = clock::now();
return now_ts - first_ts;
}
double ResourceLimit::get_absolute_cpu() const {
rusage now_ru;
get_resource_usage(now_ru);
return total_cpu_time(now_ru);
}
double ResourceLimit::get_absolute_memory() const {
rusage now_ru;
get_resource_usage(now_ru);
// Convert from internal "memory units" (KB) to our API of mibibytes
return (now_ru.ru_maxrss / 1024.0);
}
std::string ResourceLimit::get_relative_usage() const {
time_point now_ts = clock::now();
rusage now_ru;
get_resource_usage(now_ru);
duration relative_clock_delta = now_ts - start_ts;
double total_now_cpu = total_cpu_time(now_ru);
double total_start_cpu = total_cpu_time(start_ru);
double relative_cpu_delta = total_start_cpu - total_now_cpu;
long relative_memory_long = now_ru.ru_maxrss - start_ru.ru_maxrss;
// Convert from internal "memory units" (KB) to our API of mibibytes
double relative_memory_delta = relative_memory_long / 1024.0;
return boost::str(boost::format("%.2f secs CPU, %.2f MB memory, %.2f secs elapsed") %
relative_cpu_delta % relative_memory_delta % relative_clock_delta.count());
}
std::string ResourceLimit::get_absolute_usage() const {
time_point now_ts = clock::now();
rusage now_ru;
get_resource_usage(now_ru);
duration absolute_clock_delta = now_ts - first_ts;
double absolute_cpu_delta = total_cpu_time(now_ru);
// Convert from internal "memory units" (KB) to our API of mibibytes
double absolute_memory_delta = now_ru.ru_maxrss / 1024.0;
return boost::str(boost::format("%.2f secs CPU, %.2f MB memory, %.2f secs elapsed") %
absolute_cpu_delta % absolute_memory_delta % absolute_clock_delta.count());
}
PharosLimits::PharosLimits(const ProgOptVarMap &vm)
{
timeout = vm.get<double>("timeout", "pharos.timeout");
relative_timeout = vm.get<double>("reltimeout", "pharos.relative_timeout");
partitioner_timeout = vm.get<double>("ptimeout", "pharos.partitioner_timeout");
relative_partitioner_timeout = vm.get<double>("preltimeout", "pharos.relative_partitioner_timeout");
maxmem = vm.get<double>("maxmem", "pharos.maxmem");
relative_maxmem = vm.get<double>("relmaxmem", "pharos.relative_maxmem");
block_counter_limit = vm.get<int>("blockcounterlimit", "pharos.block_counter_limit");
func_counter_limit = vm.get<int>("funccounterlimit", "pharos.func_counter_limit");
}
void PharosLimits::set_clock_limits(ResourceLimit &limit, limit_type ltype) const
{
switch (ltype) {
case limit_type::BASE:
case limit_type::FUNC:
if (timeout && relative_timeout) {
limit.set_clock_limits(*relative_timeout, *timeout);
}
break;
case limit_type::PARTITIONER:
if (partitioner_timeout && relative_partitioner_timeout) {
limit.set_clock_limits(*relative_partitioner_timeout, *partitioner_timeout);
}
break;
}
}
void PharosLimits::set_cpu_limits(ResourceLimit &limit, limit_type ltype) const
{
switch (ltype) {
case limit_type::BASE:
case limit_type::FUNC:
if (timeout && relative_timeout) {
limit.set_cpu_limits(*relative_timeout, *timeout);
}
break;
case limit_type::PARTITIONER:
if (partitioner_timeout && relative_partitioner_timeout) {
limit.set_cpu_limits(*relative_partitioner_timeout, *partitioner_timeout);
}
break;
}
}
void PharosLimits::set_counter_limit(ResourceLimit &limit, limit_type ltype) const {
switch (ltype) {
case limit_type::BASE:
case limit_type::PARTITIONER:
if (block_counter_limit) {
limit.set_counter_limit(*block_counter_limit);
}
break;
case limit_type::FUNC:
if (func_counter_limit) {
limit.set_counter_limit(*func_counter_limit);
}
break;
}
}
const PharosLimits &get_global_limits()
{
static PharosLimits limits(get_global_options_vm());
return limits;
}
} // namespace pharos
/* Local Variables: */
/* mode: c++ */
/* fill-column: 95 */
/* comment-column: 0 */
/* End: */