@@ -42,6 +42,8 @@ class OperatingSystemImpl extends BaseOperatingSystemImpl
42
42
43
43
private static final int MAX_ATTEMPTS_NUMBER = 10 ;
44
44
private final Metrics containerMetrics ;
45
+ private long usageTicks = 0 ; // used for cpu load calculation
46
+ private long totalTicks = 0 ; // used for cpu load calculation
45
47
46
48
OperatingSystemImpl (VMManagement vm ) {
47
49
super (vm );
@@ -132,24 +134,56 @@ public long getMaxFileDescriptorCount() {
132
134
return getMaxFileDescriptorCount0 ();
133
135
}
134
136
137
+ private double getUsageDividesTotal (long usageTicks , long totalTicks ) {
138
+ // If cpu quota or cpu shares are in effect calculate the cpu load
139
+ // based on the following formula (similar to how
140
+ // getCpuLoad0() is being calculated):
141
+ //
142
+ // | usageTicks - usageTicks' |
143
+ // ------------------------------
144
+ // | totalTicks - totalTicks' |
145
+ //
146
+ // where usageTicks' and totalTicks' are historical values
147
+ // retrieved via an earlier call of this method.
148
+ //
149
+ // Total ticks should be scaled to the container effective number
150
+ // of cpus, if cpu shares are in effect.
151
+ if (usageTicks < 0 || totalTicks <= 0 ) {
152
+ return -1 ;
153
+ }
154
+ long distance = usageTicks - this .usageTicks ;
155
+ this .usageTicks = usageTicks ;
156
+ long totalDistance = totalTicks - this .totalTicks ;
157
+ this .totalTicks = totalTicks ;
158
+
159
+ double systemLoad = 0.0 ;
160
+ if (distance > 0 && totalDistance > 0 ) {
161
+ systemLoad = ((double )distance ) / totalDistance ;
162
+ }
163
+ // Ensure the return value is in the range 0.0 -> 1.0
164
+ systemLoad = Math .max (0.0 , systemLoad );
165
+ systemLoad = Math .min (1.0 , systemLoad );
166
+ return systemLoad ;
167
+ }
168
+
135
169
public double getCpuLoad () {
136
170
if (containerMetrics != null ) {
137
171
long quota = containerMetrics .getCpuQuota ();
172
+ long share = containerMetrics .getCpuShares ();
173
+ long usageNanos = containerMetrics .getCpuUsage ();
138
174
if (quota > 0 ) {
139
- long periodLength = containerMetrics .getCpuPeriod ();
140
175
long numPeriods = containerMetrics .getCpuNumPeriods ();
141
- long usageNanos = containerMetrics .getCpuUsage ();
142
- if (periodLength > 0 && numPeriods > 0 && usageNanos > 0 ) {
143
- long elapsedNanos = TimeUnit .MICROSECONDS .toNanos (periodLength * numPeriods );
144
- double systemLoad = (double ) usageNanos / elapsedNanos ;
145
- // Ensure the return value is in the range 0.0 -> 1.0
146
- systemLoad = Math .max (0.0 , systemLoad );
147
- systemLoad = Math .min (1.0 , systemLoad );
148
- return systemLoad ;
149
- }
150
- return -1 ;
176
+ long quotaNanos = TimeUnit .MICROSECONDS .toNanos (quota * numPeriods );
177
+ return getUsageDividesTotal (usageNanos , quotaNanos );
178
+ } else if (share > 0 ) {
179
+ long hostTicks = getHostTotalCpuTicks0 ();
180
+ int totalCPUs = getHostOnlineCpuCount0 ();
181
+ int containerCPUs = getAvailableProcessors ();
182
+ // scale the total host load to the actual container cpus
183
+ hostTicks = hostTicks * containerCPUs / totalCPUs ;
184
+ return getUsageDividesTotal (usageNanos , hostTicks );
151
185
} else {
152
- // If CPU quotas are not active then find the average system load for
186
+ // If CPU quotas and shares are not active then find the average system load for
153
187
// all online CPUs that are allowed to run this container.
154
188
155
189
// If the cpuset is the same as the host's one there is no need to iterate over each CPU
@@ -208,6 +242,8 @@ private boolean isCpuSetSameAsHostCpuSet() {
208
242
private native double getSingleCpuLoad0 (int cpuNum );
209
243
private native int getHostConfiguredCpuCount0 ();
210
244
private native int getHostOnlineCpuCount0 ();
245
+ // CPU ticks since boot in nanoseconds
246
+ private native long getHostTotalCpuTicks0 ();
211
247
212
248
static {
213
249
initialize0 ();
0 commit comments