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
public float ratio(Resource a, Resource b) {
return (float)a.getMemorySize() / b.getMemorySize();
return divideSafelyAsFloat(a.getMemorySize(), b.getMemorySize());
}
@Override

View File

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

View File

@ -87,6 +87,24 @@ public abstract class ResourceCalculator {
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) {
return divideAndCeil(a, b) * b;
}

View File

@ -36,11 +36,11 @@ import static org.junit.Assert.assertEquals;
public class TestResourceCalculator {
private final ResourceCalculator resourceCalculator;
@Parameterized.Parameters
public static Collection<ResourceCalculator[]> getParameters() {
return Arrays.asList(new ResourceCalculator[][] {
{ new DefaultResourceCalculator() },
{ new DominantResourceCalculator() } });
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> getParameters() {
return Arrays.asList(new Object[][] {
{ "DefaultResourceCalculator", new DefaultResourceCalculator() },
{ "DominantResourceCalculator", new DominantResourceCalculator() } });
}
@Before
@ -57,7 +57,7 @@ public class TestResourceCalculator {
ResourceUtils.resetResourceTypes(conf);
}
public TestResourceCalculator(ResourceCalculator rs) {
public TestResourceCalculator(String name, ResourceCalculator rs) {
this.resourceCalculator = rs;
}
@ -392,4 +392,18 @@ public class TestResourceCalculator {
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);
}
}