1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/os/linux/vm/osContainer_linux.cpp Fri Jul 06 18:50:13 2018 +0000 1.3 @@ -0,0 +1,680 @@ 1.4 +/* 1.5 + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include <string.h> 1.29 +#include <math.h> 1.30 +#include <errno.h> 1.31 +#include "utilities/globalDefinitions.hpp" 1.32 +#include "memory/allocation.hpp" 1.33 +#include "runtime/os.hpp" 1.34 +#include "osContainer_linux.hpp" 1.35 + 1.36 +#define PER_CPU_SHARES 1024 1.37 + 1.38 +bool OSContainer::_is_initialized = false; 1.39 +bool OSContainer::_is_containerized = false; 1.40 +julong _unlimited_memory; 1.41 + 1.42 +class CgroupSubsystem: CHeapObj<mtInternal> { 1.43 + friend class OSContainer; 1.44 + 1.45 + private: 1.46 + /* mountinfo contents */ 1.47 + char *_root; 1.48 + char *_mount_point; 1.49 + 1.50 + /* Constructed subsystem directory */ 1.51 + char *_path; 1.52 + 1.53 + public: 1.54 + CgroupSubsystem(char *root, char *mountpoint) { 1.55 + _root = os::strdup(root); 1.56 + _mount_point = os::strdup(mountpoint); 1.57 + _path = NULL; 1.58 + } 1.59 + 1.60 + /* 1.61 + * Set directory to subsystem specific files based 1.62 + * on the contents of the mountinfo and cgroup files. 1.63 + */ 1.64 + void set_subsystem_path(char *cgroup_path) { 1.65 + char buf[MAXPATHLEN+1]; 1.66 + if (_root != NULL && cgroup_path != NULL) { 1.67 + if (strcmp(_root, "/") == 0) { 1.68 + int buflen; 1.69 + strncpy(buf, _mount_point, MAXPATHLEN); 1.70 + buf[MAXPATHLEN-1] = '\0'; 1.71 + if (strcmp(cgroup_path,"/") != 0) { 1.72 + buflen = strlen(buf); 1.73 + if ((buflen + strlen(cgroup_path)) > (MAXPATHLEN-1)) { 1.74 + return; 1.75 + } 1.76 + strncat(buf, cgroup_path, MAXPATHLEN-buflen); 1.77 + buf[MAXPATHLEN-1] = '\0'; 1.78 + } 1.79 + _path = os::strdup(buf); 1.80 + } else { 1.81 + if (strcmp(_root, cgroup_path) == 0) { 1.82 + strncpy(buf, _mount_point, MAXPATHLEN); 1.83 + buf[MAXPATHLEN-1] = '\0'; 1.84 + _path = os::strdup(buf); 1.85 + } else { 1.86 + char *p = strstr(_root, cgroup_path); 1.87 + if (p != NULL && p == _root) { 1.88 + if (strlen(cgroup_path) > strlen(_root)) { 1.89 + int buflen; 1.90 + strncpy(buf, _mount_point, MAXPATHLEN); 1.91 + buf[MAXPATHLEN-1] = '\0'; 1.92 + buflen = strlen(buf); 1.93 + if ((buflen + strlen(cgroup_path)) > (MAXPATHLEN-1)) { 1.94 + return; 1.95 + } 1.96 + strncat(buf, cgroup_path + strlen(_root), MAXPATHLEN-buflen); 1.97 + buf[MAXPATHLEN-1] = '\0'; 1.98 + _path = os::strdup(buf); 1.99 + } 1.100 + } 1.101 + } 1.102 + } 1.103 + } 1.104 + } 1.105 + 1.106 + char *subsystem_path() { return _path; } 1.107 +}; 1.108 + 1.109 +CgroupSubsystem* memory = NULL; 1.110 +CgroupSubsystem* cpuset = NULL; 1.111 +CgroupSubsystem* cpu = NULL; 1.112 +CgroupSubsystem* cpuacct = NULL; 1.113 + 1.114 +typedef char * cptr; 1.115 + 1.116 +PRAGMA_DIAG_PUSH 1.117 +PRAGMA_FORMAT_NONLITERAL_IGNORED 1.118 +template <typename T> int subsystem_file_contents(CgroupSubsystem* c, 1.119 + const char *filename, 1.120 + const char *scan_fmt, 1.121 + T returnval) { 1.122 + FILE *fp = NULL; 1.123 + char *p; 1.124 + char file[MAXPATHLEN+1]; 1.125 + char buf[MAXPATHLEN+1]; 1.126 + 1.127 + if (c == NULL) { 1.128 + if (PrintContainerInfo) { 1.129 + tty->print_cr("subsystem_file_contents: CgroupSubsytem* is NULL"); 1.130 + } 1.131 + return OSCONTAINER_ERROR; 1.132 + } 1.133 + if (c->subsystem_path() == NULL) { 1.134 + if (PrintContainerInfo) { 1.135 + tty->print_cr("subsystem_file_contents: subsystem path is NULL"); 1.136 + } 1.137 + return OSCONTAINER_ERROR; 1.138 + } 1.139 + 1.140 + strncpy(file, c->subsystem_path(), MAXPATHLEN); 1.141 + file[MAXPATHLEN-1] = '\0'; 1.142 + int filelen = strlen(file); 1.143 + if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) { 1.144 + if (PrintContainerInfo) { 1.145 + tty->print_cr("File path too long %s, %s", file, filename); 1.146 + } 1.147 + return OSCONTAINER_ERROR; 1.148 + } 1.149 + strncat(file, filename, MAXPATHLEN-filelen); 1.150 + if (PrintContainerInfo) { 1.151 + tty->print_cr("Path to %s is %s", filename, file); 1.152 + } 1.153 + fp = fopen(file, "r"); 1.154 + if (fp != NULL) { 1.155 + p = fgets(buf, MAXPATHLEN, fp); 1.156 + if (p != NULL) { 1.157 + int matched = sscanf(p, scan_fmt, returnval); 1.158 + if (matched == 1) { 1.159 + fclose(fp); 1.160 + return 0; 1.161 + } else { 1.162 + if (PrintContainerInfo) { 1.163 + tty->print_cr("Type %s not found in file %s", scan_fmt, file); 1.164 + } 1.165 + } 1.166 + } else { 1.167 + if (PrintContainerInfo) { 1.168 + tty->print_cr("Empty file %s", file); 1.169 + } 1.170 + } 1.171 + } else { 1.172 + if (PrintContainerInfo) { 1.173 + tty->print_cr("Open of file %s failed, %s", file, strerror(errno)); 1.174 + } 1.175 + } 1.176 + if (fp != NULL) 1.177 + fclose(fp); 1.178 + return OSCONTAINER_ERROR; 1.179 +} 1.180 +PRAGMA_DIAG_POP 1.181 + 1.182 +#define GET_CONTAINER_INFO(return_type, subsystem, filename, \ 1.183 + logstring, scan_fmt, variable) \ 1.184 + return_type variable; \ 1.185 +{ \ 1.186 + int err; \ 1.187 + err = subsystem_file_contents(subsystem, \ 1.188 + filename, \ 1.189 + scan_fmt, \ 1.190 + &variable); \ 1.191 + if (err != 0) \ 1.192 + return (return_type) OSCONTAINER_ERROR; \ 1.193 + \ 1.194 + if (PrintContainerInfo) \ 1.195 + tty->print_cr(logstring, variable); \ 1.196 +} 1.197 + 1.198 +#define GET_CONTAINER_INFO_CPTR(return_type, subsystem, filename, \ 1.199 + logstring, scan_fmt, variable, bufsize) \ 1.200 + char variable[bufsize]; \ 1.201 +{ \ 1.202 + int err; \ 1.203 + err = subsystem_file_contents(subsystem, \ 1.204 + filename, \ 1.205 + scan_fmt, \ 1.206 + variable); \ 1.207 + if (err != 0) \ 1.208 + return (return_type) NULL; \ 1.209 + \ 1.210 + if (PrintContainerInfo) \ 1.211 + tty->print_cr(logstring, variable); \ 1.212 +} 1.213 + 1.214 +/* init 1.215 + * 1.216 + * Initialize the container support and determine if 1.217 + * we are running under cgroup control. 1.218 + */ 1.219 +void OSContainer::init() { 1.220 + int mountid; 1.221 + int parentid; 1.222 + int major; 1.223 + int minor; 1.224 + FILE *mntinfo = NULL; 1.225 + FILE *cgroup = NULL; 1.226 + char buf[MAXPATHLEN+1]; 1.227 + char tmproot[MAXPATHLEN+1]; 1.228 + char tmpmount[MAXPATHLEN+1]; 1.229 + char tmpbase[MAXPATHLEN+1]; 1.230 + char *p; 1.231 + jlong mem_limit; 1.232 + 1.233 + assert(!_is_initialized, "Initializing OSContainer more than once"); 1.234 + 1.235 + _is_initialized = true; 1.236 + _is_containerized = false; 1.237 + 1.238 + _unlimited_memory = (LONG_MAX / os::vm_page_size()) * os::vm_page_size(); 1.239 + 1.240 + if (PrintContainerInfo) { 1.241 + tty->print_cr("OSContainer::init: Initializing Container Support"); 1.242 + } 1.243 + if (!UseContainerSupport) { 1.244 + if (PrintContainerInfo) { 1.245 + tty->print_cr("Container Support not enabled"); 1.246 + } 1.247 + return; 1.248 + } 1.249 + 1.250 + /* 1.251 + * Find the cgroup mount point for memory and cpuset 1.252 + * by reading /proc/self/mountinfo 1.253 + * 1.254 + * Example for docker: 1.255 + * 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory 1.256 + * 1.257 + * Example for host: 1.258 + * 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory 1.259 + */ 1.260 + mntinfo = fopen("/proc/self/mountinfo", "r"); 1.261 + if (mntinfo == NULL) { 1.262 + if (PrintContainerInfo) { 1.263 + tty->print_cr("Can't open /proc/self/mountinfo, %s", 1.264 + strerror(errno)); 1.265 + } 1.266 + return; 1.267 + } 1.268 + 1.269 + while ( (p = fgets(buf, MAXPATHLEN, mntinfo)) != NULL) { 1.270 + // Look for the filesystem type and see if it's cgroup 1.271 + char fstype[MAXPATHLEN+1]; 1.272 + fstype[0] = '\0'; 1.273 + char *s = strstr(p, " - "); 1.274 + if (s != NULL && 1.275 + sscanf(s, " - %s", fstype) == 1 && 1.276 + strcmp(fstype, "cgroup") == 0) { 1.277 + 1.278 + if (strstr(p, "memory") != NULL) { 1.279 + int matched = sscanf(p, "%d %d %d:%d %s %s", 1.280 + &mountid, 1.281 + &parentid, 1.282 + &major, 1.283 + &minor, 1.284 + tmproot, 1.285 + tmpmount); 1.286 + if (matched == 6) { 1.287 + memory = new CgroupSubsystem(tmproot, tmpmount); 1.288 + } 1.289 + else 1.290 + if (PrintContainerInfo) { 1.291 + tty->print_cr("Incompatible str containing cgroup and memory: %s", p); 1.292 + } 1.293 + } else if (strstr(p, "cpuset") != NULL) { 1.294 + int matched = sscanf(p, "%d %d %d:%d %s %s", 1.295 + &mountid, 1.296 + &parentid, 1.297 + &major, 1.298 + &minor, 1.299 + tmproot, 1.300 + tmpmount); 1.301 + if (matched == 6) { 1.302 + cpuset = new CgroupSubsystem(tmproot, tmpmount); 1.303 + } 1.304 + else { 1.305 + if (PrintContainerInfo) { 1.306 + tty->print_cr("Incompatible str containing cgroup and cpuset: %s", p); 1.307 + } 1.308 + } 1.309 + } else if (strstr(p, "cpu,cpuacct") != NULL || strstr(p, "cpuacct,cpu") != NULL) { 1.310 + int matched = sscanf(p, "%d %d %d:%d %s %s", 1.311 + &mountid, 1.312 + &parentid, 1.313 + &major, 1.314 + &minor, 1.315 + tmproot, 1.316 + tmpmount); 1.317 + if (matched == 6) { 1.318 + cpu = new CgroupSubsystem(tmproot, tmpmount); 1.319 + cpuacct = new CgroupSubsystem(tmproot, tmpmount); 1.320 + } 1.321 + else { 1.322 + if (PrintContainerInfo) { 1.323 + tty->print_cr("Incompatible str containing cgroup and cpu,cpuacct: %s", p); 1.324 + } 1.325 + } 1.326 + } else if (strstr(p, "cpuacct") != NULL) { 1.327 + int matched = sscanf(p, "%d %d %d:%d %s %s", 1.328 + &mountid, 1.329 + &parentid, 1.330 + &major, 1.331 + &minor, 1.332 + tmproot, 1.333 + tmpmount); 1.334 + if (matched == 6) { 1.335 + cpuacct = new CgroupSubsystem(tmproot, tmpmount); 1.336 + } 1.337 + else { 1.338 + if (PrintContainerInfo) { 1.339 + tty->print_cr("Incompatible str containing cgroup and cpuacct: %s", p); 1.340 + } 1.341 + } 1.342 + } else if (strstr(p, "cpu") != NULL) { 1.343 + int matched = sscanf(p, "%d %d %d:%d %s %s", 1.344 + &mountid, 1.345 + &parentid, 1.346 + &major, 1.347 + &minor, 1.348 + tmproot, 1.349 + tmpmount); 1.350 + if (matched == 6) { 1.351 + cpu = new CgroupSubsystem(tmproot, tmpmount); 1.352 + } 1.353 + else { 1.354 + if (PrintContainerInfo) { 1.355 + tty->print_cr("Incompatible str containing cgroup and cpu: %s", p); 1.356 + } 1.357 + } 1.358 + } 1.359 + } 1.360 + } 1.361 + 1.362 + fclose(mntinfo); 1.363 + 1.364 + if (memory == NULL) { 1.365 + if (PrintContainerInfo) { 1.366 + tty->print_cr("Required cgroup memory subsystem not found"); 1.367 + } 1.368 + return; 1.369 + } 1.370 + if (cpuset == NULL) { 1.371 + if (PrintContainerInfo) { 1.372 + tty->print_cr("Required cgroup cpuset subsystem not found"); 1.373 + } 1.374 + return; 1.375 + } 1.376 + if (cpu == NULL) { 1.377 + if (PrintContainerInfo) { 1.378 + tty->print_cr("Required cgroup cpu subsystem not found"); 1.379 + } 1.380 + return; 1.381 + } 1.382 + if (cpuacct == NULL) { 1.383 + if (PrintContainerInfo) { 1.384 + tty->print_cr("Required cgroup cpuacct subsystem not found"); 1.385 + } 1.386 + return; 1.387 + } 1.388 + 1.389 + /* 1.390 + * Read /proc/self/cgroup and map host mount point to 1.391 + * local one via /proc/self/mountinfo content above 1.392 + * 1.393 + * Docker example: 1.394 + * 5:memory:/docker/6558aed8fc662b194323ceab5b964f69cf36b3e8af877a14b80256e93aecb044 1.395 + * 1.396 + * Host example: 1.397 + * 5:memory:/user.slice 1.398 + * 1.399 + * Construct a path to the process specific memory and cpuset 1.400 + * cgroup directory. 1.401 + * 1.402 + * For a container running under Docker from memory example above 1.403 + * the paths would be: 1.404 + * 1.405 + * /sys/fs/cgroup/memory 1.406 + * 1.407 + * For a Host from memory example above the path would be: 1.408 + * 1.409 + * /sys/fs/cgroup/memory/user.slice 1.410 + * 1.411 + */ 1.412 + cgroup = fopen("/proc/self/cgroup", "r"); 1.413 + if (cgroup == NULL) { 1.414 + if (PrintContainerInfo) { 1.415 + tty->print_cr("Can't open /proc/self/cgroup, %s", 1.416 + strerror(errno)); 1.417 + } 1.418 + return; 1.419 + } 1.420 + 1.421 + while ( (p = fgets(buf, MAXPATHLEN, cgroup)) != NULL) { 1.422 + int cgno; 1.423 + int matched; 1.424 + char *controller; 1.425 + char *base; 1.426 + 1.427 + /* Skip cgroup number */ 1.428 + strsep(&p, ":"); 1.429 + /* Get controller and base */ 1.430 + controller = strsep(&p, ":"); 1.431 + base = strsep(&p, "\n"); 1.432 + 1.433 + if (controller != NULL) { 1.434 + if (strstr(controller, "memory") != NULL) { 1.435 + memory->set_subsystem_path(base); 1.436 + } else if (strstr(controller, "cpuset") != NULL) { 1.437 + cpuset->set_subsystem_path(base); 1.438 + } else if (strstr(controller, "cpu,cpuacct") != NULL || strstr(controller, "cpuacct,cpu") != NULL) { 1.439 + cpu->set_subsystem_path(base); 1.440 + cpuacct->set_subsystem_path(base); 1.441 + } else if (strstr(controller, "cpuacct") != NULL) { 1.442 + cpuacct->set_subsystem_path(base); 1.443 + } else if (strstr(controller, "cpu") != NULL) { 1.444 + cpu->set_subsystem_path(base); 1.445 + } 1.446 + } 1.447 + } 1.448 + 1.449 + fclose(cgroup); 1.450 + 1.451 + // We need to update the amount of physical memory now that 1.452 + // command line arguments have been processed. 1.453 + if ((mem_limit = memory_limit_in_bytes()) > 0) { 1.454 + os::Linux::set_physical_memory(mem_limit); 1.455 + } 1.456 + 1.457 + _is_containerized = true; 1.458 + 1.459 +} 1.460 + 1.461 +const char * OSContainer::container_type() { 1.462 + if (is_containerized()) { 1.463 + return "cgroupv1"; 1.464 + } else { 1.465 + return NULL; 1.466 + } 1.467 +} 1.468 + 1.469 + 1.470 +/* memory_limit_in_bytes 1.471 + * 1.472 + * Return the limit of available memory for this process. 1.473 + * 1.474 + * return: 1.475 + * memory limit in bytes or 1.476 + * -1 for unlimited 1.477 + * OSCONTAINER_ERROR for not supported 1.478 + */ 1.479 +jlong OSContainer::memory_limit_in_bytes() { 1.480 + GET_CONTAINER_INFO(julong, memory, "/memory.limit_in_bytes", 1.481 + "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit); 1.482 + 1.483 + if (memlimit >= _unlimited_memory) { 1.484 + if (PrintContainerInfo) { 1.485 + tty->print_cr("Memory Limit is: Unlimited"); 1.486 + } 1.487 + return (jlong)-1; 1.488 + } 1.489 + else { 1.490 + return (jlong)memlimit; 1.491 + } 1.492 +} 1.493 + 1.494 +jlong OSContainer::memory_and_swap_limit_in_bytes() { 1.495 + GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes", 1.496 + "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit); 1.497 + if (memswlimit >= _unlimited_memory) { 1.498 + if (PrintContainerInfo) { 1.499 + tty->print_cr("Memory and Swap Limit is: Unlimited"); 1.500 + } 1.501 + return (jlong)-1; 1.502 + } else { 1.503 + return (jlong)memswlimit; 1.504 + } 1.505 +} 1.506 + 1.507 +jlong OSContainer::memory_soft_limit_in_bytes() { 1.508 + GET_CONTAINER_INFO(julong, memory, "/memory.soft_limit_in_bytes", 1.509 + "Memory Soft Limit is: " JULONG_FORMAT, JULONG_FORMAT, memsoftlimit); 1.510 + if (memsoftlimit >= _unlimited_memory) { 1.511 + if (PrintContainerInfo) { 1.512 + tty->print_cr("Memory Soft Limit is: Unlimited"); 1.513 + } 1.514 + return (jlong)-1; 1.515 + } else { 1.516 + return (jlong)memsoftlimit; 1.517 + } 1.518 +} 1.519 + 1.520 +/* memory_usage_in_bytes 1.521 + * 1.522 + * Return the amount of used memory for this process. 1.523 + * 1.524 + * return: 1.525 + * memory usage in bytes or 1.526 + * -1 for unlimited 1.527 + * OSCONTAINER_ERROR for not supported 1.528 + */ 1.529 +jlong OSContainer::memory_usage_in_bytes() { 1.530 + GET_CONTAINER_INFO(jlong, memory, "/memory.usage_in_bytes", 1.531 + "Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memusage); 1.532 + return memusage; 1.533 +} 1.534 + 1.535 +/* memory_max_usage_in_bytes 1.536 + * 1.537 + * Return the maximum amount of used memory for this process. 1.538 + * 1.539 + * return: 1.540 + * max memory usage in bytes or 1.541 + * OSCONTAINER_ERROR for not supported 1.542 + */ 1.543 +jlong OSContainer::memory_max_usage_in_bytes() { 1.544 + GET_CONTAINER_INFO(jlong, memory, "/memory.max_usage_in_bytes", 1.545 + "Maximum Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memmaxusage); 1.546 + return memmaxusage; 1.547 +} 1.548 + 1.549 +/* active_processor_count 1.550 + * 1.551 + * Calculate an appropriate number of active processors for the 1.552 + * VM to use based on these three inputs. 1.553 + * 1.554 + * cpu affinity 1.555 + * cgroup cpu quota & cpu period 1.556 + * cgroup cpu shares 1.557 + * 1.558 + * Algorithm: 1.559 + * 1.560 + * Determine the number of available CPUs from sched_getaffinity 1.561 + * 1.562 + * If user specified a quota (quota != -1), calculate the number of 1.563 + * required CPUs by dividing quota by period. 1.564 + * 1.565 + * If shares are in effect (shares != -1), calculate the number 1.566 + * of CPUs required for the shares by dividing the share value 1.567 + * by PER_CPU_SHARES. 1.568 + * 1.569 + * All results of division are rounded up to the next whole number. 1.570 + * 1.571 + * If neither shares or quotas have been specified, return the 1.572 + * number of active processors in the system. 1.573 + * 1.574 + * If both shares and quotas have been specified, the results are 1.575 + * based on the flag PreferContainerQuotaForCPUCount. If true, 1.576 + * return the quota value. If false return the smallest value 1.577 + * between shares or quotas. 1.578 + * 1.579 + * If shares and/or quotas have been specified, the resulting number 1.580 + * returned will never exceed the number of active processors. 1.581 + * 1.582 + * return: 1.583 + * number of CPUs 1.584 + */ 1.585 +int OSContainer::active_processor_count() { 1.586 + int quota_count = 0, share_count = 0; 1.587 + int cpu_count, limit_count; 1.588 + int result; 1.589 + 1.590 + cpu_count = limit_count = os::Linux::active_processor_count(); 1.591 + int quota = cpu_quota(); 1.592 + int period = cpu_period(); 1.593 + int share = cpu_shares(); 1.594 + 1.595 + if (quota > -1 && period > 0) { 1.596 + quota_count = ceilf((float)quota / (float)period); 1.597 + if (PrintContainerInfo) { 1.598 + tty->print_cr("CPU Quota count based on quota/period: %d", quota_count); 1.599 + } 1.600 + } 1.601 + if (share > -1) { 1.602 + share_count = ceilf((float)share / (float)PER_CPU_SHARES); 1.603 + if (PrintContainerInfo) { 1.604 + tty->print_cr("CPU Share count based on shares: %d", share_count); 1.605 + } 1.606 + } 1.607 + 1.608 + // If both shares and quotas are setup results depend 1.609 + // on flag PreferContainerQuotaForCPUCount. 1.610 + // If true, limit CPU count to quota 1.611 + // If false, use minimum of shares and quotas 1.612 + if (quota_count !=0 && share_count != 0) { 1.613 + if (PreferContainerQuotaForCPUCount) { 1.614 + limit_count = quota_count; 1.615 + } else { 1.616 + limit_count = MIN2(quota_count, share_count); 1.617 + } 1.618 + } else if (quota_count != 0) { 1.619 + limit_count = quota_count; 1.620 + } else if (share_count != 0) { 1.621 + limit_count = share_count; 1.622 + } 1.623 + 1.624 + result = MIN2(cpu_count, limit_count); 1.625 + if (PrintContainerInfo) { 1.626 + tty->print_cr("OSContainer::active_processor_count: %d", result); 1.627 + } 1.628 + return result; 1.629 +} 1.630 + 1.631 +char * OSContainer::cpu_cpuset_cpus() { 1.632 + GET_CONTAINER_INFO_CPTR(cptr, cpuset, "/cpuset.cpus", 1.633 + "cpuset.cpus is: %s", "%1023s", cpus, 1024); 1.634 + return os::strdup(cpus); 1.635 +} 1.636 + 1.637 +char * OSContainer::cpu_cpuset_memory_nodes() { 1.638 + GET_CONTAINER_INFO_CPTR(cptr, cpuset, "/cpuset.mems", 1.639 + "cpuset.mems is: %s", "%1023s", mems, 1024); 1.640 + return os::strdup(mems); 1.641 +} 1.642 + 1.643 +/* cpu_quota 1.644 + * 1.645 + * Return the number of milliseconds per period 1.646 + * process is guaranteed to run. 1.647 + * 1.648 + * return: 1.649 + * quota time in milliseconds 1.650 + * -1 for no quota 1.651 + * OSCONTAINER_ERROR for not supported 1.652 + */ 1.653 +int OSContainer::cpu_quota() { 1.654 + GET_CONTAINER_INFO(int, cpu, "/cpu.cfs_quota_us", 1.655 + "CPU Quota is: %d", "%d", quota); 1.656 + return quota; 1.657 +} 1.658 + 1.659 +int OSContainer::cpu_period() { 1.660 + GET_CONTAINER_INFO(int, cpu, "/cpu.cfs_period_us", 1.661 + "CPU Period is: %d", "%d", period); 1.662 + return period; 1.663 +} 1.664 + 1.665 +/* cpu_shares 1.666 + * 1.667 + * Return the amount of cpu shares available to the process 1.668 + * 1.669 + * return: 1.670 + * Share number (typically a number relative to 1024) 1.671 + * (2048 typically expresses 2 CPUs worth of processing) 1.672 + * -1 for no share setup 1.673 + * OSCONTAINER_ERROR for not supported 1.674 + */ 1.675 +int OSContainer::cpu_shares() { 1.676 + GET_CONTAINER_INFO(int, cpu, "/cpu.shares", 1.677 + "CPU Shares is: %d", "%d", shares); 1.678 + // Convert 1024 to no shares setup 1.679 + if (shares == 1024) return -1; 1.680 + 1.681 + return shares; 1.682 +} 1.683 +