Skip to content

Commit

Permalink
8267186: Add string deduplication support to ZGC
Browse files Browse the repository at this point in the history
Reviewed-by: eosterlund, kbarrett, stefank
  • Loading branch information
pliden committed Aug 11, 2021
1 parent 0d0f2d0 commit abebbe2
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
71 changes: 53 additions & 18 deletions src/hotspot/share/gc/z/zMark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,18 @@
#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"
#include "gc/z/zHeap.inline.hpp"
#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"
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -311,26 +334,32 @@ 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
if (follow) {
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()) {
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -496,17 +531,17 @@ class ZMarkNoTimeout : public StackObj {
}
};

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;
}
Expand Down Expand Up @@ -561,17 +596,17 @@ class ZMarkTimeout : public StackObj {
}
};

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;
}
Expand All @@ -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
Expand Down
26 changes: 9 additions & 17 deletions src/hotspot/share/gc/z/zMark.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
#include "utilities/globalDefinitions.hpp"

class Thread;
class ZMarkCache;
class ZMarkContext;
class ZPageTable;
class ZWorkers;

Expand Down Expand Up @@ -64,15 +64,12 @@ class ZMark {
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);

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);
void mark_and_follow(ZMarkContext* context, ZMarkStackEntry entry);

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();
Expand All @@ -84,13 +81,8 @@ class ZMark {
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;
Expand Down
52 changes: 52 additions & 0 deletions src/hotspot/share/gc/z/zMarkContext.hpp
Original file line number Diff line number Diff line change
@@ -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 changes: 53 additions & 0 deletions src/hotspot/share/gc/z/zMarkContext.inline.hpp
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@
* @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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@
* @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);
Expand Down
Loading

1 comment on commit abebbe2

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.