YARN-9019. Ratio calculation of ResourceCalculator implementations could return NaN. (Contributed by Szilard Nemeth)

This commit is contained in:
Haibo Chen 2018-12-05 15:15:30 -08:00
parent b3c75c1f1d
commit 912b1f9d64
4 changed files with 41 additions and 9 deletions

View File

@ -57,7 +57,7 @@ public class DefaultResourceCalculator extends ResourceCalculator {
@Override @Override
public float ratio(Resource a, Resource b) { public float ratio(Resource a, Resource b) {
return (float)a.getMemorySize() / b.getMemorySize(); return divideSafelyAsFloat(a.getMemorySize(), b.getMemorySize());
} }
@Override @Override

View File

@ -379,8 +379,8 @@ public class DominantResourceCalculator extends ResourceCalculator {
for (int i = 0; i < maxLength; i++) { for (int i = 0; i < maxLength; i++) {
ResourceInformation aResourceInformation = a.getResourceInformation(i); ResourceInformation aResourceInformation = a.getResourceInformation(i);
ResourceInformation bResourceInformation = b.getResourceInformation(i); ResourceInformation bResourceInformation = b.getResourceInformation(i);
float tmp = (float) aResourceInformation.getValue() final float tmp = divideSafelyAsFloat(aResourceInformation.getValue(),
/ (float) bResourceInformation.getValue(); bResourceInformation.getValue());
ratio = ratio > tmp ? ratio : tmp; ratio = ratio > tmp ? ratio : tmp;
} }
return ratio; return ratio;

View File

@ -87,6 +87,24 @@ public abstract class ResourceCalculator {
return (long) Math.ceil(a/b); return (long) Math.ceil(a/b);
} }
/**
* Divides lhs by rhs.
* If both lhs and rhs are having a value of 0, then we return 0.
* This is to avoid division by zero and return NaN as a result.
* If lhs is zero but rhs is not, Float.infinity will be returned
* as the result.
* @param lhs
* @param rhs
* @return
*/
public static float divideSafelyAsFloat(long lhs, long rhs) {
if (lhs == 0 && rhs == 0) {
return 0;
} else {
return (float) lhs / (float) rhs;
}
}
public static int roundUp(int a, int b) { public static int roundUp(int a, int b) {
return divideAndCeil(a, b) * b; return divideAndCeil(a, b) * b;
} }

View File

@ -36,11 +36,11 @@ import static org.junit.Assert.assertEquals;
public class TestResourceCalculator { public class TestResourceCalculator {
private final ResourceCalculator resourceCalculator; private final ResourceCalculator resourceCalculator;
@Parameterized.Parameters @Parameterized.Parameters(name = "{0}")
public static Collection<ResourceCalculator[]> getParameters() { public static Collection<Object[]> getParameters() {
return Arrays.asList(new ResourceCalculator[][] { return Arrays.asList(new Object[][] {
{ new DefaultResourceCalculator() }, { "DefaultResourceCalculator", new DefaultResourceCalculator() },
{ new DominantResourceCalculator() } }); { "DominantResourceCalculator", new DominantResourceCalculator() } });
} }
@Before @Before
@ -57,7 +57,7 @@ public class TestResourceCalculator {
ResourceUtils.resetResourceTypes(conf); ResourceUtils.resetResourceTypes(conf);
} }
public TestResourceCalculator(ResourceCalculator rs) { public TestResourceCalculator(String name, ResourceCalculator rs) {
this.resourceCalculator = rs; this.resourceCalculator = rs;
} }
@ -392,4 +392,18 @@ public class TestResourceCalculator {
assertEquals(2, result.getVirtualCores()); assertEquals(2, result.getVirtualCores());
} }
} }
@Test
public void testDivisionByZeroRatioDenominatorIsZero() {
float ratio = resourceCalculator.ratio(newResource(1, 1), newResource(0,
0));
assertEquals(Float.POSITIVE_INFINITY, ratio, 0.00001);
}
@Test
public void testDivisionByZeroRatioNumeratorAndDenominatorIsZero() {
float ratio = resourceCalculator.ratio(newResource(0, 0), newResource(0,
0));
assertEquals(0.0, ratio, 0.00001);
}
} }