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/globals.hpp" 31 #include "runtime/os.hpp" 32 #include "logging/log.hpp" 33 #include "osContainer_linux.hpp" 34 35 /* 36 * PER_CPU_SHARES has been set to 1024 because CPU shares' quota 37 * is commonly used in cloud frameworks like Kubernetes[1], 38 * AWS[2] and Mesos[3] in a similar way. They spawn containers with 39 * --cpu-shares option values scaled by PER_CPU_SHARES. Thus, we do 40 * the inverse for determining the number of possible available 41 * CPUs to the JVM inside a container. See JDK-8216366. 42 * 43 * [1] https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu 44 * In particular: 45 * When using Docker: 46 * The spec.containers[].resources.requests.cpu is converted to its core value, which is potentially 47 * fractional, and multiplied by 1024. The greater of this number or 2 is used as the value of the 48 * --cpu-shares flag in the docker run command. 49 * [2] https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html 50 * [3] https://github.com/apache/mesos/blob/3478e344fb77d931f6122980c6e94cd3913c441d/src/docker/docker.cpp#L648 51 * https://github.com/apache/mesos/blob/3478e344fb77d931f6122980c6e94cd3913c441d/src/slave/containerizer/mesos/isolators/cgroups/constants.hpp#L30 52 */ 53 #define PER_CPU_SHARES 1024 54 55 bool OSContainer::_is_initialized = false; 56 bool OSContainer::_is_containerized = false; 57 julong _unlimited_memory; 58 59 class CgroupSubsystem: CHeapObj<mtInternal> { 60 friend class OSContainer; 61 62 private: 63 /* mountinfo contents */ 64 char *_root; 65 char *_mount_point; 66 67 /* Constructed subsystem directory */ 68 char *_path; 69 70 public: 71 CgroupSubsystem(char *root, char *mountpoint) { 72 _root = os::strdup(root); 73 _mount_point = os::strdup(mountpoint); 74 _path = NULL; 75 } 76 77 /* 78 * Set directory to subsystem specific files based 79 * on the contents of the mountinfo and cgroup files. 80 */ 81 void set_subsystem_path(char *cgroup_path) { 82 char buf[MAXPATHLEN+1]; 83 if (_root != NULL && cgroup_path != NULL) { 84 if (strcmp(_root, "/") == 0) { 85 int buflen; 86 strncpy(buf, _mount_point, MAXPATHLEN); 87 buf[MAXPATHLEN-1] = '\0'; 88 if (strcmp(cgroup_path,"/") != 0) { 89 buflen = strlen(buf); 90 if ((buflen + strlen(cgroup_path)) > (MAXPATHLEN-1)) { 91 return; 92 } 93 strncat(buf, cgroup_path, MAXPATHLEN-buflen); 94 buf[MAXPATHLEN-1] = '\0'; 95 } 96 _path = os::strdup(buf); 97 } else { 98 if (strcmp(_root, cgroup_path) == 0) { 99 strncpy(buf, _mount_point, MAXPATHLEN); 100 buf[MAXPATHLEN-1] = '\0'; 101 _path = os::strdup(buf); 102 } else { 103 char *p = strstr(cgroup_path, _root); 104 if (p != NULL && p == _root) { 105 if (strlen(cgroup_path) > strlen(_root)) { 106 int buflen; 107 strncpy(buf, _mount_point, MAXPATHLEN); 108 buf[MAXPATHLEN-1] = '\0'; 109 buflen = strlen(buf); 110 if ((buflen + strlen(cgroup_path) - strlen(_root)) > (MAXPATHLEN-1)) { 111 return; 112 } 113 strncat(buf, cgroup_path + strlen(_root), MAXPATHLEN-buflen); 114 buf[MAXPATHLEN-1] = '\0'; 115 _path = os::strdup(buf); 116 } 117 } 118 } 119 } 120 } 121 } 122 123 char *subsystem_path() { return _path; } 124 }; 125 126 class CgroupMemorySubsystem: CgroupSubsystem { 127 friend class OSContainer; 128 129 private: 130 /* Some container runtimes set limits via cgroup 131 * hierarchy. If set to true consider also memory.stat 132 * file if everything else seems unlimited */ 133 bool _uses_mem_hierarchy; 134 volatile jlong _memory_limit_in_bytes; 135 volatile jlong _next_check_counter; 136 137 public: 138 CgroupMemorySubsystem(char *root, char *mountpoint) : CgroupSubsystem::CgroupSubsystem(root, mountpoint) { 139 _uses_mem_hierarchy = false; 140 _memory_limit_in_bytes = -1; 141 _next_check_counter = min_jlong; 142 143 } 144 145 bool is_hierarchical() { return _uses_mem_hierarchy; } 146 void set_hierarchical(bool value) { _uses_mem_hierarchy = value; } 147 148 bool should_check_memory_limit() { 149 return os::elapsed_counter() > _next_check_counter; 150 } 151 jlong memory_limit_in_bytes() { return _memory_limit_in_bytes; } 152 void set_memory_limit_in_bytes(jlong value) { 153 _memory_limit_in_bytes = value; 154 // max memory limit is unlikely to change, but we want to remain 155 // responsive to configuration changes. A very short (20ms) grace time 156 // between re-read avoids excessive overhead during startup without 157 // significantly reducing the VMs ability to promptly react to reduced 158 // memory availability 159 _next_check_counter = os::elapsed_counter() + (NANOSECS_PER_SEC/50); 160 } 161 162 }; 163 164 CgroupMemorySubsystem* memory = NULL; 165 CgroupSubsystem* cpuset = NULL; 166 CgroupSubsystem* cpu = NULL; 167 CgroupSubsystem* cpuacct = NULL; 168 169 typedef char * cptr; 170 171 PRAGMA_DIAG_PUSH 172 PRAGMA_FORMAT_NONLITERAL_IGNORED 173 template <typename T> int subsystem_file_line_contents(CgroupSubsystem* c, 174 const char *filename, 175 const char *matchline, 176 const char *scan_fmt, 177 T returnval) { 178 FILE *fp = NULL; 179 char *p; 180 char file[MAXPATHLEN+1]; 181 char buf[MAXPATHLEN+1]; 182 char discard[MAXPATHLEN+1]; 183 bool found_match = false; 184 185 if (c == NULL) { 186 log_debug(os, container)("subsystem_file_line_contents: CgroupSubsytem* is NULL"); 187 return OSCONTAINER_ERROR; 188 } 189 if (c->subsystem_path() == NULL) { 190 log_debug(os, container)("subsystem_file_line_contents: subsystem path is NULL"); 191 return OSCONTAINER_ERROR; 192 } 193 194 strncpy(file, c->subsystem_path(), MAXPATHLEN); 195 file[MAXPATHLEN-1] = '\0'; 196 int filelen = strlen(file); 197 if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) { 198 log_debug(os, container)("File path too long %s, %s", file, filename); 199 return OSCONTAINER_ERROR; 200 } 201 strncat(file, filename, MAXPATHLEN-filelen); 202 log_trace(os, container)("Path to %s is %s", filename, file); 203 fp = fopen(file, "r"); 204 if (fp != NULL) { 205 int err = 0; 206 while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) { 207 found_match = false; 208 if (matchline == NULL) { 209 // single-line file case 210 int matched = sscanf(p, scan_fmt, returnval); 211 found_match = (matched == 1); 212 } else { 213 // multi-line file case 214 if (strstr(p, matchline) != NULL) { 215 // discard matchline string prefix 216 int matched = sscanf(p, scan_fmt, discard, returnval); 217 found_match = (matched == 2); 218 } else { 219 continue; // substring not found 220 } 221 } 222 if (found_match) { 223 fclose(fp); 224 return 0; 225 } else { 226 err = 1; 227 log_debug(os, container)("Type %s not found in file %s", scan_fmt, file); 228 } 229 } 230 if (err == 0) { 231 log_debug(os, container)("Empty file %s", file); 232 } 233 } else { 234 log_debug(os, container)("Open of file %s failed, %s", file, os::strerror(errno)); 235 } 236 if (fp != NULL) 237 fclose(fp); 238 return OSCONTAINER_ERROR; 239 } 240 PRAGMA_DIAG_POP 241 242 #define GET_CONTAINER_INFO(return_type, subsystem, filename, \ 243 logstring, scan_fmt, variable) \ 244 return_type variable; \ 245 { \ 246 int err; \ 247 err = subsystem_file_line_contents(subsystem, \ 248 filename, \ 249 NULL, \ 250 scan_fmt, \ 251 &variable); \ 252 if (err != 0) \ 253 return (return_type) OSCONTAINER_ERROR; \ 254 \ 255 log_trace(os, container)(logstring, variable); \ 256 } 257 258 #define GET_CONTAINER_INFO_CPTR(return_type, subsystem, filename, \ 259 logstring, scan_fmt, variable, bufsize) \ 260 char variable[bufsize]; \ 261 { \ 262 int err; \ 263 err = subsystem_file_line_contents(subsystem, \ 264 filename, \ 265 NULL, \ 266 scan_fmt, \ 267 variable); \ 268 if (err != 0) \ 269 return (return_type) NULL; \ 270 \ 271 log_trace(os, container)(logstring, variable); \ 272 } 273 274 #define GET_CONTAINER_INFO_LINE(return_type, subsystem, filename, \ 275 matchline, logstring, scan_fmt, variable) \ 276 return_type variable; \ 277 { \ 278 int err; \ 279 err = subsystem_file_line_contents(subsystem, \ 280 filename, \ 281 matchline, \ 282 scan_fmt, \ 283 &variable); \ 284 if (err != 0) \ 285 return (return_type) OSCONTAINER_ERROR; \ 286 \ 287 log_trace(os, container)(logstring, variable); \ 288 } 289 290 /* init 291 * 292 * Initialize the container support and determine if 293 * we are running under cgroup control. 294 */ 295 void OSContainer::init() { 296 FILE *mntinfo = NULL; 297 FILE *cgroup = NULL; 298 char buf[MAXPATHLEN+1]; 299 char tmproot[MAXPATHLEN+1]; 300 char tmpmount[MAXPATHLEN+1]; 301 char *p; 302 jlong mem_limit; 303 304 assert(!_is_initialized, "Initializing OSContainer more than once"); 305 306 _is_initialized = true; 307 _is_containerized = false; 308 309 _unlimited_memory = (LONG_MAX / os::vm_page_size()) * os::vm_page_size(); 310 311 log_trace(os, container)("OSContainer::init: Initializing Container Support"); 312 if (!UseContainerSupport) { 313 log_trace(os, container)("Container Support not enabled"); 314 return; 315 } 316 317 /* 318 * Find the cgroup mount point for memory and cpuset 319 * by reading /proc/self/mountinfo 320 * 321 * Example for docker: 322 * 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory 323 * 324 * Example for host: 325 * 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory 326 */ 327 mntinfo = fopen("/proc/self/mountinfo", "r"); 328 if (mntinfo == NULL) { 329 log_debug(os, container)("Can't open /proc/self/mountinfo, %s", 330 os::strerror(errno)); 331 return; 332 } 333 334 while ((p = fgets(buf, MAXPATHLEN, mntinfo)) != NULL) { 335 char tmpcgroups[MAXPATHLEN+1]; 336 char *cptr = tmpcgroups; 337 char *token; 338 339 // mountinfo format is documented at https://www.kernel.org/doc/Documentation/filesystems/proc.txt 340 if (sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- cgroup %*s %s", tmproot, tmpmount, tmpcgroups) != 3) { 341 continue; 342 } 343 while ((token = strsep(&cptr, ",")) != NULL) { 344 if (strcmp(token, "memory") == 0) { 345 memory = new CgroupMemorySubsystem(tmproot, tmpmount); 346 } else if (strcmp(token, "cpuset") == 0) { 347 cpuset = new CgroupSubsystem(tmproot, tmpmount); 348 } else if (strcmp(token, "cpu") == 0) { 349 cpu = new CgroupSubsystem(tmproot, tmpmount); 350 } else if (strcmp(token, "cpuacct") == 0) { 351 cpuacct= new CgroupSubsystem(tmproot, tmpmount); 352 } 353 } 354 } 355 356 fclose(mntinfo); 357 358 if (memory == NULL) { 359 log_debug(os, container)("Required cgroup memory subsystem not found"); 360 return; 361 } 362 if (cpuset == NULL) { 363 log_debug(os, container)("Required cgroup cpuset subsystem not found"); 364 return; 365 } 366 if (cpu == NULL) { 367 log_debug(os, container)("Required cgroup cpu subsystem not found"); 368 return; 369 } 370 if (cpuacct == NULL) { 371 log_debug(os, container)("Required cgroup cpuacct subsystem not found"); 372 return; 373 } 374 375 /* 376 * Read /proc/self/cgroup and map host mount point to 377 * local one via /proc/self/mountinfo content above 378 * 379 * Docker example: 380 * 5:memory:/docker/6558aed8fc662b194323ceab5b964f69cf36b3e8af877a14b80256e93aecb044 381 * 382 * Host example: 383 * 5:memory:/user.slice 384 * 385 * Construct a path to the process specific memory and cpuset 386 * cgroup directory. 387 * 388 * For a container running under Docker from memory example above 389 * the paths would be: 390 * 391 * /sys/fs/cgroup/memory 392 * 393 * For a Host from memory example above the path would be: 394 * 395 * /sys/fs/cgroup/memory/user.slice 396 * 397 */ 398 cgroup = fopen("/proc/self/cgroup", "r"); 399 if (cgroup == NULL) { 400 log_debug(os, container)("Can't open /proc/self/cgroup, %s", 401 os::strerror(errno)); 402 return; 403 } 404 405 while ((p = fgets(buf, MAXPATHLEN, cgroup)) != NULL) { 406 char *controllers; 407 char *token; 408 char *base; 409 410 /* Skip cgroup number */ 411 strsep(&p, ":"); 412 /* Get controllers and base */ 413 controllers = strsep(&p, ":"); 414 base = strsep(&p, "\n"); 415 416 if (controllers == NULL) { 417 continue; 418 } 419 420 while ((token = strsep(&controllers, ",")) != NULL) { 421 if (strcmp(token, "memory") == 0) { 422 memory->set_subsystem_path(base); 423 jlong hierarchy = uses_mem_hierarchy(); 424 if (hierarchy > 0) { 425 memory->set_hierarchical(true); 426 } 427 } else if (strcmp(token, "cpuset") == 0) { 428 cpuset->set_subsystem_path(base); 429 } else if (strcmp(token, "cpu") == 0) { 430 cpu->set_subsystem_path(base); 431 } else if (strcmp(token, "cpuacct") == 0) { 432 cpuacct->set_subsystem_path(base); 433 } 434 } 435 } 436 437 fclose(cgroup); 438 439 // We need to update the amount of physical memory now that 440 // command line arguments have been processed. 441 if ((mem_limit = memory_limit_in_bytes()) > 0) { 442 os::Linux::set_physical_memory(mem_limit); 443 log_info(os, container)("Memory Limit is: " JLONG_FORMAT, mem_limit); 444 } 445 446 _is_containerized = true; 447 448 } 449 450 const char * OSContainer::container_type() { 451 if (is_containerized()) { 452 return "cgroupv1"; 453 } else { 454 return NULL; 455 } 456 } 457 458 /* uses_mem_hierarchy 459 * 460 * Return whether or not hierarchical cgroup accounting is being 461 * done. 462 * 463 * return: 464 * A number > 0 if true, or 465 * OSCONTAINER_ERROR for not supported 466 */ 467 jlong OSContainer::uses_mem_hierarchy() { 468 GET_CONTAINER_INFO(jlong, memory, "/memory.use_hierarchy", 469 "Use Hierarchy is: " JLONG_FORMAT, JLONG_FORMAT, use_hierarchy); 470 return use_hierarchy; 471 } 472 473 474 /* memory_limit_in_bytes 475 * 476 * Return the limit of available memory for this process. 477 * 478 * return: 479 * memory limit in bytes or 480 * -1 for unlimited 481 * OSCONTAINER_ERROR for not supported 482 */ 483 jlong OSContainer::memory_limit_in_bytes() { 484 if (!memory->should_check_memory_limit()) { 485 return memory->memory_limit_in_bytes(); 486 } 487 jlong memory_limit = read_memory_limit_in_bytes(); 488 // Update CgroupMemorySubsystem to avoid re-reading container settings too often 489 memory->set_memory_limit_in_bytes(memory_limit); 490 return memory_limit; 491 } 492 493 jlong OSContainer::read_memory_limit_in_bytes() { 494 GET_CONTAINER_INFO(julong, memory, "/memory.limit_in_bytes", 495 "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit); 496 497 if (memlimit >= _unlimited_memory) { 498 log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited"); 499 if (memory->is_hierarchical()) { 500 const char* matchline = "hierarchical_memory_limit"; 501 const char* format = "%s " JULONG_FORMAT; 502 GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline, 503 "Hierarchical Memory Limit is: " JULONG_FORMAT, format, hier_memlimit) 504 if (hier_memlimit >= _unlimited_memory) { 505 log_trace(os, container)("Hierarchical Memory Limit is: Unlimited"); 506 } else { 507 return (jlong)hier_memlimit; 508 } 509 } 510 return (jlong)-1; 511 } 512 else { 513 return (jlong)memlimit; 514 } 515 } 516 517 jlong OSContainer::memory_and_swap_limit_in_bytes() { 518 GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes", 519 "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit); 520 if (memswlimit >= _unlimited_memory) { 521 log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited"); 522 if (memory->is_hierarchical()) { 523 const char* matchline = "hierarchical_memsw_limit"; 524 const char* format = "%s " JULONG_FORMAT; 525 GET_CONTAINER_INFO_LINE(julong, memory, "/memory.stat", matchline, 526 "Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, format, hier_memlimit) 527 if (hier_memlimit >= _unlimited_memory) { 528 log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited"); 529 } else { 530 return (jlong)hier_memlimit; 531 } 532 } 533 return (jlong)-1; 534 } else { 535 return (jlong)memswlimit; 536 } 537 } 538 539 jlong OSContainer::memory_soft_limit_in_bytes() { 540 GET_CONTAINER_INFO(julong, memory, "/memory.soft_limit_in_bytes", 541 "Memory Soft Limit is: " JULONG_FORMAT, JULONG_FORMAT, memsoftlimit); 542 if (memsoftlimit >= _unlimited_memory) { 543 log_trace(os, container)("Memory Soft Limit is: Unlimited"); 544 return (jlong)-1; 545 } else { 546 return (jlong)memsoftlimit; 547 } 548 } 549 550 /* memory_usage_in_bytes 551 * 552 * Return the amount of used memory for this process. 553 * 554 * return: 555 * memory usage in bytes or 556 * -1 for unlimited 557 * OSCONTAINER_ERROR for not supported 558 */ 559 jlong OSContainer::memory_usage_in_bytes() { 560 GET_CONTAINER_INFO(jlong, memory, "/memory.usage_in_bytes", 561 "Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memusage); 562 return memusage; 563 } 564 565 /* memory_max_usage_in_bytes 566 * 567 * Return the maximum amount of used memory for this process. 568 * 569 * return: 570 * max memory usage in bytes or 571 * OSCONTAINER_ERROR for not supported 572 */ 573 jlong OSContainer::memory_max_usage_in_bytes() { 574 GET_CONTAINER_INFO(jlong, memory, "/memory.max_usage_in_bytes", 575 "Maximum Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memmaxusage); 576 return memmaxusage; 577 } 578 579 /* active_processor_count 580 * 581 * Calculate an appropriate number of active processors for the 582 * VM to use based on these three inputs. 583 * 584 * cpu affinity 585 * cgroup cpu quota & cpu period 586 * cgroup cpu shares 587 * 588 * Algorithm: 589 * 590 * Determine the number of available CPUs from sched_getaffinity 591 * 592 * If user specified a quota (quota != -1), calculate the number of 593 * required CPUs by dividing quota by period. 594 * 595 * If shares are in effect (shares != -1), calculate the number 596 * of CPUs required for the shares by dividing the share value 597 * by PER_CPU_SHARES. 598 * 599 * All results of division are rounded up to the next whole number. 600 * 601 * If neither shares or quotas have been specified, return the 602 * number of active processors in the system. 603 * 604 * If both shares and quotas have been specified, the results are 605 * based on the flag PreferContainerQuotaForCPUCount. If true, 606 * return the quota value. If false return the smallest value 607 * between shares or quotas. 608 * 609 * If shares and/or quotas have been specified, the resulting number 610 * returned will never exceed the number of active processors. 611 * 612 * return: 613 * number of CPUs 614 */ 615 int OSContainer::active_processor_count() { 616 int quota_count = 0, share_count = 0; 617 int cpu_count, limit_count; 618 int result; 619 620 cpu_count = limit_count = os::Linux::active_processor_count(); 621 int quota = cpu_quota(); 622 int period = cpu_period(); 623 int share = cpu_shares(); 624 625 if (quota > -1 && period > 0) { 626 quota_count = ceilf((float)quota / (float)period); 627 log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count); 628 } 629 if (share > -1) { 630 share_count = ceilf((float)share / (float)PER_CPU_SHARES); 631 log_trace(os, container)("CPU Share count based on shares: %d", share_count); 632 } 633 634 // If both shares and quotas are setup results depend 635 // on flag PreferContainerQuotaForCPUCount. 636 // If true, limit CPU count to quota 637 // If false, use minimum of shares and quotas 638 if (quota_count !=0 && share_count != 0) { 639 if (PreferContainerQuotaForCPUCount) { 640 limit_count = quota_count; 641 } else { 642 limit_count = MIN2(quota_count, share_count); 643 } 644 } else if (quota_count != 0) { 645 limit_count = quota_count; 646 } else if (share_count != 0) { 647 limit_count = share_count; 648 } 649 650 result = MIN2(cpu_count, limit_count); 651 log_trace(os, container)("OSContainer::active_processor_count: %d", result); 652 return result; 653 } 654 655 char * OSContainer::cpu_cpuset_cpus() { 656 GET_CONTAINER_INFO_CPTR(cptr, cpuset, "/cpuset.cpus", 657 "cpuset.cpus is: %s", "%1023s", cpus, 1024); 658 return os::strdup(cpus); 659 } 660 661 char * OSContainer::cpu_cpuset_memory_nodes() { 662 GET_CONTAINER_INFO_CPTR(cptr, cpuset, "/cpuset.mems", 663 "cpuset.mems is: %s", "%1023s", mems, 1024); 664 return os::strdup(mems); 665 } 666 667 /* cpu_quota 668 * 669 * Return the number of milliseconds per period 670 * process is guaranteed to run. 671 * 672 * return: 673 * quota time in milliseconds 674 * -1 for no quota 675 * OSCONTAINER_ERROR for not supported 676 */ 677 int OSContainer::cpu_quota() { 678 GET_CONTAINER_INFO(int, cpu, "/cpu.cfs_quota_us", 679 "CPU Quota is: %d", "%d", quota); 680 return quota; 681 } 682 683 int OSContainer::cpu_period() { 684 GET_CONTAINER_INFO(int, cpu, "/cpu.cfs_period_us", 685 "CPU Period is: %d", "%d", period); 686 return period; 687 } 688 689 /* cpu_shares 690 * 691 * Return the amount of cpu shares available to the process 692 * 693 * return: 694 * Share number (typically a number relative to 1024) 695 * (2048 typically expresses 2 CPUs worth of processing) 696 * -1 for no share setup 697 * OSCONTAINER_ERROR for not supported 698 */ 699 int OSContainer::cpu_shares() { 700 GET_CONTAINER_INFO(int, cpu, "/cpu.shares", 701 "CPU Shares is: %d", "%d", shares); 702 // Convert 1024 to no shares setup 703 if (shares == 1024) return -1; 704 705 return shares; 706 }