YARN-7136. Additional Performance Improvement for Resource Profile Feature

(Contributed by Wangda Tan via Daniel Templeton)
This commit is contained in:
Daniel Templeton 2017-09-11 14:17:57 -07:00 committed by Wangda Tan
parent 6b88cd1901
commit bf2b687412
13 changed files with 525 additions and 339 deletions

View File

@ -617,7 +617,7 @@
</Match>
<Match>
<Class name="org.apache.hadoop.yarn.api.records.impl.BaseResource" />
<Class name="org.apache.hadoop.yarn.api.records.Resource" />
<Method name="getResources" />
<Bug pattern="EI_EXPOSE_REP" />
</Match>

View File

@ -27,7 +27,7 @@
import org.apache.hadoop.classification.InterfaceStability.Evolving;
import org.apache.hadoop.classification.InterfaceStability.Stable;
import org.apache.hadoop.yarn.api.ApplicationMasterProtocol;
import org.apache.hadoop.yarn.api.records.impl.BaseResource;
import org.apache.hadoop.yarn.api.records.impl.LightWeightResource;
import org.apache.hadoop.yarn.exceptions.ResourceNotFoundException;
import org.apache.hadoop.yarn.util.Records;
import org.apache.hadoop.yarn.util.resource.ResourceUtils;
@ -59,8 +59,15 @@
@Stable
public abstract class Resource implements Comparable<Resource> {
protected static final String MEMORY = ResourceInformation.MEMORY_MB.getName();
protected static final String VCORES = ResourceInformation.VCORES.getName();
protected ResourceInformation[] resources = null;
// Number of mandatory resources, this is added to avoid invoke
// MandatoryResources.values().length, since values() internally will
// copy array, etc.
protected static final int NUM_MANDATORY_RESOURCES = 2;
protected static final int MEMORY_INDEX = 0;
protected static final int VCORES_INDEX = 1;
@Public
@Stable
@ -71,7 +78,7 @@ public static Resource newInstance(int memory, int vCores) {
ret.setVirtualCores(vCores);
return ret;
}
return new BaseResource(memory, vCores);
return new LightWeightResource(memory, vCores);
}
@Public
@ -83,7 +90,7 @@ public static Resource newInstance(long memory, int vCores) {
ret.setVirtualCores(vCores);
return ret;
}
return new BaseResource(memory, vCores);
return new LightWeightResource(memory, vCores);
}
@InterfaceAudience.Private
@ -201,7 +208,9 @@ public void setMemorySize(long memory) {
*/
@Public
@Evolving
public abstract ResourceInformation[] getResources();
public ResourceInformation[] getResources() {
return resources;
}
/**
* Get ResourceInformation for a specified resource.
@ -215,7 +224,6 @@ public void setMemorySize(long memory) {
public ResourceInformation getResourceInformation(String resource)
throws ResourceNotFoundException {
Integer index = ResourceUtils.getResourceTypeIndex().get(resource);
ResourceInformation[] resources = getResources();
if (index != null) {
return resources[index];
}
@ -236,12 +244,13 @@ public ResourceInformation getResourceInformation(String resource)
@Evolving
public ResourceInformation getResourceInformation(int index)
throws ResourceNotFoundException {
ResourceInformation[] resources = getResources();
if (index < 0 || index >= resources.length) {
throw new ResourceNotFoundException("Unknown resource at index '" + index
+ "'. Vaid resources are: " + Arrays.toString(resources));
ResourceInformation ri = null;
try {
ri = resources[index];
} catch (ArrayIndexOutOfBoundsException e) {
throwExceptionWhenArrayOutOfBound(index);
}
return resources[index];
return ri;
}
/**
@ -271,11 +280,11 @@ public long getResourceValue(String resource)
public void setResourceInformation(String resource,
ResourceInformation resourceInformation)
throws ResourceNotFoundException {
if (resource.equals(MEMORY)) {
if (resource.equals(ResourceInformation.MEMORY_URI)) {
this.setMemorySize(resourceInformation.getValue());
return;
}
if (resource.equals(VCORES)) {
if (resource.equals(ResourceInformation.VCORES_URI)) {
this.setVirtualCores((int) resourceInformation.getValue());
return;
}
@ -298,7 +307,6 @@ public void setResourceInformation(String resource,
public void setResourceInformation(int index,
ResourceInformation resourceInformation)
throws ResourceNotFoundException {
ResourceInformation[] resources = getResources();
if (index < 0 || index >= resources.length) {
throw new ResourceNotFoundException("Unknown resource at index '" + index
+ "'. Valid resources are " + Arrays.toString(resources));
@ -318,11 +326,11 @@ public void setResourceInformation(int index,
@Evolving
public void setResourceValue(String resource, long value)
throws ResourceNotFoundException {
if (resource.equals(MEMORY)) {
if (resource.equals(ResourceInformation.MEMORY_URI)) {
this.setMemorySize(value);
return;
}
if (resource.equals(VCORES)) {
if (resource.equals(ResourceInformation.VCORES_URI)) {
this.setVirtualCores((int)value);
return;
}
@ -346,27 +354,21 @@ public void setResourceValue(String resource, long value)
@Evolving
public void setResourceValue(int index, long value)
throws ResourceNotFoundException {
ResourceInformation[] resources = getResources();
if (index < 0 || index >= resources.length) {
throw new ResourceNotFoundException("Unknown resource at index '" + index
+ "'. Valid resources are " + Arrays.toString(resources));
try {
resources[index].setValue(value);
} catch (ArrayIndexOutOfBoundsException e) {
throwExceptionWhenArrayOutOfBound(index);
}
resources[index].setValue(value);
}
@Override
public int hashCode() {
final int prime = 263167;
private void throwExceptionWhenArrayOutOfBound(int index) {
String exceptionMsg = String.format(
"Trying to access ResourceInformation for given index=%d. "
+ "Acceptable index range is [0,%d), please check double check "
+ "configured resources in resource-types.xml",
index, ResourceUtils.getNumberOfKnownResourceTypes());
int result = (int) (939769357
+ getMemorySize()); // prime * result = 939769357 initially
result = prime * result + getVirtualCores();
for (ResourceInformation entry : getResources()) {
if (!entry.getName().equals(MEMORY) && !entry.getName().equals(VCORES)) {
result = prime * result + entry.hashCode();
}
}
return result;
throw new ResourceNotFoundException(exceptionMsg);
}
@Override
@ -381,20 +383,15 @@ public boolean equals(Object obj) {
return false;
}
Resource other = (Resource) obj;
if (getMemorySize() != other.getMemorySize()
|| getVirtualCores() != other.getVirtualCores()) {
return false;
}
ResourceInformation[] myVectors = getResources();
ResourceInformation[] otherVectors = other.getResources();
if (myVectors.length != otherVectors.length) {
if (resources.length != otherVectors.length) {
return false;
}
for (int i = 0; i < myVectors.length; i++) {
ResourceInformation a = myVectors[i];
for (int i = 0; i < resources.length; i++) {
ResourceInformation a = resources[i];
ResourceInformation b = otherVectors[i];
if ((a != b) && ((a == null) || !a.equals(b))) {
return false;
@ -403,63 +400,70 @@ public boolean equals(Object obj) {
return true;
}
@Override
public int compareTo(Resource other) {
ResourceInformation[] otherResources = other.getResources();
int arrLenThis = this.resources.length;
int arrLenOther = otherResources.length;
// compare memory and vcores first(in that order) to preserve
// existing behaviour
for (int i = 0; i < arrLenThis; i++) {
ResourceInformation otherEntry;
try {
otherEntry = otherResources[i];
} catch (ArrayIndexOutOfBoundsException e) {
// For two vectors with different size and same prefix. Shorter vector
// goes first.
return 1;
}
ResourceInformation entry = resources[i];
long diff = entry.compareTo(otherEntry);
if (diff > 0) {
return 1;
} else if (diff < 0) {
return -1;
}
}
if (arrLenThis < arrLenOther) {
return -1;
}
return 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("<memory:").append(getMemorySize()).append(", vCores:")
.append(getVirtualCores());
for (ResourceInformation entry : getResources()) {
if (entry.getName().equals(MEMORY)
&& entry.getUnits()
.equals(ResourceInformation.MEMORY_MB.getUnits())) {
for (int i = 2; i < resources.length; i++) {
ResourceInformation ri = resources[i];
if (ri.getValue() == 0) {
continue;
}
if (entry.getName().equals(VCORES)
&& entry.getUnits()
.equals(ResourceInformation.VCORES.getUnits())) {
continue;
}
sb.append(", ").append(entry.getName()).append(": ")
.append(entry.getValue())
.append(entry.getUnits());
sb.append(", ");
sb.append(ri.getName()).append(": ")
.append(ri.getValue());
sb.append(ri.getUnits());
}
sb.append(">");
return sb.toString();
}
@Override
public int compareTo(Resource other) {
ResourceInformation[] thisResources = this.getResources();
ResourceInformation[] otherResources = other.getResources();
// compare memory and vcores first(in that order) to preserve
// existing behaviour
long diff = this.getMemorySize() - other.getMemorySize();
if (diff == 0) {
diff = this.getVirtualCores() - other.getVirtualCores();
public int hashCode() {
final int prime = 47;
long result = 0;
for (ResourceInformation entry : resources) {
result = prime * result + entry.hashCode();
}
if (diff == 0) {
diff = thisResources.length - otherResources.length;
if (diff == 0) {
int maxLength = ResourceUtils.getResourceTypesArray().length;
for (int i = 0; i < maxLength; i++) {
// For memory and vcores, we can skip the loop as it's already
// compared.
if (i < 2) {
continue;
}
ResourceInformation entry = thisResources[i];
ResourceInformation otherEntry = otherResources[i];
if (entry.getName().equals(otherEntry.getName())) {
diff = entry.compareTo(otherEntry);
if (diff != 0) {
break;
}
}
}
}
}
return Long.compare(diff, 0);
return (int) result;
}
}

View File

@ -18,6 +18,8 @@
package org.apache.hadoop.yarn.api.records;
import org.apache.curator.shaded.com.google.common.reflect.ClassPath;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.yarn.api.protocolrecords.ResourceTypes;
import org.apache.hadoop.yarn.util.UnitsConversionUtil;
@ -34,8 +36,8 @@ public class ResourceInformation implements Comparable<ResourceInformation> {
private long minimumAllocation;
private long maximumAllocation;
private static final String MEMORY_URI = "memory-mb";
private static final String VCORES_URI = "vcores";
public static final String MEMORY_URI = "memory-mb";
public static final String VCORES_URI = "vcores";
public static final ResourceInformation MEMORY_MB =
ResourceInformation.newInstance(MEMORY_URI, "Mi");
@ -83,6 +85,16 @@ public void setUnits(String rUnits) {
this.units = rUnits;
}
/**
* Checking if a unit included by KNOWN_UNITS is an expensive operation. This
* can be avoided in critical path in RM.
* @param rUnits units for the resource
*/
@InterfaceAudience.Private
public void setUnitsWithoutValidation(String rUnits) {
this.units = rUnits;
}
/**
* Get the resource type.
*

View File

@ -18,19 +18,24 @@
package org.apache.hadoop.yarn.api.records.impl;
import org.apache.hadoop.classification.InterfaceAudience.Public;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability.Unstable;
import org.apache.hadoop.yarn.api.protocolrecords.ResourceTypes;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceInformation;
import java.util.Arrays;
import static org.apache.hadoop.yarn.api.records.ResourceInformation.MEMORY_MB;
import static org.apache.hadoop.yarn.api.records.ResourceInformation.MEMORY_URI;
import static org.apache.hadoop.yarn.api.records.ResourceInformation.VCORES_URI;
/**
* <p>
* <code>BaseResource</code> extends Resource to handle base resources such
* <code>LightResource</code> extends Resource to handle base resources such
* as memory and CPU.
* TODO: We have a long term plan to use AbstractResource when additional
* resource types are to be handled as well.
* This will be used to speed up internal calculation to avoid creating
* costly PB-backed Resource object: <code>ResourcePBImpl</code>
* </p>
*
* <p>
@ -54,48 +59,34 @@
*
* @see Resource
*/
@Public
@InterfaceAudience.Private
@Unstable
public class BaseResource extends Resource {
public class LightWeightResource extends Resource {
private ResourceInformation memoryResInfo;
private ResourceInformation vcoresResInfo;
protected ResourceInformation[] resources = null;
protected ResourceInformation[] readOnlyResources = null;
// Number of mandatory resources, this is added to avoid invoke
// MandatoryResources.values().length, since values() internally will
// copy array, etc.
private static final int NUM_MANDATORY_RESOURCES = 2;
protected enum MandatoryResources {
MEMORY(0), VCORES(1);
private final int id;
MandatoryResources(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
}
public BaseResource() {
// Base constructor.
}
public BaseResource(long memory, long vcores) {
this.memoryResInfo = ResourceInformation.newInstance(MEMORY,
ResourceInformation.MEMORY_MB.getUnits(), memory);
this.vcoresResInfo = ResourceInformation.newInstance(VCORES, "", vcores);
public LightWeightResource(long memory, long vcores) {
this.memoryResInfo = LightWeightResource.newDefaultInformation(MEMORY_URI,
MEMORY_MB.getUnits(), memory);
this.vcoresResInfo = LightWeightResource.newDefaultInformation(VCORES_URI,
"", vcores);
resources = new ResourceInformation[NUM_MANDATORY_RESOURCES];
readOnlyResources = new ResourceInformation[NUM_MANDATORY_RESOURCES];
resources[MandatoryResources.MEMORY.id] = memoryResInfo;
resources[MandatoryResources.VCORES.id] = vcoresResInfo;
readOnlyResources = Arrays.copyOf(resources, resources.length);
resources[MEMORY_INDEX] = memoryResInfo;
resources[VCORES_INDEX] = vcoresResInfo;
}
private static ResourceInformation newDefaultInformation(String name,
String unit, long value) {
ResourceInformation ri = new ResourceInformation();
ri.setName(name);
ri.setValue(value);
ri.setResourceType(ResourceTypes.COUNTABLE);
ri.setUnitsWithoutValidation(unit);
ri.setMinimumAllocation(0);
ri.setMaximumAllocation(Long.MAX_VALUE);
return ri;
}
@Override
@ -131,7 +122,42 @@ public void setVirtualCores(int vcores) {
}
@Override
public ResourceInformation[] getResources() {
return readOnlyResources;
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !(obj instanceof Resource)) {
return false;
}
Resource other = (Resource) obj;
if (getMemorySize() != other.getMemorySize()
|| getVirtualCores() != other.getVirtualCores()) {
return false;
}
return true;
}
@Override
public int compareTo(Resource other) {
// compare memory and vcores first(in that order) to preserve
// existing behaviour
long diff = this.getMemorySize() - other.getMemorySize();
if (diff == 0) {
return this.getVirtualCores() - other.getVirtualCores();
} else if (diff > 0){
return 1;
} else {
return -1;
}
}
@Override
public int hashCode() {
final int prime = 47;
long result = prime + getMemorySize();
result = prime * result + getVirtualCores();
return (int) result;
}
}

View File

@ -244,13 +244,28 @@ static void initializeResourcesMap(Configuration conf) {
minimumAllocation, maximumAllocation));
}
}
checkMandatoryResources(resourceInformationMap);
addMandatoryResources(resourceInformationMap);
setMinimumAllocationForMandatoryResources(resourceInformationMap, conf);
setMaximumAllocationForMandatoryResources(resourceInformationMap, conf);
initializeResourcesFromResourceInformationMap(resourceInformationMap);
}
/**
* This method is visible for testing, unit test can construct a
* resourceInformationMap and pass it to this method to initialize multiple resources.
* @param resourceInformationMap constructed resource information map.
*/
@VisibleForTesting
public static void initializeResourcesFromResourceInformationMap(
Map<String, ResourceInformation> resourceInformationMap) {
resourceTypes = Collections.unmodifiableMap(resourceInformationMap);
updateKnownResources();
updateResourceTypeIndex();
initializedResources = true;
}
private static void updateKnownResources() {
@ -347,14 +362,12 @@ private static void initializeResourceTypesIfNeeded(Configuration conf,
try {
addResourcesFileToConf(resourceFile, conf);
LOG.debug("Found " + resourceFile + ", adding to configuration");
initializeResourcesMap(conf);
initializedResources = true;
} catch (FileNotFoundException fe) {
LOG.info("Unable to find '" + resourceFile
+ "'. Falling back to memory and vcores as resources.");
initializeResourcesMap(conf);
initializedResources = true;
}
initializeResourcesMap(conf);
}
}
}
@ -558,7 +571,7 @@ public static Resource getResourceTypesMaximumAllocation() {
*/
public static String getDefaultUnit(String resourceType) {
ResourceInformation ri = getResourceTypes().get(resourceType);
if (null != ri) {
if (ri != null) {
return ri.getUnits();
}
return "";

View File

@ -25,7 +25,6 @@
import org.apache.hadoop.yarn.api.protocolrecords.ResourceTypes;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceInformation;
import org.apache.hadoop.yarn.api.records.impl.BaseResource;
import org.apache.hadoop.yarn.exceptions.ResourceNotFoundException;
import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
import org.apache.hadoop.yarn.proto.YarnProtos.ResourceProto;
@ -34,13 +33,12 @@
import org.apache.hadoop.yarn.util.UnitsConversionUtil;
import org.apache.hadoop.yarn.util.resource.ResourceUtils;
import java.util.Arrays;
import java.util.Map;
@Private
@Unstable
public class ResourcePBImpl extends BaseResource {
public class ResourcePBImpl extends Resource {
private static final Log LOG = LogFactory.getLog(ResourcePBImpl.class);
@ -95,7 +93,7 @@ public int getMemory() {
@Override
public long getMemorySize() {
// memory should always be present
ResourceInformation ri = resources[MandatoryResources.MEMORY.getId()];
ResourceInformation ri = resources[MEMORY_INDEX];
if (ri.getUnits().isEmpty()) {
return ri.getValue();
@ -113,19 +111,19 @@ public void setMemory(int memory) {
@Override
public void setMemorySize(long memory) {
maybeInitBuilder();
getResourceInformation(MEMORY).setValue(memory);
getResourceInformation(ResourceInformation.MEMORY_URI).setValue(memory);
}
@Override
public int getVirtualCores() {
// vcores should always be present
return (int) resources[MandatoryResources.VCORES.getId()].getValue();
return (int) resources[VCORES_INDEX].getValue();
}
@Override
public void setVirtualCores(int vCores) {
maybeInitBuilder();
getResourceInformation(VCORES).setValue(vCores);
getResourceInformation(ResourceInformation.VCORES_URI).setValue(vCores);
}
private void initResources() {
@ -156,7 +154,6 @@ private void initResources() {
resources[index].setValue(value);
}
}
readOnlyResources = Arrays.copyOf(resources, resources.length);
this.setMemorySize(p.getMemory());
this.setVirtualCores(p.getVirtualCores());
}
@ -186,11 +183,6 @@ public void setResourceValue(String resource, long value)
getResourceInformation(resource).setValue(value);
}
@Override
public ResourceInformation[] getResources() {
return super.getResources();
}
@Override
public ResourceInformation getResourceInformation(String resource)
throws ResourceNotFoundException {
@ -212,7 +204,6 @@ private void initResourcesMap() {
}
resources = new ResourceInformation[types.length];
readOnlyResources = new ResourceInformation[types.length];
for (ResourceInformation entry : types) {
int index = ResourceUtils.getResourceTypeIndex().get(entry.getName());
resources[index] = ResourceInformation.newInstance(entry);

View File

@ -73,7 +73,7 @@ private int compare(Resource lhs, Resource rhs) {
boolean rhsGreater = false;
int ret = 0;
int maxLength = ResourceUtils.getResourceTypesArray().length;
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
for (int i = 0; i < maxLength; i++) {
ResourceInformation lhsResourceInformation = lhs
.getResourceInformation(i);
@ -111,10 +111,12 @@ public int compare(Resource clusterResource, Resource lhs, Resource rhs,
// resources and then look for which resource has the biggest
// share overall.
ResourceInformation[] clusterRes = clusterResource.getResources();
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
// If array creation shows up as a time sink, these arrays could be cached
// because they're always the same length.
double[] lhsShares = new double[clusterRes.length];
double[] rhsShares = new double[clusterRes.length];
double[] lhsShares = new double[maxLength];
double[] rhsShares = new double[maxLength];
double diff;
try {
@ -124,10 +126,10 @@ public int compare(Resource clusterResource, Resource lhs, Resource rhs,
calculateShares(clusterRes, lhs, rhs, lhsShares, rhsShares, max);
diff = max[0] - max[1];
} else if (clusterRes.length == 2) {
} else if (maxLength == 2) {
// Special case to handle the common scenario of only CPU and memory
// so that we can optimize for performance
diff = calculateSharesForMandatoryResources(clusterRes, lhs, rhs,
diff = calculateSharesForTwoMandatoryResources(clusterRes, lhs, rhs,
lhsShares, rhsShares);
} else {
calculateShares(clusterRes, lhs, rhs, lhsShares, rhsShares);
@ -182,7 +184,8 @@ private void calculateShares(ResourceInformation[] clusterRes, Resource first,
ResourceInformation[] firstRes = first.getResources();
ResourceInformation[] secondRes = second.getResources();
for (int i = 0; i < clusterRes.length; i++) {
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
for (int i = 0; i < maxLength; i++) {
firstShares[i] = calculateShare(clusterRes[i], firstRes[i]);
secondShares[i] = calculateShare(clusterRes[i], secondRes[i]);
}
@ -205,35 +208,27 @@ private void calculateShares(ResourceInformation[] clusterRes, Resource first,
* second resource, respectively
* @throws NullPointerException if any parameter is null
*/
private int calculateSharesForMandatoryResources(
private int calculateSharesForTwoMandatoryResources(
ResourceInformation[] clusterRes, Resource first, Resource second,
double[] firstShares, double[] secondShares) {
ResourceInformation[] firstRes = first.getResources();
ResourceInformation[] secondRes = second.getResources();
firstShares[0] = calculateShare(clusterRes[0], firstRes[0]);
secondShares[0] = calculateShare(clusterRes[0], secondRes[0]);
firstShares[1] = calculateShare(clusterRes[1], firstRes[1]);
secondShares[1] = calculateShare(clusterRes[1], secondRes[1]);
int firstDom = 0;
int firstSub = 1;
if (firstShares[1] > firstShares[0]) {
firstDom = 1;
firstSub = 0;
}
int secondDom = 0;
int firstSub = 0;
int secondSub = 0;
for (int i = 0; i < clusterRes.length; i++) {
firstShares[i] = calculateShare(clusterRes[i], firstRes[i]);
secondShares[i] = calculateShare(clusterRes[i], secondRes[i]);
if (firstShares[i] > firstShares[firstDom]) {
firstDom = i;
}
if (firstShares[i] < firstShares[firstSub]) {
firstSub = i;
}
if (secondShares[i] > secondShares[secondDom]) {
secondDom = i;
}
if (secondShares[i] < secondShares[secondSub]) {
secondSub = i;
}
int secondSub = 1;
if (secondShares[1] > secondShares[0]) {
secondDom = 1;
secondSub = 0;
}
if (firstShares[firstDom] > secondShares[secondDom]) {
@ -280,7 +275,8 @@ private void calculateShares(ResourceInformation[] clusterRes, Resource first,
max[0] = 0.0;
max[1] = 0.0;
for (int i = 0; i < clusterRes.length; i++) {
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
for (int i = 0; i < maxLength; i++) {
firstShares[i] = calculateShare(clusterRes[i], firstRes[i]);
secondShares[i] = calculateShare(clusterRes[i], secondRes[i]);
@ -339,7 +335,7 @@ private double compareShares(double[] lhsShares, double[] rhsShares) {
public long computeAvailableContainers(Resource available,
Resource required) {
long min = Long.MAX_VALUE;
int maxLength = ResourceUtils.getResourceTypesArray().length;
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
for (int i = 0; i < maxLength; i++) {
ResourceInformation availableResource = available
.getResourceInformation(i);
@ -358,11 +354,12 @@ public long computeAvailableContainers(Resource available,
@Override
public float divide(Resource clusterResource,
Resource numerator, Resource denominator) {
int nKnownResourceTypes = ResourceUtils.getNumberOfKnownResourceTypes();
ResourceInformation[] clusterRes = clusterResource.getResources();
// We have to provide the calculateShares() method with somewhere to store
// the shares. We don't actually need these shares afterwards.
double[] numeratorShares = new double[clusterRes.length];
double[] denominatorShares = new double[clusterRes.length];
double[] numeratorShares = new double[nKnownResourceTypes];
double[] denominatorShares = new double[nKnownResourceTypes];
// We also have to provide a place for calculateShares() to store the max
// shares so that we can use them.
double[] max = new double[2];
@ -386,7 +383,7 @@ public boolean isInvalidDivisor(Resource r) {
@Override
public float ratio(Resource a, Resource b) {
float ratio = 0.0f;
int maxLength = ResourceUtils.getResourceTypesArray().length;
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
for (int i = 0; i < maxLength; i++) {
ResourceInformation aResourceInformation = a.getResourceInformation(i);
ResourceInformation bResourceInformation = b.getResourceInformation(i);
@ -407,7 +404,7 @@ public Resource divideAndCeil(Resource numerator, int denominator) {
public Resource divideAndCeil(Resource numerator, long denominator) {
Resource ret = Resource.newInstance(numerator);
int maxLength = ResourceUtils.getResourceTypesArray().length;
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
for (int i = 0; i < maxLength; i++) {
ResourceInformation resourceInformation = ret.getResourceInformation(i);
resourceInformation
@ -428,7 +425,7 @@ public Resource divideAndCeil(Resource numerator, float denominator) {
public Resource normalize(Resource r, Resource minimumResource,
Resource maximumResource, Resource stepFactor) {
Resource ret = Resource.newInstance(r);
int maxLength = ResourceUtils.getResourceTypesArray().length;
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
for (int i = 0; i < maxLength; i++) {
ResourceInformation rResourceInformation = r.getResourceInformation(i);
ResourceInformation minimumResourceInformation = minimumResource
@ -474,7 +471,7 @@ public Resource roundDown(Resource r, Resource stepFactor) {
private Resource rounding(Resource r, Resource stepFactor, boolean roundUp) {
Resource ret = Resource.newInstance(r);
int maxLength = ResourceUtils.getResourceTypesArray().length;
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
for (int i = 0; i < maxLength; i++) {
ResourceInformation rResourceInformation = r.getResourceInformation(i);
ResourceInformation stepFactorResourceInformation = stepFactor
@ -513,7 +510,7 @@ public Resource multiplyAndNormalizeDown(Resource r, double by,
private Resource multiplyAndNormalize(Resource r, double by,
Resource stepFactor, boolean roundUp) {
Resource ret = Resource.newInstance(r);
int maxLength = ResourceUtils.getResourceTypesArray().length;
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
for (int i = 0; i < maxLength; i++) {
ResourceInformation rResourceInformation = r.getResourceInformation(i);
ResourceInformation stepFactorResourceInformation = stepFactor
@ -542,7 +539,7 @@ private Resource multiplyAndNormalize(Resource r, double by,
@Override
public boolean fitsIn(Resource cluster, Resource smaller, Resource bigger) {
int maxLength = ResourceUtils.getResourceTypesArray().length;
int maxLength = ResourceUtils.getNumberOfKnownResourceTypes();
for (int i = 0; i < maxLength; i++) {
ResourceInformation sResourceInformation = smaller
.getResourceInformation(i);

View File

@ -24,12 +24,9 @@
import org.apache.hadoop.classification.InterfaceStability.Unstable;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceInformation;
import org.apache.hadoop.yarn.api.records.impl.BaseResource;
import org.apache.hadoop.yarn.exceptions.ResourceNotFoundException;
import org.apache.hadoop.yarn.util.UnitsConversionUtil;
import java.util.Arrays;
/**
* Resources is a computation class which provides a set of apis to do
* mathematical operations on Resource object.
@ -45,9 +42,11 @@ public class Resources {
* Helper class to create a resource with a fixed value for all resource
* types. For example, a NONE resource which returns 0 for any resource type.
*/
static class FixedValueResource extends BaseResource {
@InterfaceAudience.Private
@Unstable
static class FixedValueResource extends Resource {
private long resourceValue;
private final long resourceValue;
private String name;
/**
@ -100,6 +99,19 @@ public void setVirtualCores(int virtualCores) {
throw new RuntimeException(name + " cannot be modified!");
}
@Override
public void setResourceInformation(int index,
ResourceInformation resourceInformation)
throws ResourceNotFoundException {
throw new RuntimeException(name + " cannot be modified!");
}
@Override
public void setResourceValue(int index, long value)
throws ResourceNotFoundException {
throw new RuntimeException(name + " cannot be modified!");
}
@Override
public void setResourceInformation(String resource,
ResourceInformation resourceInformation)
@ -117,19 +129,11 @@ private void initResourceMap() {
ResourceInformation[] types = ResourceUtils.getResourceTypesArray();
if (types != null) {
resources = new ResourceInformation[types.length];
readOnlyResources = new ResourceInformation[types.length];
for (int index = 0; index < types.length; index++) {
resources[index] = ResourceInformation.newInstance(types[index]);
resources[index].setValue(resourceValue);
// this is a fix for getVirtualCores returning an int
if (resourceValue > Integer.MAX_VALUE && ResourceInformation.VCORES
.getName().equals(resources[index].getName())) {
resources[index].setValue((long) Integer.MAX_VALUE);
}
}
}
readOnlyResources = Arrays.copyOf(resources, resources.length);
}
}

View File

@ -80,6 +80,7 @@
import org.apache.hadoop.yarn.server.resourcemanager.recovery.MemoryRMStateStore;
import org.apache.hadoop.yarn.server.resourcemanager.recovery.NullRMStateStore;
import org.apache.hadoop.yarn.server.resourcemanager.recovery.RMStateStore;
import org.apache.hadoop.yarn.server.resourcemanager.resource.TestResourceProfiles;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppState;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt;
@ -151,7 +152,10 @@ public MockRM(Configuration conf, RMStateStore store,
public MockRM(Configuration conf, RMStateStore store,
boolean useNullRMNodeLabelsManager, boolean useRealElector) {
super();
ResourceUtils.resetResourceTypes(conf);
if (conf.getBoolean(TestResourceProfiles.TEST_CONF_RESET_RESOURCE_TYPES,
true)) {
ResourceUtils.resetResourceTypes(conf);
}
this.useNullRMNodeLabelsManager = useNullRMNodeLabelsManager;
this.useRealElector = useRealElector;
init(conf instanceof YarnConfiguration ? conf : new YarnConfiguration(conf));

View File

@ -33,6 +33,8 @@
* Common test class for resource profile related tests.
*/
public class TestResourceProfiles {
public static final String TEST_CONF_RESET_RESOURCE_TYPES =
"yarn.test.reset-resource-types";
@Test
public void testProfilesEnabled() throws Exception {

View File

@ -4319,143 +4319,6 @@ public void testCSReservationWithRootUnblocked() throws Exception {
rm.stop();
}
@Test (timeout = 300000)
public void testUserLimitThroughput() throws Exception {
// Since this is more of a performance unit test, only run if
// RunUserLimitThroughput is set (-DRunUserLimitThroughput=true)
Assume.assumeTrue(Boolean.valueOf(
System.getProperty("RunUserLimitThroughput")));
CapacitySchedulerConfiguration csconf =
new CapacitySchedulerConfiguration();
csconf.setMaximumApplicationMasterResourcePerQueuePercent("root", 100.0f);
csconf.setMaximumAMResourcePercentPerPartition("root", "", 100.0f);
csconf.setMaximumApplicationMasterResourcePerQueuePercent("root.default",
100.0f);
csconf.setMaximumAMResourcePercentPerPartition("root.default", "", 100.0f);
csconf.setResourceComparator(DominantResourceCalculator.class);
YarnConfiguration conf = new YarnConfiguration(csconf);
conf.setClass(YarnConfiguration.RM_SCHEDULER, CapacityScheduler.class,
ResourceScheduler.class);
MockRM rm = new MockRM(conf);
rm.start();
CapacityScheduler cs = (CapacityScheduler) rm.getResourceScheduler();
LeafQueue qb = (LeafQueue)cs.getQueue("default");
// For now make user limit large so we can activate all applications
qb.setUserLimitFactor((float)100.0);
qb.setupConfigurableCapacities();
SchedulerEvent addAppEvent;
SchedulerEvent addAttemptEvent;
Container container = mock(Container.class);
ApplicationSubmissionContext submissionContext =
mock(ApplicationSubmissionContext.class);
final int appCount = 100;
ApplicationId[] appids = new ApplicationId[appCount];
RMAppAttemptImpl[] attempts = new RMAppAttemptImpl[appCount];
ApplicationAttemptId[] appAttemptIds = new ApplicationAttemptId[appCount];
RMAppImpl[] apps = new RMAppImpl[appCount];
RMAppAttemptMetrics[] attemptMetrics = new RMAppAttemptMetrics[appCount];
for (int i=0; i<appCount; i++) {
appids[i] = BuilderUtils.newApplicationId(100, i);
appAttemptIds[i] =
BuilderUtils.newApplicationAttemptId(appids[i], 1);
attemptMetrics[i] =
new RMAppAttemptMetrics(appAttemptIds[i], rm.getRMContext());
apps[i] = mock(RMAppImpl.class);
when(apps[i].getApplicationId()).thenReturn(appids[i]);
attempts[i] = mock(RMAppAttemptImpl.class);
when(attempts[i].getMasterContainer()).thenReturn(container);
when(attempts[i].getSubmissionContext()).thenReturn(submissionContext);
when(attempts[i].getAppAttemptId()).thenReturn(appAttemptIds[i]);
when(attempts[i].getRMAppAttemptMetrics()).thenReturn(attemptMetrics[i]);
when(apps[i].getCurrentAppAttempt()).thenReturn(attempts[i]);
rm.getRMContext().getRMApps().put(appids[i], apps[i]);
addAppEvent =
new AppAddedSchedulerEvent(appids[i], "default", "user1");
cs.handle(addAppEvent);
addAttemptEvent =
new AppAttemptAddedSchedulerEvent(appAttemptIds[i], false);
cs.handle(addAttemptEvent);
}
// add nodes to cluster, so cluster has 20GB and 20 vcores
Resource newResource = Resource.newInstance(10 * GB, 10);
RMNode node = MockNodes.newNodeInfo(0, newResource, 1, "127.0.0.1");
cs.handle(new NodeAddedSchedulerEvent(node));
Resource newResource2 = Resource.newInstance(10 * GB, 10);
RMNode node2 = MockNodes.newNodeInfo(0, newResource2, 1, "127.0.0.2");
cs.handle(new NodeAddedSchedulerEvent(node2));
Priority u0Priority = TestUtils.createMockPriority(1);
RecordFactory recordFactory =
RecordFactoryProvider.getRecordFactory(null);
FiCaSchedulerApp[] fiCaApps = new FiCaSchedulerApp[appCount];
for (int i=0;i<appCount;i++) {
fiCaApps[i] =
cs.getSchedulerApplications().get(apps[i].getApplicationId())
.getCurrentAppAttempt();
// allocate container for app2 with 1GB memory and 1 vcore
fiCaApps[i].updateResourceRequests(Collections.singletonList(
TestUtils.createResourceRequest(ResourceRequest.ANY, 1*GB, 1, true,
u0Priority, recordFactory)));
}
// Now force everything to be over user limit
qb.setUserLimitFactor((float)0.0);
// Quiet the loggers while measuring throughput
for (Enumeration<?> loggers=LogManager.getCurrentLoggers();
loggers.hasMoreElements(); ) {
Logger logger = (Logger) loggers.nextElement();
logger.setLevel(Level.WARN);
}
final int topn = 20;
final int iterations = 2000000;
final int printInterval = 20000;
final float numerator = 1000.0f * printInterval;
PriorityQueue<Long> queue = new PriorityQueue<>(topn,
Collections.reverseOrder());
long n = Time.monotonicNow();
long timespent = 0;
for (int i = 0; i < iterations; i+=2) {
if (i > 0 && i % printInterval == 0){
long ts = (Time.monotonicNow() - n);
if (queue.size() < topn) {
queue.offer(ts);
} else {
Long last = queue.peek();
if (last > ts) {
queue.poll();
queue.offer(ts);
}
}
System.out.println(i + " " + (numerator / ts));
n= Time.monotonicNow();
}
cs.handle(new NodeUpdateSchedulerEvent(node));
cs.handle(new NodeUpdateSchedulerEvent(node2));
}
timespent=0;
int entries = queue.size();
while(queue.size() > 0){
long l = queue.poll();
timespent += l;
}
System.out.println("Avg of fastest " + entries + ": "
+ numerator / (timespent / entries));
rm.stop();
}
@Test
public void testCSQueueBlocked() throws Exception {
CapacitySchedulerConfiguration conf = new CapacitySchedulerConfiguration();

View File

@ -0,0 +1,265 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity;
import org.apache.hadoop.util.Time;
import org.apache.hadoop.yarn.api.protocolrecords.ResourceTypes;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
import org.apache.hadoop.yarn.api.records.Container;
import org.apache.hadoop.yarn.api.records.Priority;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceInformation;
import org.apache.hadoop.yarn.api.records.ResourceRequest;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.factories.RecordFactory;
import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider;
import org.apache.hadoop.yarn.server.resourcemanager.MockNodes;
import org.apache.hadoop.yarn.server.resourcemanager.MockRM;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptImpl;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptMetrics;
import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNode;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.common.fica.FiCaSchedulerApp;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.AppAddedSchedulerEvent;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.AppAttemptAddedSchedulerEvent;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.NodeAddedSchedulerEvent;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.NodeUpdateSchedulerEvent;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.SchedulerEvent;
import org.apache.hadoop.yarn.server.utils.BuilderUtils;
import org.apache.hadoop.yarn.util.resource.DominantResourceCalculator;
import org.apache.hadoop.yarn.util.resource.ResourceUtils;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.junit.Assume;
import org.junit.Test;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import static org.apache.hadoop.yarn.server.resourcemanager.resource.TestResourceProfiles.TEST_CONF_RESET_RESOURCE_TYPES;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class TestCapacitySchedulerPerf {
private final int GB = 1024;
private String getResourceName(int idx) {
return "resource-" + idx;
}
private void testUserLimitThroughputWithNumberOfResourceTypes(
int numOfResourceTypes)
throws Exception {
if (numOfResourceTypes > 2) {
// Initialize resource map
Map<String, ResourceInformation> riMap = new HashMap<>();
// Initialize mandatory resources
riMap.put(ResourceInformation.MEMORY_URI, ResourceInformation.MEMORY_MB);
riMap.put(ResourceInformation.VCORES_URI, ResourceInformation.VCORES);
for (int i = 2; i < numOfResourceTypes; i++) {
String resourceName = getResourceName(i);
riMap.put(resourceName, ResourceInformation
.newInstance(resourceName, "", 0, ResourceTypes.COUNTABLE, 0,
Integer.MAX_VALUE));
}
ResourceUtils.initializeResourcesFromResourceInformationMap(riMap);
}
// Since this is more of a performance unit test, only run if
// RunUserLimitThroughput is set (-DRunUserLimitThroughput=true)
Assume.assumeTrue(Boolean.valueOf(
System.getProperty("RunCapacitySchedulerPerfTests")));
CapacitySchedulerConfiguration csconf =
new CapacitySchedulerConfiguration();
csconf.setMaximumApplicationMasterResourcePerQueuePercent("root", 100.0f);
csconf.setMaximumAMResourcePercentPerPartition("root", "", 100.0f);
csconf.setMaximumApplicationMasterResourcePerQueuePercent("root.default",
100.0f);
csconf.setMaximumAMResourcePercentPerPartition("root.default", "", 100.0f);
csconf.setResourceComparator(DominantResourceCalculator.class);
YarnConfiguration conf = new YarnConfiguration(csconf);
// Don't reset resource types since we have already configured resource types
conf.setBoolean(TEST_CONF_RESET_RESOURCE_TYPES, false);
conf.setClass(YarnConfiguration.RM_SCHEDULER, CapacityScheduler.class,
ResourceScheduler.class);
MockRM rm = new MockRM(conf);
rm.start();
CapacityScheduler cs = (CapacityScheduler) rm.getResourceScheduler();
LeafQueue qb = (LeafQueue)cs.getQueue("default");
// For now make user limit large so we can activate all applications
qb.setUserLimitFactor((float)100.0);
qb.setupConfigurableCapacities();
SchedulerEvent addAppEvent;
SchedulerEvent addAttemptEvent;
Container container = mock(Container.class);
ApplicationSubmissionContext submissionContext =
mock(ApplicationSubmissionContext.class);
final int appCount = 100;
ApplicationId[] appids = new ApplicationId[appCount];
RMAppAttemptImpl[] attempts = new RMAppAttemptImpl[appCount];
ApplicationAttemptId[] appAttemptIds = new ApplicationAttemptId[appCount];
RMAppImpl[] apps = new RMAppImpl[appCount];
RMAppAttemptMetrics[] attemptMetrics = new RMAppAttemptMetrics[appCount];
for (int i=0; i<appCount; i++) {
appids[i] = BuilderUtils.newApplicationId(100, i);
appAttemptIds[i] =
BuilderUtils.newApplicationAttemptId(appids[i], 1);
attemptMetrics[i] =
new RMAppAttemptMetrics(appAttemptIds[i], rm.getRMContext());
apps[i] = mock(RMAppImpl.class);
when(apps[i].getApplicationId()).thenReturn(appids[i]);
attempts[i] = mock(RMAppAttemptImpl.class);
when(attempts[i].getMasterContainer()).thenReturn(container);
when(attempts[i].getSubmissionContext()).thenReturn(submissionContext);
when(attempts[i].getAppAttemptId()).thenReturn(appAttemptIds[i]);
when(attempts[i].getRMAppAttemptMetrics()).thenReturn(attemptMetrics[i]);
when(apps[i].getCurrentAppAttempt()).thenReturn(attempts[i]);
rm.getRMContext().getRMApps().put(appids[i], apps[i]);
addAppEvent =
new AppAddedSchedulerEvent(appids[i], "default", "user1");
cs.handle(addAppEvent);
addAttemptEvent =
new AppAttemptAddedSchedulerEvent(appAttemptIds[i], false);
cs.handle(addAttemptEvent);
}
// add nodes to cluster, so cluster has 20GB and 20 vcores
Resource nodeResource = Resource.newInstance(10 * GB, 10);
if (numOfResourceTypes > 2) {
for (int i = 2; i < numOfResourceTypes; i++) {
nodeResource.setResourceValue(getResourceName(i), 10);
}
}
RMNode node = MockNodes.newNodeInfo(0, nodeResource, 1, "127.0.0.1");
cs.handle(new NodeAddedSchedulerEvent(node));
RMNode node2 = MockNodes.newNodeInfo(0, nodeResource, 1, "127.0.0.2");
cs.handle(new NodeAddedSchedulerEvent(node2));
Priority u0Priority = TestUtils.createMockPriority(1);
RecordFactory recordFactory =
RecordFactoryProvider.getRecordFactory(null);
FiCaSchedulerApp[] fiCaApps = new FiCaSchedulerApp[appCount];
for (int i=0;i<appCount;i++) {
fiCaApps[i] =
cs.getSchedulerApplications().get(apps[i].getApplicationId())
.getCurrentAppAttempt();
ResourceRequest resourceRequest = TestUtils.createResourceRequest(
ResourceRequest.ANY, 1 * GB, 1, true, u0Priority, recordFactory);
if (numOfResourceTypes > 2) {
for (int j = 2; j < numOfResourceTypes; j++) {
resourceRequest.getCapability().setResourceValue(getResourceName(j),
10);
}
}
// allocate container for app2 with 1GB memory and 1 vcore
fiCaApps[i].updateResourceRequests(
Collections.singletonList(resourceRequest));
}
// Now force everything to be over user limit
qb.setUserLimitFactor((float)0.0);
// Quiet the loggers while measuring throughput
for (Enumeration<?> loggers = LogManager.getCurrentLoggers();
loggers.hasMoreElements(); ) {
Logger logger = (Logger) loggers.nextElement();
logger.setLevel(Level.WARN);
}
final int topn = 20;
final int iterations = 2000000;
final int printInterval = 20000;
final float numerator = 1000.0f * printInterval;
PriorityQueue<Long> queue = new PriorityQueue<>(topn,
Collections.reverseOrder());
long n = Time.monotonicNow();
long timespent = 0;
for (int i = 0; i < iterations; i+=2) {
if (i > 0 && i % printInterval == 0){
long ts = (Time.monotonicNow() - n);
if (queue.size() < topn) {
queue.offer(ts);
} else {
Long last = queue.peek();
if (last > ts) {
queue.poll();
queue.offer(ts);
}
}
System.out.println(i + " " + (numerator / ts));
n= Time.monotonicNow();
}
cs.handle(new NodeUpdateSchedulerEvent(node));
cs.handle(new NodeUpdateSchedulerEvent(node2));
}
timespent=0;
int entries = queue.size();
while(queue.size() > 0){
long l = queue.poll();
timespent += l;
}
System.out.println(
"#ResourceTypes = " + numOfResourceTypes + ". Avg of fastest " + entries
+ ": " + numerator / (timespent / entries));
rm.stop();
}
@Test(timeout = 300000)
public void testUserLimitThroughputForTwoResources() throws Exception {
testUserLimitThroughputWithNumberOfResourceTypes(2);
}
@Test(timeout = 300000)
public void testUserLimitThroughputForThreeResources() throws Exception {
testUserLimitThroughputWithNumberOfResourceTypes(3);
}
@Test(timeout = 300000)
public void testUserLimitThroughputForFourResources() throws Exception {
testUserLimitThroughputWithNumberOfResourceTypes(4);
}
@Test(timeout = 300000)
public void testUserLimitThroughputForFiveResources() throws Exception {
testUserLimitThroughputWithNumberOfResourceTypes(5);
}
}

View File

@ -101,6 +101,8 @@
import com.google.common.annotations.VisibleForTesting;
import static org.apache.hadoop.yarn.server.resourcemanager.resource.TestResourceProfiles.TEST_CONF_RESET_RESOURCE_TYPES;
/**
* <p>
* Embedded Yarn minicluster for testcases that need to interact with a cluster.
@ -251,7 +253,10 @@ public void serviceInit(Configuration conf) throws Exception {
YarnConfiguration.DEFAULT_YARN_MINICLUSTER_USE_RPC);
failoverTimeout = conf.getInt(YarnConfiguration.RM_ZK_TIMEOUT_MS,
YarnConfiguration.DEFAULT_RM_ZK_TIMEOUT_MS);
ResourceUtils.resetResourceTypes(conf);
if (conf.getBoolean(TEST_CONF_RESET_RESOURCE_TYPES, true)) {
ResourceUtils.resetResourceTypes(conf);
}
if (useRpc && !useFixedPorts) {
throw new YarnRuntimeException("Invalid configuration!" +