@@ -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 );
@@ -133,24 +135,56 @@ public long getMaxFileDescriptorCount() {
133
135
return getMaxFileDescriptorCount0 ();
134
136
}
135
137
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
+
136
170
public double getSystemCpuLoad () {
137
171
if (containerMetrics != null ) {
138
172
long quota = containerMetrics .getCpuQuota ();
173
+ long share = containerMetrics .getCpuShares ();
174
+ long usageNanos = containerMetrics .getCpuUsage ();
139
175
if (quota > 0 ) {
140
- long periodLength = containerMetrics .getCpuPeriod ();
141
176
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 );
152
186
} 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
154
188
// all online CPUs that are allowed to run this container.
155
189
156
190
// 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() {
205
239
private native double getSingleCpuLoad0 (int cpuNum );
206
240
private native int getHostConfiguredCpuCount0 ();
207
241
private native int getHostOnlineCpuCount0 ();
242
+ // CPU ticks since boot in nanoseconds
243
+ private native long getHostTotalCpuTicks0 ();
208
244
209
245
static {
210
246
initialize0 ();
0 commit comments