Github user revans2 commented on a diff in the pull request:
https://github.com/apache/storm/pull/2485#discussion_r159736224
--- Diff:
storm-server/src/main/java/org/apache/storm/scheduler/resource/NormalizedResources.java
---
@@ -246,59 +259,133 @@ public boolean
couldHoldIgnoringSharedMemory(NormalizedResources other) {
return true;
}
+ private void throwBecauseResourceIsMissingFromTotal(int resourceIndex)
{
+ String resourceName = null;
+ for (Map.Entry<String, Integer> entry : resourceNames.entrySet()) {
+ int index = entry.getValue();
+ if (index == resourceIndex) {
+ resourceName = entry.getKey();
+ break;
+ }
+ }
+ if (resourceName == null) {
+ throw new IllegalStateException("Array index " + resourceIndex
+ " is not mapped in the resource names map."
+ + " This should not be possible, and is likely a bug in
the Storm code.");
+ }
+ throw new IllegalArgumentException("Total resources does not
contain resource '"
+ + resourceName
+ + "'. All resources should be represented in the total. This
is likely a bug in the Storm code");
+ }
+
/**
- * Calculate the average resource usage percentage with this being the
total resources and
- * used being the amounts used.
+ * Calculate the average resource usage percentage with this being the
total resources and used being the amounts used.
+ *
* @param used the amount of resources used.
- * @return the average percentage used 0.0 to 100.0.
+ * @return the average percentage used 0.0 to 100.0. Clamps to 100.0
in case there are no available resources in the total
*/
public double calculateAveragePercentageUsedBy(NormalizedResources
used) {
+ int skippedResourceTypes = 0;
double total = 0.0;
double totalMemory = getTotalMemoryMb();
if (totalMemory != 0.0) {
total += used.getTotalMemoryMb() / totalMemory;
+ } else {
+ skippedResourceTypes++;
}
double totalCpu = getTotalCpu();
if (totalCpu != 0.0) {
total += used.getTotalCpu() / getTotalCpu();
+ } else {
+ skippedResourceTypes++;
}
- //If total is 0 we add in a 0% used, so we can just skip over
anything that is not in both.
- int length = Math.min(used.otherResources.length,
otherResources.length);
- for (int i = 0; i < length; i++) {
- if (otherResources[i] != 0.0) {
- total += used.otherResources[i] / otherResources[i];
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Calculating avg percentage used by. Used CPU: {}
Total CPU: {} Used Mem: {} Total Mem: {}"
+ + " Other Used: {} Other Total: {}", totalCpu,
used.getTotalCpu(), totalMemory, used.getTotalMemoryMb(),
+ this.toNormalizedOtherResources(),
used.toNormalizedOtherResources());
+ }
+
+ if (used.otherResources.length > otherResources.length) {
+
throwBecauseResourceIsMissingFromTotal(used.otherResources.length);
+ }
+
+ for (int i = 0; i < otherResources.length; i++) {
+ double totalValue = otherResources[i];
+ if (totalValue == 0.0) {
+ //Skip any resources where the total is 0, the percent
used for this resource isn't meaningful.
+ //We fall back to prioritizing by cpu, memory and any
other resources by ignoring this value
+ skippedResourceTypes++;
+ continue;
}
+ double usedValue;
+ if (i >= used.otherResources.length) {
+ //Resources missing from used are using none of that
resource
+ usedValue = 0.0;
+ } else {
+ usedValue = used.otherResources[i];
+ }
+ total += usedValue / totalValue;
+ }
+ //Adjust the divisor for the average to account for any skipped
resources (those where the total was 0)
+ int divisor = 2 + otherResources.length - skippedResourceTypes;
+ if (divisor == 0) {
+ /*This is an arbitrary choice to make the result consistent
with calculateMin.
+ Any value would be valid here, becase there are no (non-zero)
resources in the total set of resources,
+ so we're trying to average 0 values.
+ */
+ return 100.0;
+ } else {
+ return (total * 100.0) / divisor;
}
- //To get the count we divide by we need to take the maximum length
because we are doing an average.
- return (total * 100.0) / (2 + Math.max(otherResources.length,
used.otherResources.length));
}
/**
- * Calculate the minimum resource usage percentage with this being the
total resources and
- * used being the amounts used.
+ * Calculate the minimum resource usage percentage with this being the
total resources and used being the amounts used.
+ *
* @param used the amount of resources used.
- * @return the minimum percentage used 0.0 to 100.0.
+ * @return the minimum percentage used 0.0 to 100.0. Clamps to 100.0
in case there are no available resources in the total.
*/
public double calculateMinPercentageUsedBy(NormalizedResources used) {
double totalMemory = getTotalMemoryMb();
double totalCpu = getTotalCpu();
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Calculating min percentage used by. Used CPU: {}
Total CPU: {} Used Mem: {} Total Mem: {}"
+ + " Other Used: {} Other Total: {}", totalCpu,
used.getTotalCpu(), totalMemory, used.getTotalMemoryMb(),
+ toNormalizedOtherResources(),
used.toNormalizedOtherResources());
+ }
+
+ if (used.otherResources.length > otherResources.length) {
+
throwBecauseResourceIsMissingFromTotal(used.otherResources.length);
+ }
+
if (used.otherResources.length != otherResources.length
|| totalMemory == 0.0
|| totalCpu == 0.0) {
//If the lengths don't match one of the resources will be 0,
which means we would calculate the percentage to be 0.0
// and so the min would be 0.0 (assuming that we can never go
negative on a resource being used.
return 0.0;
}
- double min = used.getTotalMemoryMb() / totalMemory;
- min = Math.min(min, used.getTotalCpu() / getTotalCpu());
+
+ double min = 100.0;
+ if (totalMemory != 0.0) {
+ min = Math.min(min, used.getTotalMemoryMb() / totalMemory);
+ }
+ if (totalCpu != 0.0) {
--- End diff --
Again the math looks OK, but could you explain that 0 % used is ignored in
the javadocs, because it is not obvious to me that it what will happen.
---