1 /* 2 * Copyright (c) 2003, 2020, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.management.internal; 27 28 import jdk.internal.platform.Metrics; 29 import sun.management.BaseOperatingSystemImpl; 30 import sun.management.VMManagement; 31 32 import java.util.concurrent.TimeUnit; 33 /** 34 * Implementation class for the operating system. 35 * Standard and committed hotspot-specific metrics if any. 36 * 37 * ManagementFactory.getOperatingSystemMXBean() returns an instance 38 * of this class. 39 */ 40 class OperatingSystemImpl extends BaseOperatingSystemImpl 41 implements com.sun.management.UnixOperatingSystemMXBean { 42 43 private static final int MAX_ATTEMPTS_NUMBER = 10; 44 private final Metrics containerMetrics; 45 46 OperatingSystemImpl(VMManagement vm) { 47 super(vm); 48 this.containerMetrics = jdk.internal.platform.Container.metrics(); 49 } 50 51 public long getCommittedVirtualMemorySize() { 52 return getCommittedVirtualMemorySize0(); 53 } 54 55 public long getTotalSwapSpaceSize() { 56 if (containerMetrics != null) { 57 long limit = containerMetrics.getMemoryAndSwapLimit(); 58 // The memory limit metrics is not available if JVM runs on Linux host (not in a docker container) 59 // or if a docker container was started without specifying a memory limit (without '--memory=' 60 // Docker option). In latter case there is no limit on how much memory the container can use and 61 // it can use as much memory as the host's OS allows. 62 long memLimit = containerMetrics.getMemoryLimit(); 63 if (limit >= 0 && memLimit >= 0) { 64 // we see a limit == 0 on some machines where "kernel does not support swap limit capabilities" 65 return (limit < memLimit) ? 0 : limit - memLimit; 66 } 67 } 68 return getTotalSwapSpaceSize0(); 69 } 70 71 public long getFreeSwapSpaceSize() { 72 if (containerMetrics != null) { 73 long memSwapLimit = containerMetrics.getMemoryAndSwapLimit(); 74 long memLimit = containerMetrics.getMemoryLimit(); 75 if (memSwapLimit >= 0 && memLimit >= 0) { 76 for (int attempt = 0; attempt < MAX_ATTEMPTS_NUMBER; attempt++) { 77 long memSwapUsage = containerMetrics.getMemoryAndSwapUsage(); 78 long memUsage = containerMetrics.getMemoryUsage(); 79 if (memSwapUsage > 0 && memUsage > 0) { 80 // We read "memory usage" and "memory and swap usage" not atomically, 81 // and it's possible to get the negative value when subtracting these two. 82 // If this happens just retry the loop for a few iterations. 83 if ((memSwapUsage - memUsage) >= 0) { 84 return memSwapLimit - memLimit - (memSwapUsage - memUsage); 85 } 86 } 87 } 88 } 89 } 90 return getFreeSwapSpaceSize0(); 91 } 92 93 public long getProcessCpuTime() { 94 return getProcessCpuTime0(); 95 } 96 97 public long getFreeMemorySize() { 98 if (containerMetrics != null) { 99 long usage = containerMetrics.getMemoryUsage(); 100 long limit = containerMetrics.getMemoryLimit(); 101 if (usage > 0 && limit >= 0) { 102 return limit - usage; 103 } 104 } 105 return getFreeMemorySize0(); 106 } 107 108 public long getTotalMemorySize() { 109 if (containerMetrics != null) { 110 long limit = containerMetrics.getMemoryLimit(); 111 if (limit >= 0) { 112 return limit; 113 } 114 } 115 return getTotalMemorySize0(); 116 } 117 118 public long getOpenFileDescriptorCount() { 119 return getOpenFileDescriptorCount0(); 120 } 121 122 public long getMaxFileDescriptorCount() { 123 return getMaxFileDescriptorCount0(); 124 } 125 126 public double getCpuLoad() { 127 if (containerMetrics != null) { 128 long quota = containerMetrics.getCpuQuota(); 129 if (quota > 0) { 130 long periodLength = containerMetrics.getCpuPeriod(); 131 long numPeriods = containerMetrics.getCpuNumPeriods(); 132 long usageNanos = containerMetrics.getCpuUsage(); 133 if (periodLength > 0 && numPeriods > 0 && usageNanos > 0) { 134 long elapsedNanos = TimeUnit.MICROSECONDS.toNanos(periodLength * numPeriods); 135 double systemLoad = (double) usageNanos / elapsedNanos; 136 // Ensure the return value is in the range 0.0 -> 1.0 137 systemLoad = Math.max(0.0, systemLoad); 138 systemLoad = Math.min(1.0, systemLoad); 139 return systemLoad; 140 } 141 return -1; 142 } else { 143 // If CPU quotas are not active then find the average system load for 144 // all online CPUs that are allowed to run this container. 145 146 // If the cpuset is the same as the host's one there is no need to iterate over each CPU 147 if (isCpuSetSameAsHostCpuSet()) { 148 return getCpuLoad0(); 149 } else { 150 int[] cpuSet = containerMetrics.getEffectiveCpuSetCpus(); 151 if (cpuSet != null && cpuSet.length > 0) { 152 double systemLoad = 0.0; 153 for (int cpu : cpuSet) { 154 double cpuLoad = getSingleCpuLoad0(cpu); 155 if (cpuLoad < 0) { 156 return -1; 157 } 158 systemLoad += cpuLoad; 159 } 160 return systemLoad / cpuSet.length; 161 } 162 return -1; 163 } 164 } 165 } 166 return getCpuLoad0(); 167 } 168 169 public double getProcessCpuLoad() { 170 return getProcessCpuLoad0(); 171 } 172 173 private boolean isCpuSetSameAsHostCpuSet() { 174 if (containerMetrics != null) { 175 return containerMetrics.getCpuSetCpus().length == getHostConfiguredCpuCount0(); 176 } 177 return false; 178 } 179 180 /* native methods */ 181 private native long getCommittedVirtualMemorySize0(); 182 private native long getFreeMemorySize0(); 183 private native long getFreeSwapSpaceSize0(); 184 private native long getMaxFileDescriptorCount0(); 185 private native long getOpenFileDescriptorCount0(); 186 private native long getProcessCpuTime0(); 187 private native double getProcessCpuLoad0(); 188 private native double getCpuLoad0(); 189 private native long getTotalMemorySize0(); 190 private native long getTotalSwapSpaceSize0(); 191 private native double getSingleCpuLoad0(int cpuNum); 192 private native int getHostConfiguredCpuCount0(); 193 194 static { 195 initialize0(); 196 } 197 198 private static native void initialize0(); 199 }