Skip to content

Commit

Permalink
[BACKPORT][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
yiqian committed Oct 31, 2024
1 parent f02e5a5 commit dd5fd77
Show file tree
Hide file tree
Showing 55 changed files with 3,412 additions and 27 deletions.
78 changes: 78 additions & 0 deletions src/hotspot/share/classfile/javaClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
#include "jvmci/jvmciJavaClasses.hpp"
#endif

#if INCLUDE_G1GC
#include "gc/g1/g1TenantAllocationContext.hpp"
#endif // INCLUDE_G1GC

#define INJECTED_FIELD_COMPUTE_OFFSET(klass, name, signature, may_be_java) \
klass::_##name##_offset = JavaClasses::compute_injected_offset(JavaClasses::klass##_##name##_enum);

Expand Down Expand Up @@ -4291,6 +4295,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_G1GC
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_G1GC
int java_util_concurrent_locks_AbstractOwnableSynchronizer::_owner_offset;
int reflect_ConstantPool::_oop_offset;
int reflect_UnsafeStaticFieldAccessorImpl::_base_offset;
Expand Down Expand Up @@ -4654,6 +4665,73 @@ void java_nio_Buffer::serialize_offsets(SerializeClosure* f) {
}
#endif

#if INCLUDE_G1GC

// 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_G1GC

#define AOS_FIELDS_DO(macro) \
macro(_owner_offset, k, "exclusiveOwnerThread", thread_signature, false)

Expand Down
40 changes: 40 additions & 0 deletions src/hotspot/share/classfile/javaClasses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
f(com_alibaba_wisp_engine_WispControlGroup) \
f(com_alibaba_wisp_engine_WispControlGroup_CpuLimit) \
f(com_alibaba_rcm_AbstractResourceContainer) \
f(com_alibaba_tenant_TenantContainer) \
//end

#define BASIC_JAVA_CLASSES_DO(f) \
Expand Down Expand Up @@ -1553,6 +1554,45 @@ class java_util_concurrent_locks_AbstractOwnableSynchronizer : AllStatic {
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
};

#if INCLUDE_G1GC

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_G1GC

// 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/hotspot/share/classfile/vmSymbols.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1159,7 +1159,8 @@
do_intrinsic(_updateByteBufferCRC32, java_util_zip_CRC32, updateByteBuffer_name, updateByteBuffer_signature, F_SN) \
do_name( updateByteBuffer_name, "updateByteBuffer0") \
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/hotspot/share/gc/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/hotspot/share/gc/g1/g1AllocRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ void G1AllocRegion::update_alloc_region(HeapRegion* alloc_region) {
assert_alloc_region(alloc_region != NULL && !alloc_region->is_empty(), "pre-condition");

_alloc_region = alloc_region;
_alloc_region->set_allocation_context(allocation_context());
_count += 1;
trace("updated");
}
Expand Down Expand Up @@ -263,6 +264,16 @@ 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");
});

DEBUG_ONLY(if (TenantHeapIsolation) {
assert(alloc_region->allocation_context() == allocation_context(),
"Inconsistent allocation contexts");
});

_g1h->retire_mutator_alloc_region(alloc_region, allocated_bytes);
}

Expand Down Expand Up @@ -350,6 +361,10 @@ HeapRegion* G1GCAllocRegion::allocate_new_region(size_t word_size,

void G1GCAllocRegion::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_gc_alloc_region(alloc_region, allocated_bytes, _purpose);
}

Expand Down
16 changes: 16 additions & 0 deletions src/hotspot/share/gc/g1/g1AllocRegion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class G1AllocRegion {
// correct use of init() and release()).
HeapRegion* volatile _alloc_region;

// Allocation context associated with this alloc region.
AllocationContext_t _allocation_context;

// It keeps track of the distinct number of regions that are used
// for allocation in the active interval of this object, i.e.,
// between a call to init() and a call to release(). The count
Expand Down Expand Up @@ -142,6 +145,19 @@ class G1AllocRegion {
return (hr == _dummy_region) ? NULL : hr;
}

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; }

// The following two are the building blocks for the allocation method.
Expand Down
21 changes: 21 additions & 0 deletions src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size,
HeapRegion* alloc_region = _alloc_region;
assert_alloc_region(alloc_region != NULL, "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, min_word_size, desired_word_size, actual_word_size);
if (result != NULL) {
trace("alloc", min_word_size, desired_word_size, *actual_word_size, result);
Expand Down Expand Up @@ -110,6 +119,12 @@ inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t min_word_size,
result = new_alloc_region_and_allocate(desired_word_size, false /* force */);
if (result != NULL) {
*actual_word_size = desired_word_size;
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)", min_word_size, desired_word_size, *actual_word_size, result);
return result;
}
Expand All @@ -123,6 +138,12 @@ inline HeapWord* G1AllocRegion::attempt_allocation_force(size_t word_size) {
trace("forcing alloc", word_size, word_size);
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, word_size, word_size, result);
return result;
}
Expand Down
46 changes: 46 additions & 0 deletions src/hotspot/share/gc/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/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 dd5fd77

Please sign in to comment.