Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/linux/vm/osContainer_linux.cpp
32285 views
1
/*
2
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
25
#include <string.h>
26
#include <math.h>
27
#include <errno.h>
28
#include "utilities/globalDefinitions.hpp"
29
#include "memory/allocation.hpp"
30
#include "runtime/os.hpp"
31
#include "osContainer_linux.hpp"
32
33
#define PER_CPU_SHARES 1024
34
35
bool OSContainer::_is_initialized = false;
36
bool OSContainer::_is_containerized = false;
37
int OSContainer::_active_processor_count = 1;
38
julong _unlimited_memory;
39
40
class CgroupSubsystem: CHeapObj<mtInternal> {
41
friend class OSContainer;
42
43
private:
44
volatile jlong _next_check_counter;
45
46
/* mountinfo contents */
47
char *_root;
48
char *_mount_point;
49
50
/* Constructed subsystem directory */
51
char *_path;
52
53
public:
54
CgroupSubsystem(char *root, char *mountpoint) {
55
_root = os::strdup(root);
56
_mount_point = os::strdup(mountpoint);
57
_path = NULL;
58
_next_check_counter = min_jlong;
59
}
60
61
/*
62
* Set directory to subsystem specific files based
63
* on the contents of the mountinfo and cgroup files.
64
*/
65
void set_subsystem_path(char *cgroup_path) {
66
char buf[MAXPATHLEN+1];
67
if (_root != NULL && cgroup_path != NULL) {
68
if (strcmp(_root, "/") == 0) {
69
int buflen;
70
strncpy(buf, _mount_point, MAXPATHLEN);
71
buf[MAXPATHLEN-1] = '\0';
72
if (strcmp(cgroup_path,"/") != 0) {
73
buflen = strlen(buf);
74
if ((buflen + strlen(cgroup_path)) > (MAXPATHLEN-1)) {
75
return;
76
}
77
strncat(buf, cgroup_path, MAXPATHLEN-buflen);
78
buf[MAXPATHLEN-1] = '\0';
79
}
80
_path = os::strdup(buf);
81
} else {
82
if (strcmp(_root, cgroup_path) == 0) {
83
strncpy(buf, _mount_point, MAXPATHLEN);
84
buf[MAXPATHLEN-1] = '\0';
85
_path = os::strdup(buf);
86
} else {
87
char *p = strstr(cgroup_path, _root);
88
if (p != NULL && p == _root) {
89
if (strlen(cgroup_path) > strlen(_root)) {
90
int buflen;
91
strncpy(buf, _mount_point, MAXPATHLEN);
92
buf[MAXPATHLEN-1] = '\0';
93
buflen = strlen(buf);
94
if ((buflen + strlen(cgroup_path) - strlen(_root)) > (MAXPATHLEN-1)) {
95
return;
96
}
97
strncat(buf, cgroup_path + strlen(_root), MAXPATHLEN-buflen);
98
buf[MAXPATHLEN-1] = '\0';
99
_path = os::strdup(buf);
100
}
101
}
102
}
103
}
104
}
105
}
106
107
char *subsystem_path() { return _path; }
108
109
bool cache_has_expired() {
110
return os::elapsed_counter() > _next_check_counter;
111
}
112
113
void set_cache_expiry_time(jlong timeout) {
114
_next_check_counter = os::elapsed_counter() + timeout;
115
}
116
};
117
118
class CgroupMemorySubsystem: CgroupSubsystem {
119
friend class OSContainer;
120
121
private:
122
/* Some container runtimes set limits via cgroup
123
* hierarchy. If set to true consider also memory.stat
124
* file if everything else seems unlimited */
125
bool _uses_mem_hierarchy;
126
127
public:
128
CgroupMemorySubsystem(char *root, char *mountpoint) : CgroupSubsystem::CgroupSubsystem(root, mountpoint) {
129
_uses_mem_hierarchy = false;
130
}
131
132
bool is_hierarchical() { return _uses_mem_hierarchy; }
133
void set_hierarchical(bool value) { _uses_mem_hierarchy = value; }
134
};
135
136
CgroupMemorySubsystem* memory = NULL;
137
CgroupSubsystem* cpuset = NULL;
138
CgroupSubsystem* cpu = NULL;
139
CgroupSubsystem* cpuacct = NULL;
140
141
typedef char * cptr;
142
143
PRAGMA_DIAG_PUSH
144
PRAGMA_FORMAT_NONLITERAL_IGNORED
145
template <typename T> int subsystem_file_line_contents(CgroupSubsystem* c,
146
const char *filename,
147
const char *matchline,
148
const char *scan_fmt,
149
T returnval) {
150
FILE *fp = NULL;
151
char *p;
152
char file[MAXPATHLEN+1];
153
char buf[MAXPATHLEN+1];
154
char discard[MAXPATHLEN+1];
155
bool found_match = false;
156
157
if (c == NULL) {
158
if (PrintContainerInfo) {
159
tty->print_cr("subsystem_file_line_contents: CgroupSubsytem* is NULL");
160
}
161
return OSCONTAINER_ERROR;
162
}
163
if (c->subsystem_path() == NULL) {
164
if (PrintContainerInfo) {
165
tty->print_cr("subsystem_file_line_contents: subsystem path is NULL");
166
}
167
return OSCONTAINER_ERROR;
168
}
169
170
strncpy(file, c->subsystem_path(), MAXPATHLEN);
171
file[MAXPATHLEN-1] = '\0';
172
int filelen = strlen(file);
173
if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) {
174
if (PrintContainerInfo) {
175
tty->print_cr("File path too long %s, %s", file, filename);
176
}
177
return OSCONTAINER_ERROR;
178
}
179
strncat(file, filename, MAXPATHLEN-filelen);
180
if (PrintContainerInfo) {
181
tty->print_cr("Path to %s is %s", filename, file);
182
}
183
fp = fopen(file, "r");
184
if (fp != NULL) {
185
int err = 0;
186
while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) {
187
found_match = false;
188
if (matchline == NULL) {
189
// single-line file case
190
int matched = sscanf(p, scan_fmt, returnval);
191
found_match = (matched == 1);
192
} else {
193
// multi-line file case
194
if (strstr(p, matchline) != NULL) {
195
// discard matchline string prefix
196
int matched = sscanf(p, scan_fmt, discard, returnval);
197
found_match = (matched == 2);
198
} else {
199
continue; // substring not found
200
}
201
}
202
if (found_match) {
203
fclose(fp);
204
return 0;
205
} else {
206
err = 1;
207
if (PrintContainerInfo) {
208
tty->print_cr("Type %s not found in file %s", scan_fmt, file);
209
}
210
}
211
if (err == 0 && PrintContainerInfo) {
212
tty->print_cr("Empty file %s", file);
213
}
214
}
215
} else {
216
if (PrintContainerInfo) {
217
tty->print_cr("Open of file %s failed, %s", file, strerror(errno));
218
}
219
}
220
if (fp != NULL)
221
fclose(fp);
222
return OSCONTAINER_ERROR;
223
}
224
PRAGMA_DIAG_POP
225
226
#define GET_CONTAINER_INFO(return_type, subsystem, filename, \
227
logstring, scan_fmt, variable) \
228
return_type variable; \
229
{ \
230
int err; \
231
err = subsystem_file_line_contents(subsystem, \
232
filename, \
233
NULL, \
234
scan_fmt, \
235
&variable); \
236
if (err != 0) \
237
return (return_type) OSCONTAINER_ERROR; \
238
\
239
if (PrintContainerInfo) \
240
tty->print_cr(logstring, variable); \
241
}
242
243
#define GET_CONTAINER_INFO_CPTR(return_type, subsystem, filename, \
244
logstring, scan_fmt, variable, bufsize) \
245
char variable[bufsize]; \
246
{ \
247
int err; \
248
err = subsystem_file_line_contents(subsystem, \
249
filename, \
250
NULL, \
251
scan_fmt, \
252
variable); \
253
if (err != 0) \
254
return (return_type) NULL; \
255
\
256
if (PrintContainerInfo) \
257
tty->print_cr(logstring, variable); \
258
}
259
260
#define GET_CONTAINER_INFO_LINE(return_type, subsystem, filename, \
261
matchline, logstring, scan_fmt, variable) \
262
return_type variable; \
263
{ \
264
int err; \
265
err = subsystem_file_line_contents(subsystem, \
266
filename, \
267
matchline, \
268
scan_fmt, \
269
&variable); \
270
if (err != 0) \
271
return (return_type) OSCONTAINER_ERROR; \
272
\
273
if (PrintContainerInfo) \
274
tty->print_cr(logstring, variable); \
275
}
276
277
278
/* init
279
*
280
* Initialize the container support and determine if
281
* we are running under cgroup control.
282
*/
283
void OSContainer::init() {
284
FILE *mntinfo = NULL;
285
FILE *cgroup = NULL;
286
char buf[MAXPATHLEN+1];
287
char tmproot[MAXPATHLEN+1];
288
char tmpmount[MAXPATHLEN+1];
289
char *p;
290
jlong mem_limit;
291
292
assert(!_is_initialized, "Initializing OSContainer more than once");
293
294
_is_initialized = true;
295
_is_containerized = false;
296
297
_unlimited_memory = (LONG_MAX / os::vm_page_size()) * os::vm_page_size();
298
299
if (PrintContainerInfo) {
300
tty->print_cr("OSContainer::init: Initializing Container Support");
301
}
302
if (!UseContainerSupport) {
303
if (PrintContainerInfo) {
304
tty->print_cr("Container Support not enabled");
305
}
306
return;
307
}
308
309
/*
310
* Find the cgroup mount point for memory and cpuset
311
* by reading /proc/self/mountinfo
312
*
313
* Example for docker:
314
* 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory
315
*
316
* Example for host:
317
* 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory
318
*/
319
mntinfo = fopen("/proc/self/mountinfo", "r");
320
if (mntinfo == NULL) {
321
if (PrintContainerInfo) {
322
tty->print_cr("Can't open /proc/self/mountinfo, %s",
323
strerror(errno));
324
}
325
return;
326
}
327
328
while ((p = fgets(buf, MAXPATHLEN, mntinfo)) != NULL) {
329
char tmpcgroups[MAXPATHLEN+1];
330
char *cptr = tmpcgroups;
331
char *token;
332
333
// mountinfo format is documented at https://www.kernel.org/doc/Documentation/filesystems/proc.txt
334
if (sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- cgroup %*s %s", tmproot, tmpmount, tmpcgroups) != 3) {
335
continue;
336
}
337
while ((token = strsep(&cptr, ",")) != NULL) {
338
if (strcmp(token, "memory") == 0) {
339
memory = new CgroupMemorySubsystem(tmproot, tmpmount);
340
} else if (strcmp(token, "cpuset") == 0) {
341
cpuset = new CgroupSubsystem(tmproot, tmpmount);
342
} else if (strcmp(token, "cpu") == 0) {
343
cpu = new CgroupSubsystem(tmproot, tmpmount);
344
} else if (strcmp(token, "cpuacct") == 0) {
345
cpuacct= new CgroupSubsystem(tmproot, tmpmount);
346
}
347
}
348
}
349
fclose(mntinfo);
350
351
if (memory == NULL) {
352
if (PrintContainerInfo) {
353
tty->print_cr("Required cgroup memory subsystem not found");
354
}
355
return;
356
}
357
if (cpuset == NULL) {
358
if (PrintContainerInfo) {
359
tty->print_cr("Required cgroup cpuset subsystem not found");
360
}
361
return;
362
}
363
if (cpu == NULL) {
364
if (PrintContainerInfo) {
365
tty->print_cr("Required cgroup cpu subsystem not found");
366
}
367
return;
368
}
369
if (cpuacct == NULL) {
370
if (PrintContainerInfo) {
371
tty->print_cr("Required cgroup cpuacct subsystem not found");
372
}
373
return;
374
}
375
376
/*
377
* Read /proc/self/cgroup and map host mount point to
378
* local one via /proc/self/mountinfo content above
379
*
380
* Docker example:
381
* 5:memory:/docker/6558aed8fc662b194323ceab5b964f69cf36b3e8af877a14b80256e93aecb044
382
*
383
* Host example:
384
* 5:memory:/user.slice
385
*
386
* Construct a path to the process specific memory and cpuset
387
* cgroup directory.
388
*
389
* For a container running under Docker from memory example above
390
* the paths would be:
391
*
392
* /sys/fs/cgroup/memory
393
*
394
* For a Host from memory example above the path would be:
395
*
396
* /sys/fs/cgroup/memory/user.slice
397
*
398
*/
399
cgroup = fopen("/proc/self/cgroup", "r");
400
if (cgroup == NULL) {
401
if (PrintContainerInfo) {
402
tty->print_cr("Can't open /proc/self/cgroup, %s",
403
strerror(errno));
404
}
405
return;
406
}
407
408
while ((p = fgets(buf, MAXPATHLEN, cgroup)) != NULL) {
409
char *controllers;
410
char *token;
411
char *base;
412
413
/* Skip cgroup number */
414
strsep(&p, ":");
415
/* Get controllers and base */
416
controllers = strsep(&p, ":");
417
base = strsep(&p, "\n");
418
419
if (controllers == NULL) {
420
continue;
421
}
422
423
while ((token = strsep(&controllers, ",")) != NULL) {
424
if (strcmp(token, "memory") == 0) {
425
memory->set_subsystem_path(base);
426
jlong hierarchy = uses_mem_hierarchy();
427
if (hierarchy > 0) {
428
memory->set_hierarchical(true);
429
}
430
} else if (strcmp(token, "cpuset") == 0) {
431
cpuset->set_subsystem_path(base);
432
} else if (strcmp(token, "cpu") == 0) {
433
cpu->set_subsystem_path(base);
434
} else if (strcmp(token, "cpuacct") == 0) {
435
cpuacct->set_subsystem_path(base);
436
}
437
}
438
}
439
440
fclose(cgroup);
441
442
// We need to update the amount of physical memory now that
443
// command line arguments have been processed.
444
if ((mem_limit = memory_limit_in_bytes()) > 0) {
445
os::Linux::set_physical_memory(mem_limit);
446
if (PrintContainerInfo) {
447
tty->print_cr("Memory Limit is: " JLONG_FORMAT, mem_limit);
448
}
449
}
450
451
_is_containerized = true;
452
453
}
454
455
const char * OSContainer::container_type() {
456
if (is_containerized()) {
457
return "cgroupv1";
458
} else {
459
return NULL;
460
}
461
}
462
463
/* uses_mem_hierarchy
464
*
465
* Return whether or not hierarchical cgroup accounting is being
466
* done.
467
*
468
* return:
469
* A number > 0 if true, or
470
* OSCONTAINER_ERROR for not supported
471
*/
472
jlong OSContainer::uses_mem_hierarchy() {
473
GET_CONTAINER_INFO(jlong, memory, "/memory.use_hierarchy",
474
"Use Hierarchy is: " JLONG_FORMAT, JLONG_FORMAT, use_hierarchy);
475
return use_hierarchy;
476
}
477
478
479
/* memory_limit_in_bytes
480
*
481
* Return the limit of available memory for this process.
482
*
483
* return:
484
* memory limit in bytes or
485
* -1 for unlimited
486
* OSCONTAINER_ERROR for not supported
487
*/
488
jlong OSContainer::memory_limit_in_bytes() {
489
GET_CONTAINER_INFO(julong, memory, "/memory.limit_in_bytes",
490
"Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit);
491
492
if (memlimit >= _unlimited_memory) {
493
if (PrintContainerInfo) {
494
tty->print_cr("Non-Hierarchical Memory Limit is: Unlimited");
495
}
496
if (memory->is_hierarchical()) {
497
const char* matchline = "hierarchical_memory_limit";
498
const char* format = "%s " JULONG_FORMAT;
499
GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline,
500
"Hierarchical Memory Limit is: " JULONG_FORMAT, format, hier_memlimit)
501
if (hier_memlimit >= _unlimited_memory) {
502
if (PrintContainerInfo) {
503
tty->print_cr("Hierarchical Memory Limit is: Unlimited");
504
}
505
} else {
506
return (jlong)hier_memlimit;
507
}
508
}
509
return (jlong)-1;
510
}
511
else {
512
return (jlong)memlimit;
513
}
514
}
515
516
jlong OSContainer::memory_and_swap_limit_in_bytes() {
517
GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes",
518
"Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit);
519
if (memswlimit >= _unlimited_memory) {
520
if (PrintContainerInfo) {
521
tty->print_cr("Non-Hierarchical Memory and Swap Limit is: Unlimited");
522
}
523
if (memory->is_hierarchical()) {
524
const char* matchline = "hierarchical_memsw_limit";
525
const char* format = "%s " JULONG_FORMAT;
526
GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline,
527
"Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, format, hier_memlimit)
528
if (hier_memlimit >= _unlimited_memory) {
529
if (PrintContainerInfo) {
530
tty->print_cr("Hierarchical Memory and Swap Limit is: Unlimited");
531
}
532
} else {
533
return (jlong)hier_memlimit;
534
}
535
}
536
return (jlong)-1;
537
} else {
538
return (jlong)memswlimit;
539
}
540
}
541
542
jlong OSContainer::memory_soft_limit_in_bytes() {
543
GET_CONTAINER_INFO(julong, memory, "/memory.soft_limit_in_bytes",
544
"Memory Soft Limit is: " JULONG_FORMAT, JULONG_FORMAT, memsoftlimit);
545
if (memsoftlimit >= _unlimited_memory) {
546
if (PrintContainerInfo) {
547
tty->print_cr("Memory Soft Limit is: Unlimited");
548
}
549
return (jlong)-1;
550
} else {
551
return (jlong)memsoftlimit;
552
}
553
}
554
555
/* memory_usage_in_bytes
556
*
557
* Return the amount of used memory for this process.
558
*
559
* return:
560
* memory usage in bytes or
561
* -1 for unlimited
562
* OSCONTAINER_ERROR for not supported
563
*/
564
jlong OSContainer::memory_usage_in_bytes() {
565
GET_CONTAINER_INFO(jlong, memory, "/memory.usage_in_bytes",
566
"Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memusage);
567
return memusage;
568
}
569
570
/* memory_max_usage_in_bytes
571
*
572
* Return the maximum amount of used memory for this process.
573
*
574
* return:
575
* max memory usage in bytes or
576
* OSCONTAINER_ERROR for not supported
577
*/
578
jlong OSContainer::memory_max_usage_in_bytes() {
579
GET_CONTAINER_INFO(jlong, memory, "/memory.max_usage_in_bytes",
580
"Maximum Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memmaxusage);
581
return memmaxusage;
582
}
583
584
/* active_processor_count
585
*
586
* Calculate an appropriate number of active processors for the
587
* VM to use based on these three inputs.
588
*
589
* cpu affinity
590
* cgroup cpu quota & cpu period
591
* cgroup cpu shares
592
*
593
* Algorithm:
594
*
595
* Determine the number of available CPUs from sched_getaffinity
596
*
597
* If user specified a quota (quota != -1), calculate the number of
598
* required CPUs by dividing quota by period.
599
*
600
* If shares are in effect (shares != -1), calculate the number
601
* of CPUs required for the shares by dividing the share value
602
* by PER_CPU_SHARES.
603
*
604
* All results of division are rounded up to the next whole number.
605
*
606
* If neither shares or quotas have been specified, return the
607
* number of active processors in the system.
608
*
609
* If both shares and quotas have been specified, the results are
610
* based on the flag PreferContainerQuotaForCPUCount. If true,
611
* return the quota value. If false return the smallest value
612
* between shares or quotas.
613
*
614
* If shares and/or quotas have been specified, the resulting number
615
* returned will never exceed the number of active processors.
616
*
617
* return:
618
* number of CPUs
619
*/
620
int OSContainer::active_processor_count() {
621
int quota_count = 0, share_count = 0;
622
int cpu_count, limit_count;
623
int result;
624
625
// We use a cache with a timeout to avoid performing expensive
626
// computations in the event this function is called frequently.
627
// [See 8227006].
628
if (!cpu->cache_has_expired()) {
629
if (PrintContainerInfo) {
630
tty->print_cr("OSContainer::active_processor_count (cached): %d", OSContainer::_active_processor_count);
631
}
632
633
return OSContainer::_active_processor_count;
634
}
635
636
cpu_count = limit_count = os::Linux::active_processor_count();
637
int quota = cpu_quota();
638
int period = cpu_period();
639
int share = cpu_shares();
640
641
if (quota > -1 && period > 0) {
642
quota_count = ceilf((float)quota / (float)period);
643
if (PrintContainerInfo) {
644
tty->print_cr("CPU Quota count based on quota/period: %d", quota_count);
645
}
646
}
647
if (share > -1) {
648
share_count = ceilf((float)share / (float)PER_CPU_SHARES);
649
if (PrintContainerInfo) {
650
tty->print_cr("CPU Share count based on shares: %d", share_count);
651
}
652
}
653
654
// If both shares and quotas are setup results depend
655
// on flag PreferContainerQuotaForCPUCount.
656
// If true, limit CPU count to quota
657
// If false, use minimum of shares and quotas
658
if (quota_count !=0 && share_count != 0) {
659
if (PreferContainerQuotaForCPUCount) {
660
limit_count = quota_count;
661
} else {
662
limit_count = MIN2(quota_count, share_count);
663
}
664
} else if (quota_count != 0) {
665
limit_count = quota_count;
666
} else if (share_count != 0) {
667
limit_count = share_count;
668
}
669
670
result = MIN2(cpu_count, limit_count);
671
if (PrintContainerInfo) {
672
tty->print_cr("OSContainer::active_processor_count: %d", result);
673
}
674
675
// Update the value and reset the cache timeout
676
OSContainer::_active_processor_count = result;
677
cpu->set_cache_expiry_time(OSCONTAINER_CACHE_TIMEOUT);
678
679
return result;
680
}
681
682
char * OSContainer::cpu_cpuset_cpus() {
683
GET_CONTAINER_INFO_CPTR(cptr, cpuset, "/cpuset.cpus",
684
"cpuset.cpus is: %s", "%1023s", cpus, 1024);
685
return os::strdup(cpus);
686
}
687
688
char * OSContainer::cpu_cpuset_memory_nodes() {
689
GET_CONTAINER_INFO_CPTR(cptr, cpuset, "/cpuset.mems",
690
"cpuset.mems is: %s", "%1023s", mems, 1024);
691
return os::strdup(mems);
692
}
693
694
/* cpu_quota
695
*
696
* Return the number of milliseconds per period
697
* process is guaranteed to run.
698
*
699
* return:
700
* quota time in milliseconds
701
* -1 for no quota
702
* OSCONTAINER_ERROR for not supported
703
*/
704
int OSContainer::cpu_quota() {
705
GET_CONTAINER_INFO(int, cpu, "/cpu.cfs_quota_us",
706
"CPU Quota is: %d", "%d", quota);
707
return quota;
708
}
709
710
int OSContainer::cpu_period() {
711
GET_CONTAINER_INFO(int, cpu, "/cpu.cfs_period_us",
712
"CPU Period is: %d", "%d", period);
713
return period;
714
}
715
716
/* cpu_shares
717
*
718
* Return the amount of cpu shares available to the process
719
*
720
* return:
721
* Share number (typically a number relative to 1024)
722
* (2048 typically expresses 2 CPUs worth of processing)
723
* -1 for no share setup
724
* OSCONTAINER_ERROR for not supported
725
*/
726
int OSContainer::cpu_shares() {
727
GET_CONTAINER_INFO(int, cpu, "/cpu.shares",
728
"CPU Shares is: %d", "%d", shares);
729
// Convert 1024 to no shares setup
730
if (shares == 1024) return -1;
731
732
return shares;
733
}
734
735
736