Skip to content

Commit

Permalink
[MultiTenant] Support TenantHeapIsolation
Browse files Browse the repository at this point in the history
Summary: ported heap isolation feature of MultiTenant to Dragonwell8

Test Plan: hotspot/test/multi-tenant/

Reviewed-by: luchsh, mmyxym

Issue: dragonwell-project/dragonwell8#90
  • Loading branch information
Hao Tang committed Apr 3, 2020
1 parent 0d8749d commit b725bad
Show file tree
Hide file tree
Showing 56 changed files with 3,416 additions and 67 deletions.
5 changes: 5 additions & 0 deletions make/linux/makefiles/mapfile-vers-debug
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,12 @@ SUNWprivate_1.1 {

# INSERT VTABLE SYMBOLS HERE

JVM_TenantContainerOf;
JVM_AttachToTenant;
JVM_CreateTenantAllocationContext;
JVM_DestroyTenantAllocationContext;
JVM_GetTenantOccupiedMemory;


local:
*;
Expand Down
4 changes: 4 additions & 0 deletions make/linux/makefiles/mapfile-vers-product
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,11 @@ SUNWprivate_1.1 {

# INSERT VTABLE SYMBOLS HERE

JVM_TenantContainerOf;
JVM_AttachToTenant;
JVM_CreateTenantAllocationContext;
JVM_DestroyTenantAllocationContext;
JVM_GetTenantOccupiedMemory;

local:
*;
Expand Down
82 changes: 82 additions & 0 deletions src/share/vm/classfile/javaClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
#include "runtime/vframe.hpp"
#include "utilities/preserveException.hpp"

#if INCLUDE_ALL_GCS
#include "gc_implementation/g1/g1TenantAllocationContext.hpp"
#endif // INCLUDE_ALL_GCS

PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC

#define INJECTED_FIELD_COMPUTE_OFFSET(klass, name, signature, may_be_java) \
Expand Down Expand Up @@ -3247,6 +3251,13 @@ int java_lang_AssertionStatusDirectives::packages_offset;
int java_lang_AssertionStatusDirectives::packageEnabled_offset;
int java_lang_AssertionStatusDirectives::deflt_offset;
int java_nio_Buffer::_limit_offset;
#if INCLUDE_ALL_GCS
int com_alibaba_tenant_TenantContainer::_allocation_context_offset;
int com_alibaba_tenant_TenantContainer::_tenant_id_offset;
int com_alibaba_tenant_TenantContainer::_tenant_state_offset;

int com_alibaba_tenant_TenantState::_static_state_offsets[com_alibaba_tenant_TenantState::TS_SIZE] = { 0 };
#endif // INCLUDE_ALL_GCS
int java_util_concurrent_locks_AbstractOwnableSynchronizer::_owner_offset = 0;
int sun_reflect_ConstantPool::_oop_offset;
int sun_reflect_UnsafeStaticFieldAccessorImpl::_base_offset;
Expand Down Expand Up @@ -3306,6 +3317,73 @@ void java_nio_Buffer::compute_offsets() {
compute_offset(_limit_offset, k, vmSymbols::limit_name(), vmSymbols::int_signature());
}

#if INCLUDE_ALL_GCS

// Support for com.alibaba.tenant.TenantContainer

void com_alibaba_tenant_TenantContainer::compute_offsets() {
Klass* k = SystemDictionary::com_alibaba_tenant_TenantContainer_klass();
assert(k != NULL, "Cannot find TenantContainer in current JDK");
compute_offset(_tenant_id_offset, k, vmSymbols::tenant_id_address(), vmSymbols::long_signature());
compute_offset(_allocation_context_offset, k, vmSymbols::allocation_context_address(), vmSymbols::long_signature());
compute_offset(_tenant_state_offset, k, vmSymbols::state_name(), vmSymbols::com_alibaba_tenant_TenantState_signature());
}

jlong com_alibaba_tenant_TenantContainer::get_tenant_id(oop obj) {
assert(obj != NULL, "TenantContainer object cannot be NULL");
return obj->long_field(_tenant_id_offset);
}

G1TenantAllocationContext* com_alibaba_tenant_TenantContainer::get_tenant_allocation_context(oop obj) {
assert(obj != NULL, "TenantContainer object cannot be NULL");
return (G1TenantAllocationContext*)(obj->long_field(_allocation_context_offset));
}

void com_alibaba_tenant_TenantContainer::set_tenant_allocation_context(oop obj, G1TenantAllocationContext* context) {
assert(obj != NULL, "TenantContainer object cannot be NULL");
obj->long_field_put(_allocation_context_offset, (jlong)context);
}

bool com_alibaba_tenant_TenantContainer::is_dead(oop obj) {
assert(obj != NULL, "TenantContainer object cannot be NULL");
int state = com_alibaba_tenant_TenantState::state_of(obj);
return state == com_alibaba_tenant_TenantState::TS_STOPPING
|| state == com_alibaba_tenant_TenantState::TS_DEAD;
}

oop com_alibaba_tenant_TenantContainer::get_tenant_state(oop obj) {
assert(obj != NULL, "TenantContainer object cannot be NULL");
obj->obj_field(_tenant_state_offset);
}

// Support for com.alibaba.tenant.TenantState

int com_alibaba_tenant_TenantState::state_of(oop tenant_obj) {
assert(tenant_obj != NULL, "TenantContainer ");

oop tenant_state = com_alibaba_tenant_TenantContainer::get_tenant_state(tenant_obj);
InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::com_alibaba_tenant_TenantState_klass());

for (int i = TS_STARTING; i < TS_SIZE; ++i) {
assert(_static_state_offsets[i] == i * heapOopSize, "Must have been initialized");
address addr = ik->static_field_addr(_static_state_offsets[i]);
oop o = NULL;
if (UseCompressedOops) {
o = oopDesc::load_decode_heap_oop((narrowOop*)addr);
} else {
o = oopDesc::load_decode_heap_oop((oop*)addr);
}
assert(!oopDesc::is_null(o), "sanity");
if (tenant_state == o) {
return i;
}
}

ShouldNotReachHere();
}

#endif // INCLUDE_ALL_GCS

void java_util_concurrent_locks_AbstractOwnableSynchronizer::initialize(TRAPS) {
if (_owner_offset != 0) return;

Expand Down Expand Up @@ -3415,6 +3493,10 @@ void JavaClasses::compute_offsets() {

// generated interpreter code wants to know about the offsets we just computed:
AbstractAssembler::update_delayed_values();

if(MultiTenant) {
com_alibaba_tenant_TenantContainer::compute_offsets();
}
}

#ifndef PRODUCT
Expand Down
39 changes: 39 additions & 0 deletions src/share/vm/classfile/javaClasses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1404,6 +1404,45 @@ class java_util_concurrent_locks_AbstractOwnableSynchronizer : AllStatic {
static oop get_owner_threadObj(oop obj);
};

#if INCLUDE_ALL_GCS

class G1TenantAllocationContext;

class com_alibaba_tenant_TenantContainer : AllStatic {
private:
static int _tenant_id_offset;
static int _allocation_context_offset;
static int _tenant_state_offset;
public:
static jlong get_tenant_id(oop obj);
static G1TenantAllocationContext* get_tenant_allocation_context(oop obj);
static void set_tenant_allocation_context(oop obj, G1TenantAllocationContext* context);
static oop get_tenant_state(oop obj);
static bool is_dead(oop obj);
static void compute_offsets();
};

class com_alibaba_tenant_TenantState : AllStatic {
friend class JavaClasses;
public:
// C++ level definition of tenant status
enum {
TS_STARTING = 0,
TS_RUNNING = 1,
TS_STOPPING = 2,
TS_DEAD = 3,
TS_SIZE,
};

private:
// offsets
static int _static_state_offsets[TS_SIZE];
public:
static int state_of(oop tenant_obj);
};

#endif // INCLUDE_ALL_GCS

// Use to declare fields that need to be injected into Java classes
// for the JVM to use. The name_index and signature_index are
// declared in vmSymbols. The may_be_java flag is used to declare
Expand Down
3 changes: 2 additions & 1 deletion src/share/vm/classfile/vmSymbols.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,8 @@
do_intrinsic(_updateByteBufferCRC32, java_util_zip_CRC32, updateByteBuffer_name, updateByteBuffer_signature, F_SN) \
do_name( updateByteBuffer_name, "updateByteBuffer") \
do_signature(updateByteBuffer_signature, "(IJII)I") \
/* support for com.alibaba.tenant.TenantContainer */ \
\
/* support for com.alibaba.tenant.TenantContainer */ \
do_name( allocation_context_address, "allocationContext") \
do_name( tenant_id_address, "tenantId") \
\
Expand Down
12 changes: 12 additions & 0 deletions src/share/vm/gc_implementation/g1/evacuationInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ class EvacuationInfo : public StackObj {
_allocation_regions = allocation_regions;
}

void increment_allocation_regions(uint allocation_regions) {
assert(TenantHeapIsolation, "pre-condition");
_allocation_regions += allocation_regions;
}

void set_collectionset_used_before(size_t used) {
_collectionset_used_before = used;
}
Expand All @@ -61,6 +66,13 @@ class EvacuationInfo : public StackObj {
_alloc_regions_used_before = used;
}

// For multi-tenant mode, multiple calls to set_alloc_regions_used_before() may happen,
// thus change to below method to accumulate those results
void increment_alloc_regions_used_before(size_t used) {
assert(TenantHeapIsolation, "pre-condition");
_alloc_regions_used_before += used;
}

void set_bytes_copied(size_t copied) {
_bytes_copied = copied;
}
Expand Down
15 changes: 15 additions & 0 deletions src/share/vm/gc_implementation/g1/g1AllocRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size,

void MutatorAllocRegion::retire_region(HeapRegion* alloc_region,
size_t allocated_bytes) {
DEBUG_ONLY(if (TenantHeapIsolation) {
assert(alloc_region->allocation_context() == allocation_context(),
"Inconsistent allocation contexts");
});

_g1h->retire_mutator_alloc_region(alloc_region, allocated_bytes);
}

Expand All @@ -259,6 +264,11 @@ HeapRegion* SurvivorGCAllocRegion::allocate_new_region(size_t word_size,

void SurvivorGCAllocRegion::retire_region(HeapRegion* alloc_region,
size_t allocated_bytes) {
DEBUG_ONLY(if (TenantHeapIsolation) {
assert(alloc_region->allocation_context() == allocation_context(),
"HeapRegion's context should be same as SurvivorGCAllocRegion's");
});

_g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, InCSetState::Young);
}

Expand All @@ -270,6 +280,11 @@ HeapRegion* OldGCAllocRegion::allocate_new_region(size_t word_size,

void OldGCAllocRegion::retire_region(HeapRegion* alloc_region,
size_t allocated_bytes) {
DEBUG_ONLY(if (TenantHeapIsolation) {
assert(alloc_region->allocation_context() == allocation_context(),
"HeapRegion's context should be same as OldGCAllocRegion's");
});

_g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, InCSetState::Old);
}

Expand Down
14 changes: 12 additions & 2 deletions src/share/vm/gc_implementation/g1/g1AllocRegion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,18 @@ class G1AllocRegion VALUE_OBJ_CLASS_SPEC {
return (hr == _dummy_region) ? NULL : hr;
}

void set_allocation_context(AllocationContext_t context) { _allocation_context = context; }
AllocationContext_t allocation_context() { return _allocation_context; }
void set_allocation_context(AllocationContext_t context) {
_allocation_context = context;
}

const AllocationContext_t& allocation_context() const {
return _allocation_context;
}

const G1TenantAllocationContext* tenant_allocation_context() const {
assert(TenantHeapIsolation, "pre-condition");
return allocation_context().tenant_allocation_context();
}

uint count() { return _count; }

Expand Down
21 changes: 21 additions & 0 deletions src/share/vm/gc_implementation/g1/g1AllocRegion.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ inline HeapWord* G1AllocRegion::attempt_allocation(size_t word_size,
HeapRegion* alloc_region = _alloc_region;
assert(alloc_region != NULL, ar_ext_msg(this, "not initialized properly"));

DEBUG_ONLY(if (TenantHeapIsolation
/* (_alloc_region == _dummy_region) means current AllocRegion has not yet
* really initialized
*/
&& alloc_region != G1AllocRegion::_dummy_region) {
assert(allocation_context() == alloc_region->allocation_context(),
"Tring to allocate in the wrong heap region");
});

HeapWord* result = par_allocate(alloc_region, word_size, bot_updates);
if (result != NULL) {
trace("alloc", word_size, result);
Expand All @@ -82,6 +91,12 @@ inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t word_size,
retire(true /* fill_up */);
result = new_alloc_region_and_allocate(word_size, false /* force */);
if (result != NULL) {
DEBUG_ONLY(if (TenantHeapIsolation) {
// _alloc_region was updated, check its tenant alloc context
assert(allocation_context() == _alloc_region->allocation_context(),
"Allocate in wrong region");
});

trace("alloc locked (second attempt)", word_size, result);
return result;
}
Expand All @@ -97,6 +112,12 @@ inline HeapWord* G1AllocRegion::attempt_allocation_force(size_t word_size,
trace("forcing alloc");
HeapWord* result = new_alloc_region_and_allocate(word_size, true /* force */);
if (result != NULL) {
DEBUG_ONLY(if (TenantHeapIsolation) {
// _alloc_region was updated, check its tenant alloc context
assert(allocation_context() == _alloc_region->allocation_context(),
"Allocate in wrong region");
});

trace("alloc forced", word_size, result);
return result;
}
Expand Down
46 changes: 46 additions & 0 deletions src/share/vm/gc_implementation/g1/g1AllocationContext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

#include "gc_implementation/g1/g1AllocationContext.hpp"
#include "runtime/thread.hpp"

// 0 will be returned if in ROOT tenant or memory isolation not enabled
AllocationContext_t AllocationContext::_root_context;

AllocationContext_t AllocationContext::current() {
return Thread::current()->allocation_context();
}

AllocationContext_t AllocationContext::system() {
return _root_context;
}

AllocationContextMark::AllocationContextMark(AllocationContext_t ctxt)
: _saved_context(Thread::current()->allocation_context()) {
Thread* thrd = Thread::current();
thrd->set_allocation_context(ctxt);
}

AllocationContextMark::~AllocationContextMark() {
Thread* thrd = Thread::current();
thrd->set_allocation_context(_saved_context);
}
Loading

0 comments on commit b725bad

Please sign in to comment.