Fri, 27 Jul 2018 11:47:10 +0100
Merge
.hgtags | file | annotate | diff | comparison | revisions |
1.1 --- a/.hgtags Wed Jul 11 15:59:47 2018 +0100 1.2 +++ b/.hgtags Fri Jul 27 11:47:10 2018 +0100 1.3 @@ -1190,3 +1190,5 @@ 1.4 eed8e846c982d7474dd07fc873ba02f83ad1f847 jdk8u181-b13 1.5 21a3fffc43418f4d75c2091bf03478330b8a9a98 jdk8u191-b01 1.6 2bf8498a25ec87c92584a6542f8724644c8c5706 jdk8u201-b00 1.7 +5aa3d728164a674d08ad847811be6bdd853e9bf8 jdk8u191-b02 1.8 +dd79b482625361458b2b34e7d669ee982eee06a4 jdk8u191-b03
2.1 --- a/src/os/aix/vm/os_aix.cpp Wed Jul 11 15:59:47 2018 +0100 2.2 +++ b/src/os/aix/vm/os_aix.cpp Fri Jul 27 11:47:10 2018 +0100 2.3 @@ -4008,6 +4008,16 @@ 2.4 }; 2.5 2.6 int os::active_processor_count() { 2.7 + // User has overridden the number of active processors 2.8 + if (ActiveProcessorCount > 0) { 2.9 + if (PrintActiveCpus) { 2.10 + tty->print_cr("active_processor_count: " 2.11 + "active processor count set by user : %d", 2.12 + ActiveProcessorCount); 2.13 + } 2.14 + return ActiveProcessorCount; 2.15 + } 2.16 + 2.17 int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN); 2.18 assert(online_cpus > 0 && online_cpus <= processor_count(), "sanity check"); 2.19 return online_cpus;
3.1 --- a/src/os/bsd/vm/os_bsd.cpp Wed Jul 11 15:59:47 2018 +0100 3.2 +++ b/src/os/bsd/vm/os_bsd.cpp Fri Jul 27 11:47:10 2018 +0100 3.3 @@ -3765,6 +3765,16 @@ 3.4 }; 3.5 3.6 int os::active_processor_count() { 3.7 + // User has overridden the number of active processors 3.8 + if (ActiveProcessorCount > 0) { 3.9 + if (PrintActiveCpus) { 3.10 + tty->print_cr("active_processor_count: " 3.11 + "active processor count set by user : %d", 3.12 + ActiveProcessorCount); 3.13 + } 3.14 + return ActiveProcessorCount; 3.15 + } 3.16 + 3.17 return _processor_count; 3.18 } 3.19
4.1 --- a/src/os/linux/vm/globals_linux.hpp Wed Jul 11 15:59:47 2018 +0100 4.2 +++ b/src/os/linux/vm/globals_linux.hpp Fri Jul 27 11:47:10 2018 +0100 4.3 @@ -1,5 +1,5 @@ 4.4 /* 4.5 - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. 4.6 + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. 4.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.8 * 4.9 * This code is free software; you can redistribute it and/or modify it 4.10 @@ -49,8 +49,13 @@ 4.11 product(bool, UseSHM, false, \ 4.12 "Use SYSV shared memory for large pages") \ 4.13 \ 4.14 - diagnostic(bool, PrintActiveCpus, false, \ 4.15 - "Print the number of CPUs detected in os::active_processor_count") 4.16 + product(bool, UseContainerSupport, true, \ 4.17 + "Enable detection and runtime container configuration support") \ 4.18 + \ 4.19 + product(bool, PreferContainerQuotaForCPUCount, true, \ 4.20 + "Calculate the container CPU availability based on the value" \ 4.21 + " of quotas (if set), when true. Otherwise, use the CPU" \ 4.22 + " shares value, provided it is less than quota.") 4.23 4.24 // 4.25 // Defines Linux-specific default values. The flags are available on all
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/os/linux/vm/osContainer_linux.cpp Fri Jul 27 11:47:10 2018 +0100 5.3 @@ -0,0 +1,680 @@ 5.4 +/* 5.5 + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.23 + * or visit www.oracle.com if you need additional information or have any 5.24 + * questions. 5.25 + * 5.26 + */ 5.27 + 5.28 +#include <string.h> 5.29 +#include <math.h> 5.30 +#include <errno.h> 5.31 +#include "utilities/globalDefinitions.hpp" 5.32 +#include "memory/allocation.hpp" 5.33 +#include "runtime/os.hpp" 5.34 +#include "osContainer_linux.hpp" 5.35 + 5.36 +#define PER_CPU_SHARES 1024 5.37 + 5.38 +bool OSContainer::_is_initialized = false; 5.39 +bool OSContainer::_is_containerized = false; 5.40 +julong _unlimited_memory; 5.41 + 5.42 +class CgroupSubsystem: CHeapObj<mtInternal> { 5.43 + friend class OSContainer; 5.44 + 5.45 + private: 5.46 + /* mountinfo contents */ 5.47 + char *_root; 5.48 + char *_mount_point; 5.49 + 5.50 + /* Constructed subsystem directory */ 5.51 + char *_path; 5.52 + 5.53 + public: 5.54 + CgroupSubsystem(char *root, char *mountpoint) { 5.55 + _root = os::strdup(root); 5.56 + _mount_point = os::strdup(mountpoint); 5.57 + _path = NULL; 5.58 + } 5.59 + 5.60 + /* 5.61 + * Set directory to subsystem specific files based 5.62 + * on the contents of the mountinfo and cgroup files. 5.63 + */ 5.64 + void set_subsystem_path(char *cgroup_path) { 5.65 + char buf[MAXPATHLEN+1]; 5.66 + if (_root != NULL && cgroup_path != NULL) { 5.67 + if (strcmp(_root, "/") == 0) { 5.68 + int buflen; 5.69 + strncpy(buf, _mount_point, MAXPATHLEN); 5.70 + buf[MAXPATHLEN-1] = '\0'; 5.71 + if (strcmp(cgroup_path,"/") != 0) { 5.72 + buflen = strlen(buf); 5.73 + if ((buflen + strlen(cgroup_path)) > (MAXPATHLEN-1)) { 5.74 + return; 5.75 + } 5.76 + strncat(buf, cgroup_path, MAXPATHLEN-buflen); 5.77 + buf[MAXPATHLEN-1] = '\0'; 5.78 + } 5.79 + _path = os::strdup(buf); 5.80 + } else { 5.81 + if (strcmp(_root, cgroup_path) == 0) { 5.82 + strncpy(buf, _mount_point, MAXPATHLEN); 5.83 + buf[MAXPATHLEN-1] = '\0'; 5.84 + _path = os::strdup(buf); 5.85 + } else { 5.86 + char *p = strstr(_root, cgroup_path); 5.87 + if (p != NULL && p == _root) { 5.88 + if (strlen(cgroup_path) > strlen(_root)) { 5.89 + int buflen; 5.90 + strncpy(buf, _mount_point, MAXPATHLEN); 5.91 + buf[MAXPATHLEN-1] = '\0'; 5.92 + buflen = strlen(buf); 5.93 + if ((buflen + strlen(cgroup_path)) > (MAXPATHLEN-1)) { 5.94 + return; 5.95 + } 5.96 + strncat(buf, cgroup_path + strlen(_root), MAXPATHLEN-buflen); 5.97 + buf[MAXPATHLEN-1] = '\0'; 5.98 + _path = os::strdup(buf); 5.99 + } 5.100 + } 5.101 + } 5.102 + } 5.103 + } 5.104 + } 5.105 + 5.106 + char *subsystem_path() { return _path; } 5.107 +}; 5.108 + 5.109 +CgroupSubsystem* memory = NULL; 5.110 +CgroupSubsystem* cpuset = NULL; 5.111 +CgroupSubsystem* cpu = NULL; 5.112 +CgroupSubsystem* cpuacct = NULL; 5.113 + 5.114 +typedef char * cptr; 5.115 + 5.116 +PRAGMA_DIAG_PUSH 5.117 +PRAGMA_FORMAT_NONLITERAL_IGNORED 5.118 +template <typename T> int subsystem_file_contents(CgroupSubsystem* c, 5.119 + const char *filename, 5.120 + const char *scan_fmt, 5.121 + T returnval) { 5.122 + FILE *fp = NULL; 5.123 + char *p; 5.124 + char file[MAXPATHLEN+1]; 5.125 + char buf[MAXPATHLEN+1]; 5.126 + 5.127 + if (c == NULL) { 5.128 + if (PrintContainerInfo) { 5.129 + tty->print_cr("subsystem_file_contents: CgroupSubsytem* is NULL"); 5.130 + } 5.131 + return OSCONTAINER_ERROR; 5.132 + } 5.133 + if (c->subsystem_path() == NULL) { 5.134 + if (PrintContainerInfo) { 5.135 + tty->print_cr("subsystem_file_contents: subsystem path is NULL"); 5.136 + } 5.137 + return OSCONTAINER_ERROR; 5.138 + } 5.139 + 5.140 + strncpy(file, c->subsystem_path(), MAXPATHLEN); 5.141 + file[MAXPATHLEN-1] = '\0'; 5.142 + int filelen = strlen(file); 5.143 + if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) { 5.144 + if (PrintContainerInfo) { 5.145 + tty->print_cr("File path too long %s, %s", file, filename); 5.146 + } 5.147 + return OSCONTAINER_ERROR; 5.148 + } 5.149 + strncat(file, filename, MAXPATHLEN-filelen); 5.150 + if (PrintContainerInfo) { 5.151 + tty->print_cr("Path to %s is %s", filename, file); 5.152 + } 5.153 + fp = fopen(file, "r"); 5.154 + if (fp != NULL) { 5.155 + p = fgets(buf, MAXPATHLEN, fp); 5.156 + if (p != NULL) { 5.157 + int matched = sscanf(p, scan_fmt, returnval); 5.158 + if (matched == 1) { 5.159 + fclose(fp); 5.160 + return 0; 5.161 + } else { 5.162 + if (PrintContainerInfo) { 5.163 + tty->print_cr("Type %s not found in file %s", scan_fmt, file); 5.164 + } 5.165 + } 5.166 + } else { 5.167 + if (PrintContainerInfo) { 5.168 + tty->print_cr("Empty file %s", file); 5.169 + } 5.170 + } 5.171 + } else { 5.172 + if (PrintContainerInfo) { 5.173 + tty->print_cr("Open of file %s failed, %s", file, strerror(errno)); 5.174 + } 5.175 + } 5.176 + if (fp != NULL) 5.177 + fclose(fp); 5.178 + return OSCONTAINER_ERROR; 5.179 +} 5.180 +PRAGMA_DIAG_POP 5.181 + 5.182 +#define GET_CONTAINER_INFO(return_type, subsystem, filename, \ 5.183 + logstring, scan_fmt, variable) \ 5.184 + return_type variable; \ 5.185 +{ \ 5.186 + int err; \ 5.187 + err = subsystem_file_contents(subsystem, \ 5.188 + filename, \ 5.189 + scan_fmt, \ 5.190 + &variable); \ 5.191 + if (err != 0) \ 5.192 + return (return_type) OSCONTAINER_ERROR; \ 5.193 + \ 5.194 + if (PrintContainerInfo) \ 5.195 + tty->print_cr(logstring, variable); \ 5.196 +} 5.197 + 5.198 +#define GET_CONTAINER_INFO_CPTR(return_type, subsystem, filename, \ 5.199 + logstring, scan_fmt, variable, bufsize) \ 5.200 + char variable[bufsize]; \ 5.201 +{ \ 5.202 + int err; \ 5.203 + err = subsystem_file_contents(subsystem, \ 5.204 + filename, \ 5.205 + scan_fmt, \ 5.206 + variable); \ 5.207 + if (err != 0) \ 5.208 + return (return_type) NULL; \ 5.209 + \ 5.210 + if (PrintContainerInfo) \ 5.211 + tty->print_cr(logstring, variable); \ 5.212 +} 5.213 + 5.214 +/* init 5.215 + * 5.216 + * Initialize the container support and determine if 5.217 + * we are running under cgroup control. 5.218 + */ 5.219 +void OSContainer::init() { 5.220 + int mountid; 5.221 + int parentid; 5.222 + int major; 5.223 + int minor; 5.224 + FILE *mntinfo = NULL; 5.225 + FILE *cgroup = NULL; 5.226 + char buf[MAXPATHLEN+1]; 5.227 + char tmproot[MAXPATHLEN+1]; 5.228 + char tmpmount[MAXPATHLEN+1]; 5.229 + char tmpbase[MAXPATHLEN+1]; 5.230 + char *p; 5.231 + jlong mem_limit; 5.232 + 5.233 + assert(!_is_initialized, "Initializing OSContainer more than once"); 5.234 + 5.235 + _is_initialized = true; 5.236 + _is_containerized = false; 5.237 + 5.238 + _unlimited_memory = (LONG_MAX / os::vm_page_size()) * os::vm_page_size(); 5.239 + 5.240 + if (PrintContainerInfo) { 5.241 + tty->print_cr("OSContainer::init: Initializing Container Support"); 5.242 + } 5.243 + if (!UseContainerSupport) { 5.244 + if (PrintContainerInfo) { 5.245 + tty->print_cr("Container Support not enabled"); 5.246 + } 5.247 + return; 5.248 + } 5.249 + 5.250 + /* 5.251 + * Find the cgroup mount point for memory and cpuset 5.252 + * by reading /proc/self/mountinfo 5.253 + * 5.254 + * Example for docker: 5.255 + * 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory 5.256 + * 5.257 + * Example for host: 5.258 + * 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory 5.259 + */ 5.260 + mntinfo = fopen("/proc/self/mountinfo", "r"); 5.261 + if (mntinfo == NULL) { 5.262 + if (PrintContainerInfo) { 5.263 + tty->print_cr("Can't open /proc/self/mountinfo, %s", 5.264 + strerror(errno)); 5.265 + } 5.266 + return; 5.267 + } 5.268 + 5.269 + while ( (p = fgets(buf, MAXPATHLEN, mntinfo)) != NULL) { 5.270 + // Look for the filesystem type and see if it's cgroup 5.271 + char fstype[MAXPATHLEN+1]; 5.272 + fstype[0] = '\0'; 5.273 + char *s = strstr(p, " - "); 5.274 + if (s != NULL && 5.275 + sscanf(s, " - %s", fstype) == 1 && 5.276 + strcmp(fstype, "cgroup") == 0) { 5.277 + 5.278 + if (strstr(p, "memory") != NULL) { 5.279 + int matched = sscanf(p, "%d %d %d:%d %s %s", 5.280 + &mountid, 5.281 + &parentid, 5.282 + &major, 5.283 + &minor, 5.284 + tmproot, 5.285 + tmpmount); 5.286 + if (matched == 6) { 5.287 + memory = new CgroupSubsystem(tmproot, tmpmount); 5.288 + } 5.289 + else 5.290 + if (PrintContainerInfo) { 5.291 + tty->print_cr("Incompatible str containing cgroup and memory: %s", p); 5.292 + } 5.293 + } else if (strstr(p, "cpuset") != NULL) { 5.294 + int matched = sscanf(p, "%d %d %d:%d %s %s", 5.295 + &mountid, 5.296 + &parentid, 5.297 + &major, 5.298 + &minor, 5.299 + tmproot, 5.300 + tmpmount); 5.301 + if (matched == 6) { 5.302 + cpuset = new CgroupSubsystem(tmproot, tmpmount); 5.303 + } 5.304 + else { 5.305 + if (PrintContainerInfo) { 5.306 + tty->print_cr("Incompatible str containing cgroup and cpuset: %s", p); 5.307 + } 5.308 + } 5.309 + } else if (strstr(p, "cpu,cpuacct") != NULL || strstr(p, "cpuacct,cpu") != NULL) { 5.310 + int matched = sscanf(p, "%d %d %d:%d %s %s", 5.311 + &mountid, 5.312 + &parentid, 5.313 + &major, 5.314 + &minor, 5.315 + tmproot, 5.316 + tmpmount); 5.317 + if (matched == 6) { 5.318 + cpu = new CgroupSubsystem(tmproot, tmpmount); 5.319 + cpuacct = new CgroupSubsystem(tmproot, tmpmount); 5.320 + } 5.321 + else { 5.322 + if (PrintContainerInfo) { 5.323 + tty->print_cr("Incompatible str containing cgroup and cpu,cpuacct: %s", p); 5.324 + } 5.325 + } 5.326 + } else if (strstr(p, "cpuacct") != NULL) { 5.327 + int matched = sscanf(p, "%d %d %d:%d %s %s", 5.328 + &mountid, 5.329 + &parentid, 5.330 + &major, 5.331 + &minor, 5.332 + tmproot, 5.333 + tmpmount); 5.334 + if (matched == 6) { 5.335 + cpuacct = new CgroupSubsystem(tmproot, tmpmount); 5.336 + } 5.337 + else { 5.338 + if (PrintContainerInfo) { 5.339 + tty->print_cr("Incompatible str containing cgroup and cpuacct: %s", p); 5.340 + } 5.341 + } 5.342 + } else if (strstr(p, "cpu") != NULL) { 5.343 + int matched = sscanf(p, "%d %d %d:%d %s %s", 5.344 + &mountid, 5.345 + &parentid, 5.346 + &major, 5.347 + &minor, 5.348 + tmproot, 5.349 + tmpmount); 5.350 + if (matched == 6) { 5.351 + cpu = new CgroupSubsystem(tmproot, tmpmount); 5.352 + } 5.353 + else { 5.354 + if (PrintContainerInfo) { 5.355 + tty->print_cr("Incompatible str containing cgroup and cpu: %s", p); 5.356 + } 5.357 + } 5.358 + } 5.359 + } 5.360 + } 5.361 + 5.362 + fclose(mntinfo); 5.363 + 5.364 + if (memory == NULL) { 5.365 + if (PrintContainerInfo) { 5.366 + tty->print_cr("Required cgroup memory subsystem not found"); 5.367 + } 5.368 + return; 5.369 + } 5.370 + if (cpuset == NULL) { 5.371 + if (PrintContainerInfo) { 5.372 + tty->print_cr("Required cgroup cpuset subsystem not found"); 5.373 + } 5.374 + return; 5.375 + } 5.376 + if (cpu == NULL) { 5.377 + if (PrintContainerInfo) { 5.378 + tty->print_cr("Required cgroup cpu subsystem not found"); 5.379 + } 5.380 + return; 5.381 + } 5.382 + if (cpuacct == NULL) { 5.383 + if (PrintContainerInfo) { 5.384 + tty->print_cr("Required cgroup cpuacct subsystem not found"); 5.385 + } 5.386 + return; 5.387 + } 5.388 + 5.389 + /* 5.390 + * Read /proc/self/cgroup and map host mount point to 5.391 + * local one via /proc/self/mountinfo content above 5.392 + * 5.393 + * Docker example: 5.394 + * 5:memory:/docker/6558aed8fc662b194323ceab5b964f69cf36b3e8af877a14b80256e93aecb044 5.395 + * 5.396 + * Host example: 5.397 + * 5:memory:/user.slice 5.398 + * 5.399 + * Construct a path to the process specific memory and cpuset 5.400 + * cgroup directory. 5.401 + * 5.402 + * For a container running under Docker from memory example above 5.403 + * the paths would be: 5.404 + * 5.405 + * /sys/fs/cgroup/memory 5.406 + * 5.407 + * For a Host from memory example above the path would be: 5.408 + * 5.409 + * /sys/fs/cgroup/memory/user.slice 5.410 + * 5.411 + */ 5.412 + cgroup = fopen("/proc/self/cgroup", "r"); 5.413 + if (cgroup == NULL) { 5.414 + if (PrintContainerInfo) { 5.415 + tty->print_cr("Can't open /proc/self/cgroup, %s", 5.416 + strerror(errno)); 5.417 + } 5.418 + return; 5.419 + } 5.420 + 5.421 + while ( (p = fgets(buf, MAXPATHLEN, cgroup)) != NULL) { 5.422 + int cgno; 5.423 + int matched; 5.424 + char *controller; 5.425 + char *base; 5.426 + 5.427 + /* Skip cgroup number */ 5.428 + strsep(&p, ":"); 5.429 + /* Get controller and base */ 5.430 + controller = strsep(&p, ":"); 5.431 + base = strsep(&p, "\n"); 5.432 + 5.433 + if (controller != NULL) { 5.434 + if (strstr(controller, "memory") != NULL) { 5.435 + memory->set_subsystem_path(base); 5.436 + } else if (strstr(controller, "cpuset") != NULL) { 5.437 + cpuset->set_subsystem_path(base); 5.438 + } else if (strstr(controller, "cpu,cpuacct") != NULL || strstr(controller, "cpuacct,cpu") != NULL) { 5.439 + cpu->set_subsystem_path(base); 5.440 + cpuacct->set_subsystem_path(base); 5.441 + } else if (strstr(controller, "cpuacct") != NULL) { 5.442 + cpuacct->set_subsystem_path(base); 5.443 + } else if (strstr(controller, "cpu") != NULL) { 5.444 + cpu->set_subsystem_path(base); 5.445 + } 5.446 + } 5.447 + } 5.448 + 5.449 + fclose(cgroup); 5.450 + 5.451 + // We need to update the amount of physical memory now that 5.452 + // command line arguments have been processed. 5.453 + if ((mem_limit = memory_limit_in_bytes()) > 0) { 5.454 + os::Linux::set_physical_memory(mem_limit); 5.455 + } 5.456 + 5.457 + _is_containerized = true; 5.458 + 5.459 +} 5.460 + 5.461 +const char * OSContainer::container_type() { 5.462 + if (is_containerized()) { 5.463 + return "cgroupv1"; 5.464 + } else { 5.465 + return NULL; 5.466 + } 5.467 +} 5.468 + 5.469 + 5.470 +/* memory_limit_in_bytes 5.471 + * 5.472 + * Return the limit of available memory for this process. 5.473 + * 5.474 + * return: 5.475 + * memory limit in bytes or 5.476 + * -1 for unlimited 5.477 + * OSCONTAINER_ERROR for not supported 5.478 + */ 5.479 +jlong OSContainer::memory_limit_in_bytes() { 5.480 + GET_CONTAINER_INFO(julong, memory, "/memory.limit_in_bytes", 5.481 + "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit); 5.482 + 5.483 + if (memlimit >= _unlimited_memory) { 5.484 + if (PrintContainerInfo) { 5.485 + tty->print_cr("Memory Limit is: Unlimited"); 5.486 + } 5.487 + return (jlong)-1; 5.488 + } 5.489 + else { 5.490 + return (jlong)memlimit; 5.491 + } 5.492 +} 5.493 + 5.494 +jlong OSContainer::memory_and_swap_limit_in_bytes() { 5.495 + GET_CONTAINER_INFO(julong, memory, "/memory.memsw.limit_in_bytes", 5.496 + "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit); 5.497 + if (memswlimit >= _unlimited_memory) { 5.498 + if (PrintContainerInfo) { 5.499 + tty->print_cr("Memory and Swap Limit is: Unlimited"); 5.500 + } 5.501 + return (jlong)-1; 5.502 + } else { 5.503 + return (jlong)memswlimit; 5.504 + } 5.505 +} 5.506 + 5.507 +jlong OSContainer::memory_soft_limit_in_bytes() { 5.508 + GET_CONTAINER_INFO(julong, memory, "/memory.soft_limit_in_bytes", 5.509 + "Memory Soft Limit is: " JULONG_FORMAT, JULONG_FORMAT, memsoftlimit); 5.510 + if (memsoftlimit >= _unlimited_memory) { 5.511 + if (PrintContainerInfo) { 5.512 + tty->print_cr("Memory Soft Limit is: Unlimited"); 5.513 + } 5.514 + return (jlong)-1; 5.515 + } else { 5.516 + return (jlong)memsoftlimit; 5.517 + } 5.518 +} 5.519 + 5.520 +/* memory_usage_in_bytes 5.521 + * 5.522 + * Return the amount of used memory for this process. 5.523 + * 5.524 + * return: 5.525 + * memory usage in bytes or 5.526 + * -1 for unlimited 5.527 + * OSCONTAINER_ERROR for not supported 5.528 + */ 5.529 +jlong OSContainer::memory_usage_in_bytes() { 5.530 + GET_CONTAINER_INFO(jlong, memory, "/memory.usage_in_bytes", 5.531 + "Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memusage); 5.532 + return memusage; 5.533 +} 5.534 + 5.535 +/* memory_max_usage_in_bytes 5.536 + * 5.537 + * Return the maximum amount of used memory for this process. 5.538 + * 5.539 + * return: 5.540 + * max memory usage in bytes or 5.541 + * OSCONTAINER_ERROR for not supported 5.542 + */ 5.543 +jlong OSContainer::memory_max_usage_in_bytes() { 5.544 + GET_CONTAINER_INFO(jlong, memory, "/memory.max_usage_in_bytes", 5.545 + "Maximum Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memmaxusage); 5.546 + return memmaxusage; 5.547 +} 5.548 + 5.549 +/* active_processor_count 5.550 + * 5.551 + * Calculate an appropriate number of active processors for the 5.552 + * VM to use based on these three inputs. 5.553 + * 5.554 + * cpu affinity 5.555 + * cgroup cpu quota & cpu period 5.556 + * cgroup cpu shares 5.557 + * 5.558 + * Algorithm: 5.559 + * 5.560 + * Determine the number of available CPUs from sched_getaffinity 5.561 + * 5.562 + * If user specified a quota (quota != -1), calculate the number of 5.563 + * required CPUs by dividing quota by period. 5.564 + * 5.565 + * If shares are in effect (shares != -1), calculate the number 5.566 + * of CPUs required for the shares by dividing the share value 5.567 + * by PER_CPU_SHARES. 5.568 + * 5.569 + * All results of division are rounded up to the next whole number. 5.570 + * 5.571 + * If neither shares or quotas have been specified, return the 5.572 + * number of active processors in the system. 5.573 + * 5.574 + * If both shares and quotas have been specified, the results are 5.575 + * based on the flag PreferContainerQuotaForCPUCount. If true, 5.576 + * return the quota value. If false return the smallest value 5.577 + * between shares or quotas. 5.578 + * 5.579 + * If shares and/or quotas have been specified, the resulting number 5.580 + * returned will never exceed the number of active processors. 5.581 + * 5.582 + * return: 5.583 + * number of CPUs 5.584 + */ 5.585 +int OSContainer::active_processor_count() { 5.586 + int quota_count = 0, share_count = 0; 5.587 + int cpu_count, limit_count; 5.588 + int result; 5.589 + 5.590 + cpu_count = limit_count = os::Linux::active_processor_count(); 5.591 + int quota = cpu_quota(); 5.592 + int period = cpu_period(); 5.593 + int share = cpu_shares(); 5.594 + 5.595 + if (quota > -1 && period > 0) { 5.596 + quota_count = ceilf((float)quota / (float)period); 5.597 + if (PrintContainerInfo) { 5.598 + tty->print_cr("CPU Quota count based on quota/period: %d", quota_count); 5.599 + } 5.600 + } 5.601 + if (share > -1) { 5.602 + share_count = ceilf((float)share / (float)PER_CPU_SHARES); 5.603 + if (PrintContainerInfo) { 5.604 + tty->print_cr("CPU Share count based on shares: %d", share_count); 5.605 + } 5.606 + } 5.607 + 5.608 + // If both shares and quotas are setup results depend 5.609 + // on flag PreferContainerQuotaForCPUCount. 5.610 + // If true, limit CPU count to quota 5.611 + // If false, use minimum of shares and quotas 5.612 + if (quota_count !=0 && share_count != 0) { 5.613 + if (PreferContainerQuotaForCPUCount) { 5.614 + limit_count = quota_count; 5.615 + } else { 5.616 + limit_count = MIN2(quota_count, share_count); 5.617 + } 5.618 + } else if (quota_count != 0) { 5.619 + limit_count = quota_count; 5.620 + } else if (share_count != 0) { 5.621 + limit_count = share_count; 5.622 + } 5.623 + 5.624 + result = MIN2(cpu_count, limit_count); 5.625 + if (PrintContainerInfo) { 5.626 + tty->print_cr("OSContainer::active_processor_count: %d", result); 5.627 + } 5.628 + return result; 5.629 +} 5.630 + 5.631 +char * OSContainer::cpu_cpuset_cpus() { 5.632 + GET_CONTAINER_INFO_CPTR(cptr, cpuset, "/cpuset.cpus", 5.633 + "cpuset.cpus is: %s", "%1023s", cpus, 1024); 5.634 + return os::strdup(cpus); 5.635 +} 5.636 + 5.637 +char * OSContainer::cpu_cpuset_memory_nodes() { 5.638 + GET_CONTAINER_INFO_CPTR(cptr, cpuset, "/cpuset.mems", 5.639 + "cpuset.mems is: %s", "%1023s", mems, 1024); 5.640 + return os::strdup(mems); 5.641 +} 5.642 + 5.643 +/* cpu_quota 5.644 + * 5.645 + * Return the number of milliseconds per period 5.646 + * process is guaranteed to run. 5.647 + * 5.648 + * return: 5.649 + * quota time in milliseconds 5.650 + * -1 for no quota 5.651 + * OSCONTAINER_ERROR for not supported 5.652 + */ 5.653 +int OSContainer::cpu_quota() { 5.654 + GET_CONTAINER_INFO(int, cpu, "/cpu.cfs_quota_us", 5.655 + "CPU Quota is: %d", "%d", quota); 5.656 + return quota; 5.657 +} 5.658 + 5.659 +int OSContainer::cpu_period() { 5.660 + GET_CONTAINER_INFO(int, cpu, "/cpu.cfs_period_us", 5.661 + "CPU Period is: %d", "%d", period); 5.662 + return period; 5.663 +} 5.664 + 5.665 +/* cpu_shares 5.666 + * 5.667 + * Return the amount of cpu shares available to the process 5.668 + * 5.669 + * return: 5.670 + * Share number (typically a number relative to 1024) 5.671 + * (2048 typically expresses 2 CPUs worth of processing) 5.672 + * -1 for no share setup 5.673 + * OSCONTAINER_ERROR for not supported 5.674 + */ 5.675 +int OSContainer::cpu_shares() { 5.676 + GET_CONTAINER_INFO(int, cpu, "/cpu.shares", 5.677 + "CPU Shares is: %d", "%d", shares); 5.678 + // Convert 1024 to no shares setup 5.679 + if (shares == 1024) return -1; 5.680 + 5.681 + return shares; 5.682 +} 5.683 +
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/os/linux/vm/osContainer_linux.hpp Fri Jul 27 11:47:10 2018 +0100 6.3 @@ -0,0 +1,68 @@ 6.4 +/* 6.5 + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.7 + * 6.8 + * This code is free software; you can redistribute it and/or modify it 6.9 + * under the terms of the GNU General Public License version 2 only, as 6.10 + * published by the Free Software Foundation. 6.11 + * 6.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 6.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 6.15 + * version 2 for more details (a copy is included in the LICENSE file that 6.16 + * accompanied this code). 6.17 + * 6.18 + * You should have received a copy of the GNU General Public License version 6.19 + * 2 along with this work; if not, write to the Free Software Foundation, 6.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 6.21 + * 6.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 6.23 + * or visit www.oracle.com if you need additional information or have any 6.24 + * questions. 6.25 + * 6.26 + */ 6.27 + 6.28 +#ifndef OS_LINUX_VM_OSCONTAINER_LINUX_HPP 6.29 +#define OS_LINUX_VM_OSCONTAINER_LINUX_HPP 6.30 + 6.31 +#include "utilities/globalDefinitions.hpp" 6.32 +#include "utilities/macros.hpp" 6.33 +#include "memory/allocation.hpp" 6.34 + 6.35 +#define OSCONTAINER_ERROR (-2) 6.36 + 6.37 +class OSContainer: AllStatic { 6.38 + 6.39 + private: 6.40 + static bool _is_initialized; 6.41 + static bool _is_containerized; 6.42 + 6.43 + public: 6.44 + static void init(); 6.45 + static inline bool is_containerized(); 6.46 + static const char * container_type(); 6.47 + 6.48 + static jlong memory_limit_in_bytes(); 6.49 + static jlong memory_and_swap_limit_in_bytes(); 6.50 + static jlong memory_soft_limit_in_bytes(); 6.51 + static jlong memory_usage_in_bytes(); 6.52 + static jlong memory_max_usage_in_bytes(); 6.53 + 6.54 + static int active_processor_count(); 6.55 + 6.56 + static char * cpu_cpuset_cpus(); 6.57 + static char * cpu_cpuset_memory_nodes(); 6.58 + 6.59 + static int cpu_quota(); 6.60 + static int cpu_period(); 6.61 + 6.62 + static int cpu_shares(); 6.63 + 6.64 +}; 6.65 + 6.66 +inline bool OSContainer::is_containerized() { 6.67 + assert(_is_initialized, "OSContainer not initialized"); 6.68 + return _is_containerized; 6.69 +} 6.70 + 6.71 +#endif // OS_LINUX_VM_OSCONTAINER_LINUX_HPP
7.1 --- a/src/os/linux/vm/os_linux.cpp Wed Jul 11 15:59:47 2018 +0100 7.2 +++ b/src/os/linux/vm/os_linux.cpp Fri Jul 27 11:47:10 2018 +0100 7.3 @@ -37,6 +37,7 @@ 7.4 #include "mutex_linux.inline.hpp" 7.5 #include "oops/oop.inline.hpp" 7.6 #include "os_share_linux.hpp" 7.7 +#include "osContainer_linux.hpp" 7.8 #include "prims/jniFastGetField.hpp" 7.9 #include "prims/jvm.h" 7.10 #include "prims/jvm_misc.hpp" 7.11 @@ -179,13 +180,62 @@ 7.12 julong os::Linux::available_memory() { 7.13 // values in struct sysinfo are "unsigned long" 7.14 struct sysinfo si; 7.15 + julong avail_mem; 7.16 + 7.17 + if (OSContainer::is_containerized()) { 7.18 + jlong mem_limit, mem_usage; 7.19 + if ((mem_limit = OSContainer::memory_limit_in_bytes()) < 1) { 7.20 + if (PrintContainerInfo) { 7.21 + tty->print_cr("container memory limit %s: " JLONG_FORMAT ", using host value", 7.22 + mem_limit == OSCONTAINER_ERROR ? "failed" : "unlimited", mem_limit); 7.23 + } 7.24 + } 7.25 + 7.26 + if (mem_limit > 0 && (mem_usage = OSContainer::memory_usage_in_bytes()) < 1) { 7.27 + if (PrintContainerInfo) { 7.28 + tty->print_cr("container memory usage failed: " JLONG_FORMAT ", using host value", mem_usage); 7.29 + } 7.30 + } 7.31 + 7.32 + if (mem_limit > 0 && mem_usage > 0 ) { 7.33 + avail_mem = mem_limit > mem_usage ? (julong)mem_limit - (julong)mem_usage : 0; 7.34 + if (PrintContainerInfo) { 7.35 + tty->print_cr("available container memory: " JULONG_FORMAT, avail_mem); 7.36 + } 7.37 + return avail_mem; 7.38 + } 7.39 + } 7.40 + 7.41 sysinfo(&si); 7.42 - 7.43 - return (julong)si.freeram * si.mem_unit; 7.44 + avail_mem = (julong)si.freeram * si.mem_unit; 7.45 + if (Verbose) { 7.46 + tty->print_cr("available memory: " JULONG_FORMAT, avail_mem); 7.47 + } 7.48 + return avail_mem; 7.49 } 7.50 7.51 julong os::physical_memory() { 7.52 - return Linux::physical_memory(); 7.53 + jlong phys_mem = 0; 7.54 + if (OSContainer::is_containerized()) { 7.55 + jlong mem_limit; 7.56 + if ((mem_limit = OSContainer::memory_limit_in_bytes()) > 0) { 7.57 + if (PrintContainerInfo) { 7.58 + tty->print_cr("total container memory: " JLONG_FORMAT, mem_limit); 7.59 + } 7.60 + return mem_limit; 7.61 + } 7.62 + 7.63 + if (PrintContainerInfo) { 7.64 + tty->print_cr("container memory limit %s: " JLONG_FORMAT ", using host value", 7.65 + mem_limit == OSCONTAINER_ERROR ? "failed" : "unlimited", mem_limit); 7.66 + } 7.67 + } 7.68 + 7.69 + phys_mem = Linux::physical_memory(); 7.70 + if (Verbose) { 7.71 + tty->print_cr("total system memory: " JLONG_FORMAT, phys_mem); 7.72 + } 7.73 + return phys_mem; 7.74 } 7.75 7.76 //////////////////////////////////////////////////////////////////////////////// 7.77 @@ -2114,6 +2164,8 @@ 7.78 os::Posix::print_load_average(st); 7.79 7.80 os::Linux::print_full_memory_info(st); 7.81 + 7.82 + os::Linux::print_container_info(st); 7.83 } 7.84 7.85 // Try to identify popular distros. 7.86 @@ -2179,6 +2231,57 @@ 7.87 st->cr(); 7.88 } 7.89 7.90 +void os::Linux::print_container_info(outputStream* st) { 7.91 +if (!OSContainer::is_containerized()) { 7.92 + return; 7.93 + } 7.94 + 7.95 + st->print("container (cgroup) information:\n"); 7.96 + 7.97 + const char *p_ct = OSContainer::container_type(); 7.98 + st->print("container_type: %s\n", p_ct != NULL ? p_ct : "failed"); 7.99 + 7.100 + char *p = OSContainer::cpu_cpuset_cpus(); 7.101 + st->print("cpu_cpuset_cpus: %s\n", p != NULL ? p : "failed"); 7.102 + free(p); 7.103 + 7.104 + p = OSContainer::cpu_cpuset_memory_nodes(); 7.105 + st->print("cpu_memory_nodes: %s\n", p != NULL ? p : "failed"); 7.106 + free(p); 7.107 + 7.108 + int i = OSContainer::active_processor_count(); 7.109 + if (i > 0) { 7.110 + st->print("active_processor_count: %d\n", i); 7.111 + } else { 7.112 + st->print("active_processor_count: failed\n"); 7.113 + } 7.114 + 7.115 + i = OSContainer::cpu_quota(); 7.116 + st->print("cpu_quota: %d\n", i); 7.117 + 7.118 + i = OSContainer::cpu_period(); 7.119 + st->print("cpu_period: %d\n", i); 7.120 + 7.121 + i = OSContainer::cpu_shares(); 7.122 + st->print("cpu_shares: %d\n", i); 7.123 + 7.124 + jlong j = OSContainer::memory_limit_in_bytes(); 7.125 + st->print("memory_limit_in_bytes: " JLONG_FORMAT "\n", j); 7.126 + 7.127 + j = OSContainer::memory_and_swap_limit_in_bytes(); 7.128 + st->print("memory_and_swap_limit_in_bytes: " JLONG_FORMAT "\n", j); 7.129 + 7.130 + j = OSContainer::memory_soft_limit_in_bytes(); 7.131 + st->print("memory_soft_limit_in_bytes: " JLONG_FORMAT "\n", j); 7.132 + 7.133 + j = OSContainer::OSContainer::memory_usage_in_bytes(); 7.134 + st->print("memory_usage_in_bytes: " JLONG_FORMAT "\n", j); 7.135 + 7.136 + j = OSContainer::OSContainer::memory_max_usage_in_bytes(); 7.137 + st->print("memory_max_usage_in_bytes: " JLONG_FORMAT "\n", j); 7.138 + st->cr(); 7.139 +} 7.140 + 7.141 void os::print_memory_info(outputStream* st) { 7.142 7.143 st->print("Memory:"); 7.144 @@ -4951,6 +5054,10 @@ 7.145 } 7.146 } 7.147 7.148 +void os::pd_init_container_support() { 7.149 + OSContainer::init(); 7.150 +} 7.151 + 7.152 // this is called _after_ the global arguments have been parsed 7.153 jint os::init_2(void) 7.154 { 7.155 @@ -5131,7 +5238,7 @@ 7.156 // sched_getaffinity gives an accurate answer as it accounts for cpusets. 7.157 // If anything goes wrong we fallback to returning the number of online 7.158 // processors - which can be greater than the number available to the process. 7.159 -int os::active_processor_count() { 7.160 +int os::Linux::active_processor_count() { 7.161 cpu_set_t cpus; // can represent at most 1024 (CPU_SETSIZE) processors 7.162 int cpus_size = sizeof(cpu_set_t); 7.163 int cpu_count = 0; 7.164 @@ -5149,10 +5256,48 @@ 7.165 "which may exceed available processors", strerror(errno), cpu_count); 7.166 } 7.167 7.168 - assert(cpu_count > 0 && cpu_count <= processor_count(), "sanity check"); 7.169 + assert(cpu_count > 0 && cpu_count <= os::processor_count(), "sanity check"); 7.170 return cpu_count; 7.171 } 7.172 7.173 +// Determine the active processor count from one of 7.174 +// three different sources: 7.175 +// 7.176 +// 1. User option -XX:ActiveProcessorCount 7.177 +// 2. kernel os calls (sched_getaffinity or sysconf(_SC_NPROCESSORS_ONLN) 7.178 +// 3. extracted from cgroup cpu subsystem (shares and quotas) 7.179 +// 7.180 +// Option 1, if specified, will always override. 7.181 +// If the cgroup subsystem is active and configured, we 7.182 +// will return the min of the cgroup and option 2 results. 7.183 +// This is required since tools, such as numactl, that 7.184 +// alter cpu affinity do not update cgroup subsystem 7.185 +// cpuset configuration files. 7.186 +int os::active_processor_count() { 7.187 + // User has overridden the number of active processors 7.188 + if (ActiveProcessorCount > 0) { 7.189 + if (PrintActiveCpus) { 7.190 + tty->print_cr("active_processor_count: " 7.191 + "active processor count set by user : %d", 7.192 + ActiveProcessorCount); 7.193 + } 7.194 + return ActiveProcessorCount; 7.195 + } 7.196 + 7.197 + int active_cpus; 7.198 + if (OSContainer::is_containerized()) { 7.199 + active_cpus = OSContainer::active_processor_count(); 7.200 + if (PrintActiveCpus) { 7.201 + tty->print_cr("active_processor_count: determined by OSContainer: %d", 7.202 + active_cpus); 7.203 + } 7.204 + } else { 7.205 + active_cpus = os::Linux::active_processor_count(); 7.206 + } 7.207 + 7.208 + return active_cpus; 7.209 +} 7.210 + 7.211 void os::set_native_thread_name(const char *name) { 7.212 // Not yet implemented. 7.213 return;
8.1 --- a/src/os/linux/vm/os_linux.hpp Wed Jul 11 15:59:47 2018 +0100 8.2 +++ b/src/os/linux/vm/os_linux.hpp Fri Jul 27 11:47:10 2018 +0100 8.3 @@ -35,6 +35,7 @@ 8.4 8.5 class Linux { 8.6 friend class os; 8.7 + friend class OSContainer; 8.8 friend class TestReserveMemorySpecial; 8.9 8.10 // For signal-chaining 8.11 @@ -79,6 +80,9 @@ 8.12 8.13 static julong available_memory(); 8.14 static julong physical_memory() { return _physical_memory; } 8.15 + static void set_physical_memory(julong phys_mem) { _physical_memory = phys_mem; } 8.16 + static int active_processor_count(); 8.17 + 8.18 static void initialize_system_info(); 8.19 8.20 static int commit_memory_impl(char* addr, size_t bytes, bool exec); 8.21 @@ -116,6 +120,7 @@ 8.22 static bool release_memory_special_huge_tlbfs(char* base, size_t bytes); 8.23 8.24 static void print_full_memory_info(outputStream* st); 8.25 + static void print_container_info(outputStream* st); 8.26 static void print_distro_info(outputStream* st); 8.27 static void print_libversion_info(outputStream* st); 8.28
9.1 --- a/src/os/solaris/vm/os_solaris.cpp Wed Jul 11 15:59:47 2018 +0100 9.2 +++ b/src/os/solaris/vm/os_solaris.cpp Fri Jul 27 11:47:10 2018 +0100 9.3 @@ -357,6 +357,16 @@ 9.4 } 9.5 9.6 int os::active_processor_count() { 9.7 + // User has overridden the number of active processors 9.8 + if (ActiveProcessorCount > 0) { 9.9 + if (Verbose) { 9.10 + tty->print_cr("active_processor_count: " 9.11 + "active processor count set by user : %d", 9.12 + ActiveProcessorCount); 9.13 + } 9.14 + return ActiveProcessorCount; 9.15 + } 9.16 + 9.17 int online_cpus = sysconf(_SC_NPROCESSORS_ONLN); 9.18 pid_t pid = getpid(); 9.19 psetid_t pset = PS_NONE;
10.1 --- a/src/os/windows/vm/os_windows.cpp Wed Jul 11 15:59:47 2018 +0100 10.2 +++ b/src/os/windows/vm/os_windows.cpp Fri Jul 27 11:47:10 2018 +0100 10.3 @@ -716,6 +716,16 @@ 10.4 #endif 10.5 10.6 int os::active_processor_count() { 10.7 + // User has overridden the number of active processors 10.8 + if (ActiveProcessorCount > 0) { 10.9 + if (PrintActiveCpus) { 10.10 + tty->print_cr("active_processor_count: " 10.11 + "active processor count set by user : %d", 10.12 + ActiveProcessorCount); 10.13 + } 10.14 + return ActiveProcessorCount; 10.15 + } 10.16 + 10.17 DWORD_PTR lpProcessAffinityMask = 0; 10.18 DWORD_PTR lpSystemAffinityMask = 0; 10.19 int proc_count = processor_count();
11.1 --- a/src/share/vm/runtime/arguments.cpp Wed Jul 11 15:59:47 2018 +0100 11.2 +++ b/src/share/vm/runtime/arguments.cpp Fri Jul 27 11:47:10 2018 +0100 11.3 @@ -1,5 +1,5 @@ 11.4 /* 11.5 - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. 11.6 + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. 11.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 11.8 * 11.9 * This code is free software; you can redistribute it and/or modify it 11.10 @@ -1801,20 +1801,34 @@ 11.11 } 11.12 } 11.13 11.14 + // Convert Fraction to Precentage values 11.15 + if (FLAG_IS_DEFAULT(MaxRAMPercentage) && 11.16 + !FLAG_IS_DEFAULT(MaxRAMFraction)) 11.17 + MaxRAMPercentage = 100.0 / MaxRAMFraction; 11.18 + 11.19 + if (FLAG_IS_DEFAULT(MinRAMPercentage) && 11.20 + !FLAG_IS_DEFAULT(MinRAMFraction)) 11.21 + MinRAMPercentage = 100.0 / MinRAMFraction; 11.22 + 11.23 + if (FLAG_IS_DEFAULT(InitialRAMPercentage) && 11.24 + !FLAG_IS_DEFAULT(InitialRAMFraction)) 11.25 + InitialRAMPercentage = 100.0 / InitialRAMFraction; 11.26 + 11.27 // If the maximum heap size has not been set with -Xmx, 11.28 // then set it as fraction of the size of physical memory, 11.29 // respecting the maximum and minimum sizes of the heap. 11.30 if (FLAG_IS_DEFAULT(MaxHeapSize)) { 11.31 - julong reasonable_max = phys_mem / MaxRAMFraction; 11.32 - 11.33 - if (phys_mem <= MaxHeapSize * MinRAMFraction) { 11.34 + julong reasonable_max = (julong)((phys_mem * MaxRAMPercentage) / 100); 11.35 + const julong reasonable_min = (julong)((phys_mem * MinRAMPercentage) / 100); 11.36 + if (reasonable_min < MaxHeapSize) { 11.37 // Small physical memory, so use a minimum fraction of it for the heap 11.38 - reasonable_max = phys_mem / MinRAMFraction; 11.39 + reasonable_max = reasonable_min; 11.40 } else { 11.41 // Not-small physical memory, so require a heap at least 11.42 // as large as MaxHeapSize 11.43 reasonable_max = MAX2(reasonable_max, (julong)MaxHeapSize); 11.44 } 11.45 + 11.46 if (!FLAG_IS_DEFAULT(ErgoHeapSizeLimit) && ErgoHeapSizeLimit != 0) { 11.47 // Limit the heap size to ErgoHeapSizeLimit 11.48 reasonable_max = MIN2(reasonable_max, (julong)ErgoHeapSizeLimit); 11.49 @@ -1856,7 +1870,7 @@ 11.50 reasonable_minimum = limit_by_allocatable_memory(reasonable_minimum); 11.51 11.52 if (InitialHeapSize == 0) { 11.53 - julong reasonable_initial = phys_mem / InitialRAMFraction; 11.54 + julong reasonable_initial = (julong)((phys_mem * InitialRAMPercentage) / 100); 11.55 11.56 reasonable_initial = MAX3(reasonable_initial, reasonable_minimum, (julong)min_heap_size()); 11.57 reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize); 11.58 @@ -1881,6 +1895,94 @@ 11.59 } 11.60 } 11.61 11.62 +// This option inspects the machine and attempts to set various 11.63 +// parameters to be optimal for long-running, memory allocation 11.64 +// intensive jobs. It is intended for machines with large 11.65 +// amounts of cpu and memory. 11.66 +jint Arguments::set_aggressive_heap_flags() { 11.67 + // initHeapSize is needed since _initial_heap_size is 4 bytes on a 32 bit 11.68 + // VM, but we may not be able to represent the total physical memory 11.69 + // available (like having 8gb of memory on a box but using a 32bit VM). 11.70 + // Thus, we need to make sure we're using a julong for intermediate 11.71 + // calculations. 11.72 + julong initHeapSize; 11.73 + julong total_memory = os::physical_memory(); 11.74 + 11.75 + if (total_memory < (julong) 256 * M) { 11.76 + jio_fprintf(defaultStream::error_stream(), 11.77 + "You need at least 256mb of memory to use -XX:+AggressiveHeap\n"); 11.78 + vm_exit(1); 11.79 + } 11.80 + 11.81 + // The heap size is half of available memory, or (at most) 11.82 + // all of possible memory less 160mb (leaving room for the OS 11.83 + // when using ISM). This is the maximum; because adaptive sizing 11.84 + // is turned on below, the actual space used may be smaller. 11.85 + 11.86 + initHeapSize = MIN2(total_memory / (julong) 2, 11.87 + total_memory - (julong) 160 * M); 11.88 + 11.89 + initHeapSize = limit_by_allocatable_memory(initHeapSize); 11.90 + 11.91 + if (FLAG_IS_DEFAULT(MaxHeapSize)) { 11.92 + FLAG_SET_CMDLINE(uintx, MaxHeapSize, initHeapSize); 11.93 + FLAG_SET_CMDLINE(uintx, InitialHeapSize, initHeapSize); 11.94 + // Currently the minimum size and the initial heap sizes are the same. 11.95 + set_min_heap_size(initHeapSize); 11.96 + } 11.97 + if (FLAG_IS_DEFAULT(NewSize)) { 11.98 + // Make the young generation 3/8ths of the total heap. 11.99 + FLAG_SET_CMDLINE(uintx, NewSize, 11.100 + ((julong) MaxHeapSize / (julong) 8) * (julong) 3); 11.101 + FLAG_SET_CMDLINE(uintx, MaxNewSize, NewSize); 11.102 + } 11.103 + 11.104 +#ifndef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD. 11.105 + FLAG_SET_DEFAULT(UseLargePages, true); 11.106 +#endif 11.107 + 11.108 + // Increase some data structure sizes for efficiency 11.109 + FLAG_SET_CMDLINE(uintx, BaseFootPrintEstimate, MaxHeapSize); 11.110 + FLAG_SET_CMDLINE(bool, ResizeTLAB, false); 11.111 + FLAG_SET_CMDLINE(uintx, TLABSize, 256 * K); 11.112 + 11.113 + // See the OldPLABSize comment below, but replace 'after promotion' 11.114 + // with 'after copying'. YoungPLABSize is the size of the survivor 11.115 + // space per-gc-thread buffers. The default is 4kw. 11.116 + FLAG_SET_CMDLINE(uintx, YoungPLABSize, 256 * K); // Note: this is in words 11.117 + 11.118 + // OldPLABSize is the size of the buffers in the old gen that 11.119 + // UseParallelGC uses to promote live data that doesn't fit in the 11.120 + // survivor spaces. At any given time, there's one for each gc thread. 11.121 + // The default size is 1kw. These buffers are rarely used, since the 11.122 + // survivor spaces are usually big enough. For specjbb, however, there 11.123 + // are occasions when there's lots of live data in the young gen 11.124 + // and we end up promoting some of it. We don't have a definite 11.125 + // explanation for why bumping OldPLABSize helps, but the theory 11.126 + // is that a bigger PLAB results in retaining something like the 11.127 + // original allocation order after promotion, which improves mutator 11.128 + // locality. A minor effect may be that larger PLABs reduce the 11.129 + // number of PLAB allocation events during gc. The value of 8kw 11.130 + // was arrived at by experimenting with specjbb. 11.131 + FLAG_SET_CMDLINE(uintx, OldPLABSize, 8 * K); // Note: this is in words 11.132 + 11.133 + // Enable parallel GC and adaptive generation sizing 11.134 + FLAG_SET_CMDLINE(bool, UseParallelGC, true); 11.135 + 11.136 + // Encourage steady state memory management 11.137 + FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100); 11.138 + 11.139 + // This appears to improve mutator locality 11.140 + FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false); 11.141 + 11.142 + // Get around early Solaris scheduling bug 11.143 + // (affinity vs other jobs on system) 11.144 + // but disallow DR and offlining (5008695). 11.145 + FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true); 11.146 + 11.147 + return JNI_OK; 11.148 +} 11.149 + 11.150 // This must be called after ergonomics because we want bytecode rewriting 11.151 // if the server compiler is used, or if UseSharedSpaces is disabled. 11.152 void Arguments::set_bytecode_flags() { 11.153 @@ -2644,6 +2746,14 @@ 11.154 return result; 11.155 } 11.156 11.157 + // We need to ensure processor and memory resources have been properly 11.158 + // configured - which may rely on arguments we just processed - before 11.159 + // doing the final argument processing. Any argument processing that 11.160 + // needs to know about processor and memory resources must occur after 11.161 + // this point. 11.162 + 11.163 + os::init_container_support(); 11.164 + 11.165 // Do final processing now that all arguments have been parsed 11.166 result = finalize_vm_init_args(&scp, scp_assembly_required); 11.167 if (result != JNI_OK) { 11.168 @@ -3117,94 +3227,6 @@ 11.169 _exit_hook = CAST_TO_FN_PTR(exit_hook_t, option->extraInfo); 11.170 } else if (match_option(option, "abort", &tail)) { 11.171 _abort_hook = CAST_TO_FN_PTR(abort_hook_t, option->extraInfo); 11.172 - // -XX:+AggressiveHeap 11.173 - } else if (match_option(option, "-XX:+AggressiveHeap", &tail)) { 11.174 - 11.175 - // This option inspects the machine and attempts to set various 11.176 - // parameters to be optimal for long-running, memory allocation 11.177 - // intensive jobs. It is intended for machines with large 11.178 - // amounts of cpu and memory. 11.179 - 11.180 - // initHeapSize is needed since _initial_heap_size is 4 bytes on a 32 bit 11.181 - // VM, but we may not be able to represent the total physical memory 11.182 - // available (like having 8gb of memory on a box but using a 32bit VM). 11.183 - // Thus, we need to make sure we're using a julong for intermediate 11.184 - // calculations. 11.185 - julong initHeapSize; 11.186 - julong total_memory = os::physical_memory(); 11.187 - 11.188 - if (total_memory < (julong)256*M) { 11.189 - jio_fprintf(defaultStream::error_stream(), 11.190 - "You need at least 256mb of memory to use -XX:+AggressiveHeap\n"); 11.191 - vm_exit(1); 11.192 - } 11.193 - 11.194 - // The heap size is half of available memory, or (at most) 11.195 - // all of possible memory less 160mb (leaving room for the OS 11.196 - // when using ISM). This is the maximum; because adaptive sizing 11.197 - // is turned on below, the actual space used may be smaller. 11.198 - 11.199 - initHeapSize = MIN2(total_memory / (julong)2, 11.200 - total_memory - (julong)160*M); 11.201 - 11.202 - initHeapSize = limit_by_allocatable_memory(initHeapSize); 11.203 - 11.204 - if (FLAG_IS_DEFAULT(MaxHeapSize)) { 11.205 - FLAG_SET_CMDLINE(uintx, MaxHeapSize, initHeapSize); 11.206 - FLAG_SET_CMDLINE(uintx, InitialHeapSize, initHeapSize); 11.207 - // Currently the minimum size and the initial heap sizes are the same. 11.208 - set_min_heap_size(initHeapSize); 11.209 - } 11.210 - if (FLAG_IS_DEFAULT(NewSize)) { 11.211 - // Make the young generation 3/8ths of the total heap. 11.212 - FLAG_SET_CMDLINE(uintx, NewSize, 11.213 - ((julong)MaxHeapSize / (julong)8) * (julong)3); 11.214 - FLAG_SET_CMDLINE(uintx, MaxNewSize, NewSize); 11.215 - } 11.216 - 11.217 -#ifndef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD. 11.218 - FLAG_SET_DEFAULT(UseLargePages, true); 11.219 -#endif 11.220 - 11.221 - // Increase some data structure sizes for efficiency 11.222 - FLAG_SET_CMDLINE(uintx, BaseFootPrintEstimate, MaxHeapSize); 11.223 - FLAG_SET_CMDLINE(bool, ResizeTLAB, false); 11.224 - FLAG_SET_CMDLINE(uintx, TLABSize, 256*K); 11.225 - 11.226 - // See the OldPLABSize comment below, but replace 'after promotion' 11.227 - // with 'after copying'. YoungPLABSize is the size of the survivor 11.228 - // space per-gc-thread buffers. The default is 4kw. 11.229 - FLAG_SET_CMDLINE(uintx, YoungPLABSize, 256*K); // Note: this is in words 11.230 - 11.231 - // OldPLABSize is the size of the buffers in the old gen that 11.232 - // UseParallelGC uses to promote live data that doesn't fit in the 11.233 - // survivor spaces. At any given time, there's one for each gc thread. 11.234 - // The default size is 1kw. These buffers are rarely used, since the 11.235 - // survivor spaces are usually big enough. For specjbb, however, there 11.236 - // are occasions when there's lots of live data in the young gen 11.237 - // and we end up promoting some of it. We don't have a definite 11.238 - // explanation for why bumping OldPLABSize helps, but the theory 11.239 - // is that a bigger PLAB results in retaining something like the 11.240 - // original allocation order after promotion, which improves mutator 11.241 - // locality. A minor effect may be that larger PLABs reduce the 11.242 - // number of PLAB allocation events during gc. The value of 8kw 11.243 - // was arrived at by experimenting with specjbb. 11.244 - FLAG_SET_CMDLINE(uintx, OldPLABSize, 8*K); // Note: this is in words 11.245 - 11.246 - // Enable parallel GC and adaptive generation sizing 11.247 - FLAG_SET_CMDLINE(bool, UseParallelGC, true); 11.248 - 11.249 - // Encourage steady state memory management 11.250 - FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100); 11.251 - 11.252 - // This appears to improve mutator locality 11.253 - FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false); 11.254 - 11.255 - // Get around early Solaris scheduling bug 11.256 - // (affinity vs other jobs on system) 11.257 - // but disallow DR and offlining (5008695). 11.258 - FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true); 11.259 - 11.260 } else if (match_option(option, "-XX:+NeverTenure", &tail)) { 11.261 // The last option must always win. 11.262 FLAG_SET_CMDLINE(bool, AlwaysTenure, false); 11.263 @@ -3605,6 +3627,15 @@ 11.264 return JNI_ERR; 11.265 } 11.266 11.267 + // This must be done after all arguments have been processed 11.268 + // and the container support has been initialized since AggressiveHeap 11.269 + // relies on the amount of total memory available. 11.270 + if (AggressiveHeap) { 11.271 + jint result = set_aggressive_heap_flags(); 11.272 + if (result != JNI_OK) { 11.273 + return result; 11.274 + } 11.275 + } 11.276 // This must be done after all arguments have been processed. 11.277 // java_compiler() true means set to "NONE" or empty. 11.278 if (java_compiler() && !xdebug_mode()) {
12.1 --- a/src/share/vm/runtime/arguments.hpp Wed Jul 11 15:59:47 2018 +0100 12.2 +++ b/src/share/vm/runtime/arguments.hpp Fri Jul 27 11:47:10 2018 +0100 12.3 @@ -1,5 +1,5 @@ 12.4 /* 12.5 - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 12.6 + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. 12.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.8 * 12.9 * This code is free software; you can redistribute it and/or modify it 12.10 @@ -365,6 +365,8 @@ 12.11 // Aggressive optimization flags. 12.12 static void set_aggressive_opts_flags(); 12.13 12.14 + static jint set_aggressive_heap_flags(); 12.15 + 12.16 // Argument parsing 12.17 static void do_pd_flag_adjustments(); 12.18 static bool parse_argument(const char* arg, Flag::Flags origin);
13.1 --- a/src/share/vm/runtime/globals.hpp Wed Jul 11 15:59:47 2018 +0100 13.2 +++ b/src/share/vm/runtime/globals.hpp Fri Jul 27 11:47:10 2018 +0100 13.3 @@ -2064,13 +2064,23 @@ 13.4 product_pd(uint64_t, MaxRAM, \ 13.5 "Real memory size (in bytes) used to set maximum heap size") \ 13.6 \ 13.7 + product(bool, AggressiveHeap, false, \ 13.8 + "Optimize heap options for long-running memory intensive apps") \ 13.9 + \ 13.10 product(uintx, ErgoHeapSizeLimit, 0, \ 13.11 "Maximum ergonomically set heap size (in bytes); zero means use " \ 13.12 - "MaxRAM / MaxRAMFraction") \ 13.13 + "MaxRAM * MaxRAMPercentage / 100") \ 13.14 \ 13.15 experimental(bool, UseCGroupMemoryLimitForHeap, false, \ 13.16 "Use CGroup memory limit as physical memory limit for heap " \ 13.17 - "sizing") \ 13.18 + "sizing" \ 13.19 + "Deprecated, replaced by container support") \ 13.20 + \ 13.21 + diagnostic(bool, PrintContainerInfo, false, \ 13.22 + "Print container related information") \ 13.23 + \ 13.24 + diagnostic(bool, PrintActiveCpus, false, \ 13.25 + "Print the number of CPUs detected in os::active_processor_count") \ 13.26 \ 13.27 product(uintx, MaxRAMFraction, 4, \ 13.28 "Maximum fraction (1/n) of real memory used for maximum heap " \ 13.29 @@ -2087,6 +2097,19 @@ 13.30 product(uintx, InitialRAMFraction, 64, \ 13.31 "Fraction (1/n) of real memory used for initial heap size") \ 13.32 \ 13.33 + product(double, MaxRAMPercentage, 25.0, \ 13.34 + "Maximum percentage of real memory used for maximum heap size") \ 13.35 + \ 13.36 + product(double, MinRAMPercentage, 50.0, \ 13.37 + "Minimum percentage of real memory used for maximum heap" \ 13.38 + "size on systems with small physical memory size") \ 13.39 + \ 13.40 + product(double, InitialRAMPercentage, 1.5625, \ 13.41 + "Percentage of real memory used for initial heap size") \ 13.42 + \ 13.43 + product(intx, ActiveProcessorCount, -1, \ 13.44 + "Specify the CPU count the VM should use and report as active") \ 13.45 + \ 13.46 develop(uintx, MaxVirtMemFraction, 2, \ 13.47 "Maximum fraction (1/n) of virtual memory used for ergonomically "\ 13.48 "determining maximum heap size") \
14.1 --- a/src/share/vm/runtime/os.hpp Wed Jul 11 15:59:47 2018 +0100 14.2 +++ b/src/share/vm/runtime/os.hpp Fri Jul 27 11:47:10 2018 +0100 14.3 @@ -152,8 +152,16 @@ 14.4 static size_t page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned); 14.5 14.6 static void initialize_initial_active_processor_count(); 14.7 + 14.8 + LINUX_ONLY(static void pd_init_container_support();) 14.9 + 14.10 public: 14.11 static void init(void); // Called before command line parsing 14.12 + 14.13 + static void init_container_support() { // Called during command line parsing. 14.14 + LINUX_ONLY(pd_init_container_support();) 14.15 + } 14.16 + 14.17 static void init_before_ergo(void); // Called after command line parsing 14.18 // before VM ergonomics processing. 14.19 static jint init_2(void); // Called after command line parsing
15.1 --- a/src/share/vm/runtime/thread.cpp Wed Jul 11 15:59:47 2018 +0100 15.2 +++ b/src/share/vm/runtime/thread.cpp Fri Jul 27 11:47:10 2018 +0100 15.3 @@ -3335,6 +3335,7 @@ 15.4 Arguments::init_version_specific_system_properties(); 15.5 15.6 // Parse arguments 15.7 + // Note: this internally calls os::init_container_support() 15.8 jint parse_result = Arguments::parse(args); 15.9 if (parse_result != JNI_OK) return parse_result; 15.10