@@ -42,6 +42,8 @@ class OperatingSystemImpl extends BaseOperatingSystemImpl
4242
4343 private static final int MAX_ATTEMPTS_NUMBER = 10 ;
4444 private final Metrics containerMetrics ;
45+ private long usageTicks = 0 ; // used for cpu load calculation
46+ private long totalTicks = 0 ; // used for cpu load calculation
4547
4648 OperatingSystemImpl (VMManagement vm ) {
4749 super (vm );
@@ -133,24 +135,56 @@ public long getMaxFileDescriptorCount() {
133135 return getMaxFileDescriptorCount0 ();
134136 }
135137
138+ private double getUsageDividesTotal (long usageTicks , long totalTicks ) {
139+ // If cpu quota or cpu shares are in effect calculate the cpu load
140+ // based on the following formula (similar to how
141+ // getCpuLoad0() is being calculated):
142+ //
143+ // | usageTicks - usageTicks' |
144+ // ------------------------------
145+ // | totalTicks - totalTicks' |
146+ //
147+ // where usageTicks' and totalTicks' are historical values
148+ // retrieved via an earlier call of this method.
149+ //
150+ // Total ticks should be scaled to the container effective number
151+ // of cpus, if cpu shares are in effect.
152+ if (usageTicks < 0 || totalTicks <= 0 ) {
153+ return -1 ;
154+ }
155+ long distance = usageTicks - this .usageTicks ;
156+ this .usageTicks = usageTicks ;
157+ long totalDistance = totalTicks - this .totalTicks ;
158+ this .totalTicks = totalTicks ;
159+
160+ double systemLoad = 0.0 ;
161+ if (distance > 0 && totalDistance > 0 ) {
162+ systemLoad = ((double )distance ) / totalDistance ;
163+ }
164+ // Ensure the return value is in the range 0.0 -> 1.0
165+ systemLoad = Math .max (0.0 , systemLoad );
166+ systemLoad = Math .min (1.0 , systemLoad );
167+ return systemLoad ;
168+ }
169+
136170 public double getSystemCpuLoad () {
137171 if (containerMetrics != null ) {
138172 long quota = containerMetrics .getCpuQuota ();
173+ long share = containerMetrics .getCpuShares ();
174+ long usageNanos = containerMetrics .getCpuUsage ();
139175 if (quota > 0 ) {
140- long periodLength = containerMetrics .getCpuPeriod ();
141176 long numPeriods = containerMetrics .getCpuNumPeriods ();
142- long usageNanos = containerMetrics .getCpuUsage ();
143- if (periodLength > 0 && numPeriods > 0 && usageNanos > 0 ) {
144- long elapsedNanos = TimeUnit .MICROSECONDS .toNanos (periodLength * numPeriods );
145- double systemLoad = (double ) usageNanos / elapsedNanos ;
146- // Ensure the return value is in the range 0.0 -> 1.0
147- systemLoad = Math .max (0.0 , systemLoad );
148- systemLoad = Math .min (1.0 , systemLoad );
149- return systemLoad ;
150- }
151- return -1 ;
177+ long quotaNanos = TimeUnit .MICROSECONDS .toNanos (quota * numPeriods );
178+ return getUsageDividesTotal (usageNanos , quotaNanos );
179+ } else if (share > 0 ) {
180+ long hostTicks = getHostTotalCpuTicks0 ();
181+ int totalCPUs = getHostOnlineCpuCount0 ();
182+ int containerCPUs = getAvailableProcessors ();
183+ // scale the total host load to the actual container cpus
184+ hostTicks = hostTicks * containerCPUs / totalCPUs ;
185+ return getUsageDividesTotal (usageNanos , hostTicks );
152186 } else {
153- // If CPU quotas are not active then find the average system load for
187+ // If CPU quotas and shares are not active then find the average system load for
154188 // all online CPUs that are allowed to run this container.
155189
156190 // If the cpuset is the same as the host's one there is no need to iterate over each CPU
@@ -205,6 +239,8 @@ private boolean isCpuSetSameAsHostCpuSet() {
205239 private native double getSingleCpuLoad0 (int cpuNum );
206240 private native int getHostConfiguredCpuCount0 ();
207241 private native int getHostOnlineCpuCount0 ();
242+ // CPU ticks since boot in nanoseconds
243+ private native long getHostTotalCpuTicks0 ();
208244
209245 static {
210246 initialize0 ();
0 commit comments