提交 d786fdbf 编写于 作者: H Hao Tang 提交者: Hao Tang

[MultiTenant] Support TenantHeapIsolation

Summary: ported heap isolation feature of MultiTenant to Dragonwell8

Test Plan: hotspot/test/multi-tenant/

Reviewed-by: luchsh, mmyxym

Issue: https://github.com/alibaba/dragonwell8/issues/90
上级 f09d14b6
...@@ -47,8 +47,7 @@ public class Constraint { ...@@ -47,8 +47,7 @@ public class Constraint {
/** /**
* Constraint should be instantiated by {@link ResourceType#newConstraint(long...)} * Constraint should be instantiated by {@link ResourceType#newConstraint(long...)}
*/ */
Constraint(ResourceType type, long[] values) { protected Constraint(ResourceType type, long[] values) {
assert type.validate(values);
this.type = type; this.type = type;
this.values = values; this.values = values;
} }
......
...@@ -22,9 +22,6 @@ ...@@ -22,9 +22,6 @@
package com.alibaba.rcm; package com.alibaba.rcm;
import java.util.Arrays;
import java.util.stream.IntStream;
/** /**
* Enumeration of {@link Constraint}'s type. * Enumeration of {@link Constraint}'s type.
* <p> * <p>
...@@ -54,27 +51,38 @@ public class ResourceType { ...@@ -54,27 +51,38 @@ public class ResourceType {
* The value ranges from 0 to CPU_COUNT * 100. For example, {@code 150} * The value ranges from 0 to CPU_COUNT * 100. For example, {@code 150}
* means that ResourceContainer can use up to 1.5 CPU cores. * means that ResourceContainer can use up to 1.5 CPU cores.
*/ */
public final static ResourceType CPU_PERCENT = public final static ResourceType CPU_PERCENT = new ResourceType("CPU_PERCENT") {
new ResourceType("CPU_PERCENT", newChecker(0, Runtime.getRuntime().availableProcessors() * 100)); @Override
protected void validate(long... values) throws IllegalArgumentException {
if (values == null || values.length != 1
|| values[0] < 1
|| values[0] > Runtime.getRuntime().availableProcessors() * 100) {
throw new IllegalArgumentException("Bad CPU_PERCENT constraint: " + values[0]);
}
}
};
/** /**
* Throttling the max heap usage. * Throttling the max heap usage.
* <p> * <p>
* param #1: maximum heap size in bytes * param #1: maximum heap size in bytes
*/ */
public final static ResourceType HEAP_RETAINED = public final static ResourceType HEAP_RETAINED = new ResourceType("HEAP_RETAINED") {
new ResourceType("HEAP_RETAINED", newChecker(0, Runtime.getRuntime().maxMemory())); @Override
protected void validate(long... values) throws IllegalArgumentException {
if (values == null || values.length != 1
|| values[0] <= 0
|| values[0] > Runtime.getRuntime().maxMemory()) {
throw new IllegalArgumentException("Bad HEAP_RETAINED constraint: " + values[0]);
}
}
};
// name of this ResourceType
private final String name; private final String name;
private final ParameterChecker[] checkers;
protected ResourceType(String name) { protected ResourceType(String name) {
this.name = name; this.name = name;
this.checkers = null;
}
protected ResourceType(String name, ParameterChecker... checkers) {
this.name = name;
this.checkers = checkers;
} }
/** /**
...@@ -85,11 +93,8 @@ public class ResourceType { ...@@ -85,11 +93,8 @@ public class ResourceType {
* @return newly-created Constraint * @return newly-created Constraint
* @throws IllegalArgumentException when parameter check fails * @throws IllegalArgumentException when parameter check fails
*/ */
public final Constraint newConstraint(long... values) { public Constraint newConstraint(long... values) {
if (!validate(values)) { validate(values);
throw new IllegalArgumentException(this +
" values: " + Arrays.toString(values));
}
return new Constraint(this, values); return new Constraint(this, values);
} }
...@@ -102,49 +107,21 @@ public class ResourceType { ...@@ -102,49 +107,21 @@ public class ResourceType {
* <pre> * <pre>
* public final static ResourceType MY_RESOURCE = * public final static ResourceType MY_RESOURCE =
* new ResourceType() { * new ResourceType() {
* protected boolean validate(long[] values) { * protected void validate(long[] values) throws IllegalArgumentException {
* // the check logic * // the check logic
* } * }
* }; * };
* </pre> * </pre>
* *
* @param values parameter value * @param values parameter value
* @return if parameter is validated * @throws IllegalArgumentException if validation failed
*/ */
protected boolean validate(long[] values) { protected void validate(long... values) throws IllegalArgumentException {
if (checkers == null) { // No check at all!
return true;
}
if (checkers.length != values.length) {
return false;
}
return IntStream.range(0, values.length)
.allMatch(i -> checkers[i].check(values[i]));
} }
@Override @Override
public String toString() { public String toString() {
return name; return "ResourceType-" + name;
}
protected static ParameterChecker newChecker(long from, long to) {
return new ParameterChecker(from, to);
}
/**
* Helper class for parameter range check.
*/
protected static class ParameterChecker {
private final long from;
private final long to;
protected ParameterChecker(long from, long to) {
this.from = from;
this.to = to;
}
protected boolean check(long value) {
return value >= from && value < to;
}
} }
} }
...@@ -32,9 +32,22 @@ class NativeDispatcher { ...@@ -32,9 +32,22 @@ class NativeDispatcher {
// Attach the current thread to given {@code tenant} // Attach the current thread to given {@code tenant}
native void attach(TenantContainer tenant); native void attach(TenantContainer tenant);
// Create and initialize native allocation context
native void createTenantAllocationContext(TenantContainer tenant, long heapLimit);
// Destroy native allocation context
// NOTE: cannot be called directly in finalize() otherwise will lead to hang issue
native void destroyTenantAllocationContext(long allocationContext);
// Get memory size currently occupied by this allocation context
native long getTenantOccupiedMemory(long allocationContext);
// Gets an array containing the amount of memory allocated on the Java heap for a set of threads (in bytes) // Gets an array containing the amount of memory allocated on the Java heap for a set of threads (in bytes)
native void getThreadsAllocatedMemory(long[] ids, long[] memSizes); native void getThreadsAllocatedMemory(long[] ids, long[] memSizes);
// Gets the TenantContainer object whose memory space contains <code>obj</code>, or null if ROOT tenant container
native TenantContainer containerOf(Object obj);
private static native void registerNatives0(); private static native void registerNatives0();
static { static {
......
...@@ -30,6 +30,7 @@ import java.util.Map; ...@@ -30,6 +30,7 @@ import java.util.Map;
import java.util.Collection; import java.util.Collection;
import com.alibaba.rcm.ResourceType; import com.alibaba.rcm.ResourceType;
import com.alibaba.rcm.Constraint; import com.alibaba.rcm.Constraint;
import static com.alibaba.rcm.ResourceType.*;
/** /**
* *
...@@ -70,4 +71,24 @@ public class TenantConfiguration { ...@@ -70,4 +71,24 @@ public class TenantConfiguration {
void setConstraint(Constraint constraint) { void setConstraint(Constraint constraint) {
constraints.put(constraint.getResourceType(), constraint); constraints.put(constraint.getResourceType(), constraint);
} }
/**
* Limit total heap size of new {@code TenantContainer} created from this configuration
* @param maxJavaHeapBytes maximum heap size in byte
* @return current {@code TenantConfiguration}
*/
public TenantConfiguration limitHeap(long maxJavaHeapBytes) {
constraints.put(HEAP_RETAINED, HEAP_RETAINED.newConstraint(maxJavaHeapBytes));
return this;
}
/**
* @return the max amount of heap the tenant is allowed to consume.
*/
public long getMaxHeap() {
if (constraints.containsKey(HEAP_RETAINED)) {
return constraints.get(HEAP_RETAINED).getValues()[0];
}
return Runtime.getRuntime().maxMemory();
}
} }
...@@ -93,6 +93,11 @@ public class TenantContainer { ...@@ -93,6 +93,11 @@ public class TenantContainer {
*/ */
private long tenantId; private long tenantId;
/*
* address of native tenant allocation context
*/
private long allocationContext = 0L;
/* /*
* tenant name * tenant name
*/ */
...@@ -253,6 +258,10 @@ public class TenantContainer { ...@@ -253,6 +258,10 @@ public class TenantContainer {
* *
*/ */
private void cleanUp() { private void cleanUp() {
if (TenantGlobals.isHeapIsolationEnabled()) {
nd.destroyTenantAllocationContext(allocationContext);
}
// clear references // clear references
spawnedThreads.clear(); spawnedThreads.clear();
attachedThreads.clear(); attachedThreads.clear();
...@@ -274,6 +283,11 @@ public class TenantContainer { ...@@ -274,6 +283,11 @@ public class TenantContainer {
props = new Properties(); props = new Properties();
props.putAll(System.getProperties()); props.putAll(System.getProperties());
tenantContainerMap.put(this.tenantId, this); tenantContainerMap.put(this.tenantId, this);
// Create allocation context if heap isolation enabled
if (TenantGlobals.isHeapIsolationEnabled()) {
nd.createTenantAllocationContext(this, configuration.getMaxHeap());
}
} }
TenantConfiguration getConfiguration() { TenantConfiguration getConfiguration() {
...@@ -376,6 +390,7 @@ public class TenantContainer { ...@@ -376,6 +390,7 @@ public class TenantContainer {
if (null == configuration) { if (null == configuration) {
throw new IllegalArgumentException("Failed to create tenant, illegal arguments: configuration is null"); throw new IllegalArgumentException("Failed to create tenant, illegal arguments: configuration is null");
} }
TenantContainer tc = new TenantContainer(parent, name, configuration); TenantContainer tc = new TenantContainer(parent, name, configuration);
tenantContainerMap.put(tc.getTenantId(), tc); tenantContainerMap.put(tc.getTenantId(), tc);
return tc; return tc;
...@@ -424,6 +439,18 @@ public class TenantContainer { ...@@ -424,6 +439,18 @@ public class TenantContainer {
return cpuTime; return cpuTime;
} }
/**
* Gets the heap space occupied by this tenant
* @return heap space occupied by this tenant, 0 if tenant heap isolation is disabled.
* @throws IllegalStateException if -XX:+TenantHeapIsolation is not enabled.
*/
public long getOccupiedMemory() {
if (!TenantGlobals.isHeapIsolationEnabled()) {
throw new IllegalStateException("-XX:+TenantHeapIsolation is not enabled");
}
return nd.getTenantOccupiedMemory(allocationContext);
}
/** /**
* Runs the code in the target tenant container * Runs the code in the target tenant container
* @param task the code to run * @param task the code to run
...@@ -564,6 +591,19 @@ public class TenantContainer { ...@@ -564,6 +591,19 @@ public class TenantContainer {
} }
} }
/**
* Retrieve the tenant container where <code>obj</code> is allocated in
* @param obj object to be searched
* @return TenantContainer object whose memory space contains <code>obj</code>,
* or null if ROOT tenant container
*/
public static TenantContainer containerOf(Object obj) {
if (!TenantGlobals.isHeapIsolationEnabled()) {
throw new UnsupportedOperationException("containerOf() only works with -XX:+TenantHeapIsolation");
}
return obj != null ? nd.containerOf(obj) : null;
}
/** /**
* Runs {@code Supplier.get} in the root tenant. * Runs {@code Supplier.get} in the root tenant.
* @param supplier target used to call * @param supplier target used to call
......
...@@ -365,7 +365,19 @@ JVM_ElasticHeapGetTotalUncommittedBytes(JNIEnv *env, jclass clazz); ...@@ -365,7 +365,19 @@ JVM_ElasticHeapGetTotalUncommittedBytes(JNIEnv *env, jclass clazz);
* com.alibaba.tenant.TenantContainer * com.alibaba.tenant.TenantContainer
*/ */
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
JVM_AttachToTenant(JNIEnv *env, jobject tenant); JVM_AttachToTenant(JNIEnv *env, jobject ignored, jobject tenant);
JNIEXPORT void JNICALL
JVM_CreateTenantAllocationContext(JNIEnv *env, jobject ignored, jobject tenant, jlong heapLimit);
JNIEXPORT void JNICALL
JVM_DestroyTenantAllocationContext(JNIEnv *env, jobject ignored, jlong context);
JNIEXPORT jobject JNICALL
JVM_TenantContainerOf(JNIEnv* env, jclass tenantContainerClass, jobject obj);
JNIEXPORT jlong JNICALL
JVM_GetTenantOccupiedMemory(JNIEnv *env, jobject ignored, jlong context);
/* /*
* java.lang.reflect.Array * java.lang.reflect.Array
......
...@@ -13,6 +13,10 @@ static const JmmInterface* jmm_interface = NULL; ...@@ -13,6 +13,10 @@ static const JmmInterface* jmm_interface = NULL;
static JNINativeMethod methods[] = { static JNINativeMethod methods[] = {
{"attach", "(" TENANT ")V", (void *)&JVM_AttachToTenant}, {"attach", "(" TENANT ")V", (void *)&JVM_AttachToTenant},
{"createTenantAllocationContext", "(" TENANT "J)V", (void *)&JVM_CreateTenantAllocationContext},
{"destroyTenantAllocationContext", "(J)V", (void *)&JVM_DestroyTenantAllocationContext},
{"getTenantOccupiedMemory", "(J)J", (void *)&JVM_GetTenantOccupiedMemory},
{"containerOf", "(Ljava/lang/Object;)"TENANT, (void *)&JVM_TenantContainerOf },
}; };
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册