8267186: Add string deduplication support to ZGC
Reviewed-by: eosterlund, kbarrett, stefank
This commit is contained in:
parent
0d0f2d07f7
commit
abebbe2335
@ -116,7 +116,7 @@ size_t StringDedup::Config::desired_table_size(size_t entry_count) {
|
||||
bool StringDedup::Config::ergo_initialize() {
|
||||
if (!UseStringDeduplication) {
|
||||
return true;
|
||||
} else if (!UseG1GC && !UseShenandoahGC) {
|
||||
} else if (!UseG1GC && !UseShenandoahGC && !UseZGC) {
|
||||
// String deduplication requested but not supported by the selected GC.
|
||||
// Warn and force disable, but don't error except in debug build with
|
||||
// incorrect default.
|
||||
|
@ -24,8 +24,10 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "classfile/classLoaderDataGraph.hpp"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "gc/shared/gc_globals.hpp"
|
||||
#include "gc/shared/stringdedup/stringDedup.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "gc/z/zAbort.inline.hpp"
|
||||
#include "gc/z/zBarrier.inline.hpp"
|
||||
@ -33,6 +35,7 @@
|
||||
#include "gc/z/zLock.inline.hpp"
|
||||
#include "gc/z/zMark.inline.hpp"
|
||||
#include "gc/z/zMarkCache.inline.hpp"
|
||||
#include "gc/z/zMarkContext.inline.hpp"
|
||||
#include "gc/z/zMarkStack.inline.hpp"
|
||||
#include "gc/z/zMarkTerminate.inline.hpp"
|
||||
#include "gc/z/zNMethod.hpp"
|
||||
@ -279,7 +282,27 @@ void ZMark::follow_object(oop obj, bool finalizable) {
|
||||
}
|
||||
}
|
||||
|
||||
void ZMark::mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry) {
|
||||
static void try_deduplicate(ZMarkContext* context, oop obj) {
|
||||
if (!StringDedup::is_enabled()) {
|
||||
// Not enabled
|
||||
return;
|
||||
}
|
||||
|
||||
if (!java_lang_String::is_instance_inlined(obj)) {
|
||||
// Not a String object
|
||||
return;
|
||||
}
|
||||
|
||||
if (java_lang_String::test_and_set_deduplication_requested(obj)) {
|
||||
// Already requested deduplication
|
||||
return;
|
||||
}
|
||||
|
||||
// Request deduplication
|
||||
context->string_dedup_requests()->add(obj);
|
||||
}
|
||||
|
||||
void ZMark::mark_and_follow(ZMarkContext* context, ZMarkStackEntry entry) {
|
||||
// Decode flags
|
||||
const bool finalizable = entry.finalizable();
|
||||
const bool partial_array = entry.partial_array();
|
||||
@ -311,7 +334,7 @@ void ZMark::mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry) {
|
||||
// and alignment paddings can never be reclaimed.
|
||||
const size_t size = ZUtils::object_size(addr);
|
||||
const size_t aligned_size = align_up(size, page->object_alignment());
|
||||
cache->inc_live(page, aligned_size);
|
||||
context->cache()->inc_live(page, aligned_size);
|
||||
}
|
||||
|
||||
// Follow
|
||||
@ -319,18 +342,24 @@ void ZMark::mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry) {
|
||||
if (is_array(addr)) {
|
||||
follow_array_object(objArrayOop(ZOop::from_address(addr)), finalizable);
|
||||
} else {
|
||||
follow_object(ZOop::from_address(addr), finalizable);
|
||||
const oop obj = ZOop::from_address(addr);
|
||||
follow_object(obj, finalizable);
|
||||
|
||||
// Try deduplicate
|
||||
try_deduplicate(context, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ZMark::drain(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks, ZMarkCache* cache, T* timeout) {
|
||||
bool ZMark::drain(ZMarkContext* context, T* timeout) {
|
||||
ZMarkStripe* const stripe = context->stripe();
|
||||
ZMarkThreadLocalStacks* const stacks = context->stacks();
|
||||
ZMarkStackEntry entry;
|
||||
|
||||
// Drain stripe stacks
|
||||
while (stacks->pop(&_allocator, &_stripes, stripe, entry)) {
|
||||
mark_and_follow(cache, entry);
|
||||
mark_and_follow(context, entry);
|
||||
|
||||
// Check timeout
|
||||
if (timeout->has_expired()) {
|
||||
@ -343,7 +372,10 @@ bool ZMark::drain(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks, ZMarkCach
|
||||
return !timeout->has_expired();
|
||||
}
|
||||
|
||||
bool ZMark::try_steal_local(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
|
||||
bool ZMark::try_steal_local(ZMarkContext* context) {
|
||||
ZMarkStripe* const stripe = context->stripe();
|
||||
ZMarkThreadLocalStacks* const stacks = context->stacks();
|
||||
|
||||
// Try to steal a local stack from another stripe
|
||||
for (ZMarkStripe* victim_stripe = _stripes.stripe_next(stripe);
|
||||
victim_stripe != stripe;
|
||||
@ -360,7 +392,10 @@ bool ZMark::try_steal_local(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ZMark::try_steal_global(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
|
||||
bool ZMark::try_steal_global(ZMarkContext* context) {
|
||||
ZMarkStripe* const stripe = context->stripe();
|
||||
ZMarkThreadLocalStacks* const stacks = context->stacks();
|
||||
|
||||
// Try to steal a stack from another stripe
|
||||
for (ZMarkStripe* victim_stripe = _stripes.stripe_next(stripe);
|
||||
victim_stripe != stripe;
|
||||
@ -377,8 +412,8 @@ bool ZMark::try_steal_global(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ZMark::try_steal(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
|
||||
return try_steal_local(stripe, stacks) || try_steal_global(stripe, stacks);
|
||||
bool ZMark::try_steal(ZMarkContext* context) {
|
||||
return try_steal_local(context) || try_steal_global(context);
|
||||
}
|
||||
|
||||
void ZMark::idle() const {
|
||||
@ -496,17 +531,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void ZMark::work_without_timeout(ZMarkCache* cache, ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
|
||||
void ZMark::work_without_timeout(ZMarkContext* context) {
|
||||
ZStatTimer timer(ZSubPhaseConcurrentMark);
|
||||
ZMarkNoTimeout no_timeout;
|
||||
|
||||
for (;;) {
|
||||
if (!drain(stripe, stacks, cache, &no_timeout)) {
|
||||
if (!drain(context, &no_timeout)) {
|
||||
// Abort
|
||||
break;
|
||||
}
|
||||
|
||||
if (try_steal(stripe, stacks)) {
|
||||
if (try_steal(context)) {
|
||||
// Stole work
|
||||
continue;
|
||||
}
|
||||
@ -561,17 +596,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void ZMark::work_with_timeout(ZMarkCache* cache, ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks, uint64_t timeout_in_micros) {
|
||||
void ZMark::work_with_timeout(ZMarkContext* context, uint64_t timeout_in_micros) {
|
||||
ZStatTimer timer(ZSubPhaseMarkTryComplete);
|
||||
ZMarkTimeout timeout(timeout_in_micros);
|
||||
|
||||
for (;;) {
|
||||
if (!drain(stripe, stacks, cache, &timeout)) {
|
||||
if (!drain(context, &timeout)) {
|
||||
// Timed out
|
||||
break;
|
||||
}
|
||||
|
||||
if (try_steal(stripe, stacks)) {
|
||||
if (try_steal(context)) {
|
||||
// Stole work
|
||||
continue;
|
||||
}
|
||||
@ -582,14 +617,14 @@ void ZMark::work_with_timeout(ZMarkCache* cache, ZMarkStripe* stripe, ZMarkThrea
|
||||
}
|
||||
|
||||
void ZMark::work(uint64_t timeout_in_micros) {
|
||||
ZMarkCache cache(_stripes.nstripes());
|
||||
ZMarkStripe* const stripe = _stripes.stripe_for_worker(_nworkers, ZThread::worker_id());
|
||||
ZMarkThreadLocalStacks* const stacks = ZThreadLocalData::stacks(Thread::current());
|
||||
ZMarkContext context(_stripes.nstripes(), stripe, stacks);
|
||||
|
||||
if (timeout_in_micros == 0) {
|
||||
work_without_timeout(&cache, stripe, stacks);
|
||||
work_without_timeout(&context);
|
||||
} else {
|
||||
work_with_timeout(&cache, stripe, stacks, timeout_in_micros);
|
||||
work_with_timeout(&context, timeout_in_micros);
|
||||
}
|
||||
|
||||
// Flush and publish stacks
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class Thread;
|
||||
class ZMarkCache;
|
||||
class ZMarkContext;
|
||||
class ZPageTable;
|
||||
class ZWorkers;
|
||||
|
||||
@ -64,15 +64,12 @@ private:
|
||||
void follow_partial_array(ZMarkStackEntry entry, bool finalizable);
|
||||
void follow_array_object(objArrayOop obj, bool finalizable);
|
||||
void follow_object(oop obj, bool finalizable);
|
||||
void mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry);
|
||||
void mark_and_follow(ZMarkContext* context, ZMarkStackEntry entry);
|
||||
|
||||
template <typename T> bool drain(ZMarkStripe* stripe,
|
||||
ZMarkThreadLocalStacks* stacks,
|
||||
ZMarkCache* cache,
|
||||
T* timeout);
|
||||
bool try_steal_local(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks);
|
||||
bool try_steal_global(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks);
|
||||
bool try_steal(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks);
|
||||
template <typename T> bool drain(ZMarkContext* context, T* timeout);
|
||||
bool try_steal_local(ZMarkContext* context);
|
||||
bool try_steal_global(ZMarkContext* context);
|
||||
bool try_steal(ZMarkContext* context);
|
||||
void idle() const;
|
||||
bool flush(bool at_safepoint);
|
||||
bool try_proactive_flush();
|
||||
@ -84,13 +81,8 @@ private:
|
||||
void prepare_work();
|
||||
void finish_work();
|
||||
|
||||
void work_without_timeout(ZMarkCache* cache,
|
||||
ZMarkStripe* stripe,
|
||||
ZMarkThreadLocalStacks* stacks);
|
||||
void work_with_timeout(ZMarkCache* cache,
|
||||
ZMarkStripe* stripe,
|
||||
ZMarkThreadLocalStacks* stacks,
|
||||
uint64_t timeout_in_micros);
|
||||
void work_without_timeout(ZMarkContext* context);
|
||||
void work_with_timeout(ZMarkContext* context, uint64_t timeout_in_micros);
|
||||
void work(uint64_t timeout_in_micros);
|
||||
|
||||
void verify_all_stacks_empty() const;
|
||||
|
52
src/hotspot/share/gc/z/zMarkContext.hpp
Normal file
52
src/hotspot/share/gc/z/zMarkContext.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_Z_ZMARKCONTEXT_HPP
|
||||
#define SHARE_GC_Z_ZMARKCONTEXT_HPP
|
||||
|
||||
#include "gc/z/zMarkCache.hpp"
|
||||
#include "gc/shared/stringdedup/stringDedup.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class ZMarkStripe;
|
||||
class ZMarkThreadLocalStacks;
|
||||
|
||||
class ZMarkContext : public StackObj {
|
||||
private:
|
||||
ZMarkCache _cache;
|
||||
ZMarkStripe* const _stripe;
|
||||
ZMarkThreadLocalStacks* const _stacks;
|
||||
StringDedup::Requests _string_dedup_requests;
|
||||
|
||||
public:
|
||||
ZMarkContext(size_t nstripes,
|
||||
ZMarkStripe* stripe,
|
||||
ZMarkThreadLocalStacks* stacks);
|
||||
|
||||
ZMarkCache* cache();
|
||||
ZMarkStripe* stripe();
|
||||
ZMarkThreadLocalStacks* stacks();
|
||||
StringDedup::Requests* string_dedup_requests();
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_Z_ZMARKCONTEXT_HPP
|
53
src/hotspot/share/gc/z/zMarkContext.inline.hpp
Normal file
53
src/hotspot/share/gc/z/zMarkContext.inline.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_Z_ZMARKCONTEXT_INLINE_HPP
|
||||
#define SHARE_GC_Z_ZMARKCONTEXT_INLINE_HPP
|
||||
|
||||
#include "gc/z/zMarkContext.hpp"
|
||||
|
||||
inline ZMarkContext::ZMarkContext(size_t nstripes,
|
||||
ZMarkStripe* stripe,
|
||||
ZMarkThreadLocalStacks* stacks) :
|
||||
_cache(nstripes),
|
||||
_stripe(stripe),
|
||||
_stacks(stacks),
|
||||
_string_dedup_requests() {}
|
||||
|
||||
inline ZMarkCache* ZMarkContext::cache() {
|
||||
return &_cache;
|
||||
}
|
||||
|
||||
inline ZMarkStripe* ZMarkContext::stripe() {
|
||||
return _stripe;
|
||||
}
|
||||
|
||||
inline ZMarkThreadLocalStacks* ZMarkContext::stacks() {
|
||||
return _stacks;
|
||||
}
|
||||
|
||||
inline StringDedup::Requests* ZMarkContext::string_dedup_requests() {
|
||||
return &_string_dedup_requests;
|
||||
}
|
||||
|
||||
#endif // SHARE_GC_Z_ZMARKCACHE_INLINE_HPP
|
@ -49,6 +49,19 @@ package gc.stringdedup;
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationAgeThreshold Shenandoah
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestStringDeduplicationAgeThreshold
|
||||
* @summary Test string deduplication age threshold
|
||||
* @bug 8029075
|
||||
* @requires vm.gc.Z
|
||||
* @library /test/lib
|
||||
* @library /
|
||||
* @modules java.base/jdk.internal.misc:open
|
||||
* @modules java.base/java.lang:open
|
||||
* java.management
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationAgeThreshold Z
|
||||
*/
|
||||
|
||||
public class TestStringDeduplicationAgeThreshold {
|
||||
public static void main(String[] args) throws Exception {
|
||||
TestStringDeduplicationTools.selectGC(args);
|
||||
|
@ -49,6 +49,19 @@ package gc.stringdedup;
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationFullGC Shenandoah
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestStringDeduplicationFullGC
|
||||
* @summary Test string deduplication during full GC
|
||||
* @bug 8029075
|
||||
* @requires vm.gc.Z
|
||||
* @library /test/lib
|
||||
* @library /
|
||||
* @modules java.base/jdk.internal.misc:open
|
||||
* @modules java.base/java.lang:open
|
||||
* java.management
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationFullGC Z
|
||||
*/
|
||||
|
||||
public class TestStringDeduplicationFullGC {
|
||||
public static void main(String[] args) throws Exception {
|
||||
TestStringDeduplicationTools.selectGC(args);
|
||||
|
@ -36,6 +36,19 @@ package gc.stringdedup;
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationInterned G1
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestStringDeduplicationInterned
|
||||
* @summary Test string deduplication of interned strings
|
||||
* @bug 8029075
|
||||
* @requires vm.gc.Z
|
||||
* @library /test/lib
|
||||
* @library /
|
||||
* @modules java.base/jdk.internal.misc:open
|
||||
* @modules java.base/java.lang:open
|
||||
* java.management
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationInterned Z
|
||||
*/
|
||||
|
||||
public class TestStringDeduplicationInterned {
|
||||
public static void main(String[] args) throws Exception {
|
||||
TestStringDeduplicationTools.selectGC(args);
|
||||
|
@ -49,6 +49,19 @@ package gc.stringdedup;
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationPrintOptions Shenandoah
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestStringDeduplicationPrintOptions
|
||||
* @summary Test string deduplication print options
|
||||
* @bug 8029075
|
||||
* @requires vm.gc.Z
|
||||
* @library /test/lib
|
||||
* @library /
|
||||
* @modules java.base/jdk.internal.misc:open
|
||||
* @modules java.base/java.lang:open
|
||||
* java.management
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationPrintOptions Z
|
||||
*/
|
||||
|
||||
public class TestStringDeduplicationPrintOptions {
|
||||
public static void main(String[] args) throws Exception {
|
||||
TestStringDeduplicationTools.selectGC(args);
|
||||
|
@ -49,6 +49,19 @@ package gc.stringdedup;
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationTableResize Shenandoah
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestStringDeduplicationTableResize
|
||||
* @summary Test string deduplication table resize
|
||||
* @bug 8029075
|
||||
* @requires vm.gc.Z
|
||||
* @library /test/lib
|
||||
* @library /
|
||||
* @modules java.base/jdk.internal.misc:open
|
||||
* @modules java.base/java.lang:open
|
||||
* java.management
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationTableResize Z
|
||||
*/
|
||||
|
||||
public class TestStringDeduplicationTableResize {
|
||||
public static void main(String[] args) throws Exception {
|
||||
TestStringDeduplicationTools.selectGC(args);
|
||||
|
@ -49,6 +49,19 @@ package gc.stringdedup;
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationYoungGC Shenandoah
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestStringDeduplicationYoungGC
|
||||
* @summary Test string deduplication during young GC
|
||||
* @bug 8029075
|
||||
* @requires vm.gc.Z
|
||||
* @library /test/lib
|
||||
* @library /
|
||||
* @modules java.base/jdk.internal.misc:open
|
||||
* @modules java.base/java.lang:open
|
||||
* java.management
|
||||
* @run driver gc.stringdedup.TestStringDeduplicationYoungGC Z
|
||||
*/
|
||||
|
||||
public class TestStringDeduplicationYoungGC {
|
||||
public static void main(String[] args) throws Exception {
|
||||
TestStringDeduplicationTools.selectGC(args);
|
||||
|
Loading…
Reference in New Issue
Block a user