8267186: Add string deduplication support to ZGC

Reviewed-by: eosterlund, kbarrett, stefank
This commit is contained in:
Per Liden 2021-08-11 11:07:12 +00:00
parent 0d0f2d07f7
commit abebbe2335
11 changed files with 245 additions and 35 deletions

View File

@ -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.

View File

@ -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

View File

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

View 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

View 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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);