Skip to content

Commit abebbe2

Browse files
committed
8267186: Add string deduplication support to ZGC
Reviewed-by: eosterlund, kbarrett, stefank
1 parent 0d0f2d0 commit abebbe2

11 files changed

+246
-36
lines changed

src/hotspot/share/gc/shared/stringdedup/stringDedupConfig.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ size_t StringDedup::Config::desired_table_size(size_t entry_count) {
116116
bool StringDedup::Config::ergo_initialize() {
117117
if (!UseStringDeduplication) {
118118
return true;
119-
} else if (!UseG1GC && !UseShenandoahGC) {
119+
} else if (!UseG1GC && !UseShenandoahGC && !UseZGC) {
120120
// String deduplication requested but not supported by the selected GC.
121121
// Warn and force disable, but don't error except in debug build with
122122
// incorrect default.

src/hotspot/share/gc/z/zMark.cpp

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,18 @@
2424
#include "precompiled.hpp"
2525
#include "classfile/classLoaderData.hpp"
2626
#include "classfile/classLoaderDataGraph.hpp"
27+
#include "classfile/javaClasses.inline.hpp"
2728
#include "code/nmethod.hpp"
2829
#include "gc/shared/gc_globals.hpp"
30+
#include "gc/shared/stringdedup/stringDedup.hpp"
2931
#include "gc/shared/suspendibleThreadSet.hpp"
3032
#include "gc/z/zAbort.inline.hpp"
3133
#include "gc/z/zBarrier.inline.hpp"
3234
#include "gc/z/zHeap.inline.hpp"
3335
#include "gc/z/zLock.inline.hpp"
3436
#include "gc/z/zMark.inline.hpp"
3537
#include "gc/z/zMarkCache.inline.hpp"
38+
#include "gc/z/zMarkContext.inline.hpp"
3639
#include "gc/z/zMarkStack.inline.hpp"
3740
#include "gc/z/zMarkTerminate.inline.hpp"
3841
#include "gc/z/zNMethod.hpp"
@@ -279,7 +282,27 @@ void ZMark::follow_object(oop obj, bool finalizable) {
279282
}
280283
}
281284

282-
void ZMark::mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry) {
285+
static void try_deduplicate(ZMarkContext* context, oop obj) {
286+
if (!StringDedup::is_enabled()) {
287+
// Not enabled
288+
return;
289+
}
290+
291+
if (!java_lang_String::is_instance_inlined(obj)) {
292+
// Not a String object
293+
return;
294+
}
295+
296+
if (java_lang_String::test_and_set_deduplication_requested(obj)) {
297+
// Already requested deduplication
298+
return;
299+
}
300+
301+
// Request deduplication
302+
context->string_dedup_requests()->add(obj);
303+
}
304+
305+
void ZMark::mark_and_follow(ZMarkContext* context, ZMarkStackEntry entry) {
283306
// Decode flags
284307
const bool finalizable = entry.finalizable();
285308
const bool partial_array = entry.partial_array();
@@ -311,26 +334,32 @@ void ZMark::mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry) {
311334
// and alignment paddings can never be reclaimed.
312335
const size_t size = ZUtils::object_size(addr);
313336
const size_t aligned_size = align_up(size, page->object_alignment());
314-
cache->inc_live(page, aligned_size);
337+
context->cache()->inc_live(page, aligned_size);
315338
}
316339

317340
// Follow
318341
if (follow) {
319342
if (is_array(addr)) {
320343
follow_array_object(objArrayOop(ZOop::from_address(addr)), finalizable);
321344
} else {
322-
follow_object(ZOop::from_address(addr), finalizable);
345+
const oop obj = ZOop::from_address(addr);
346+
follow_object(obj, finalizable);
347+
348+
// Try deduplicate
349+
try_deduplicate(context, obj);
323350
}
324351
}
325352
}
326353

327354
template <typename T>
328-
bool ZMark::drain(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks, ZMarkCache* cache, T* timeout) {
355+
bool ZMark::drain(ZMarkContext* context, T* timeout) {
356+
ZMarkStripe* const stripe = context->stripe();
357+
ZMarkThreadLocalStacks* const stacks = context->stacks();
329358
ZMarkStackEntry entry;
330359

331360
// Drain stripe stacks
332361
while (stacks->pop(&_allocator, &_stripes, stripe, entry)) {
333-
mark_and_follow(cache, entry);
362+
mark_and_follow(context, entry);
334363

335364
// Check timeout
336365
if (timeout->has_expired()) {
@@ -343,7 +372,10 @@ bool ZMark::drain(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks, ZMarkCach
343372
return !timeout->has_expired();
344373
}
345374

346-
bool ZMark::try_steal_local(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
375+
bool ZMark::try_steal_local(ZMarkContext* context) {
376+
ZMarkStripe* const stripe = context->stripe();
377+
ZMarkThreadLocalStacks* const stacks = context->stacks();
378+
347379
// Try to steal a local stack from another stripe
348380
for (ZMarkStripe* victim_stripe = _stripes.stripe_next(stripe);
349381
victim_stripe != stripe;
@@ -360,7 +392,10 @@ bool ZMark::try_steal_local(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks)
360392
return false;
361393
}
362394

363-
bool ZMark::try_steal_global(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
395+
bool ZMark::try_steal_global(ZMarkContext* context) {
396+
ZMarkStripe* const stripe = context->stripe();
397+
ZMarkThreadLocalStacks* const stacks = context->stacks();
398+
364399
// Try to steal a stack from another stripe
365400
for (ZMarkStripe* victim_stripe = _stripes.stripe_next(stripe);
366401
victim_stripe != stripe;
@@ -377,8 +412,8 @@ bool ZMark::try_steal_global(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks
377412
return false;
378413
}
379414

380-
bool ZMark::try_steal(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
381-
return try_steal_local(stripe, stacks) || try_steal_global(stripe, stacks);
415+
bool ZMark::try_steal(ZMarkContext* context) {
416+
return try_steal_local(context) || try_steal_global(context);
382417
}
383418

384419
void ZMark::idle() const {
@@ -496,17 +531,17 @@ class ZMarkNoTimeout : public StackObj {
496531
}
497532
};
498533

499-
void ZMark::work_without_timeout(ZMarkCache* cache, ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
534+
void ZMark::work_without_timeout(ZMarkContext* context) {
500535
ZStatTimer timer(ZSubPhaseConcurrentMark);
501536
ZMarkNoTimeout no_timeout;
502537

503538
for (;;) {
504-
if (!drain(stripe, stacks, cache, &no_timeout)) {
539+
if (!drain(context, &no_timeout)) {
505540
// Abort
506541
break;
507542
}
508543

509-
if (try_steal(stripe, stacks)) {
544+
if (try_steal(context)) {
510545
// Stole work
511546
continue;
512547
}
@@ -561,17 +596,17 @@ class ZMarkTimeout : public StackObj {
561596
}
562597
};
563598

564-
void ZMark::work_with_timeout(ZMarkCache* cache, ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks, uint64_t timeout_in_micros) {
599+
void ZMark::work_with_timeout(ZMarkContext* context, uint64_t timeout_in_micros) {
565600
ZStatTimer timer(ZSubPhaseMarkTryComplete);
566601
ZMarkTimeout timeout(timeout_in_micros);
567602

568603
for (;;) {
569-
if (!drain(stripe, stacks, cache, &timeout)) {
604+
if (!drain(context, &timeout)) {
570605
// Timed out
571606
break;
572607
}
573608

574-
if (try_steal(stripe, stacks)) {
609+
if (try_steal(context)) {
575610
// Stole work
576611
continue;
577612
}
@@ -582,14 +617,14 @@ void ZMark::work_with_timeout(ZMarkCache* cache, ZMarkStripe* stripe, ZMarkThrea
582617
}
583618

584619
void ZMark::work(uint64_t timeout_in_micros) {
585-
ZMarkCache cache(_stripes.nstripes());
586620
ZMarkStripe* const stripe = _stripes.stripe_for_worker(_nworkers, ZThread::worker_id());
587621
ZMarkThreadLocalStacks* const stacks = ZThreadLocalData::stacks(Thread::current());
622+
ZMarkContext context(_stripes.nstripes(), stripe, stacks);
588623

589624
if (timeout_in_micros == 0) {
590-
work_without_timeout(&cache, stripe, stacks);
625+
work_without_timeout(&context);
591626
} else {
592-
work_with_timeout(&cache, stripe, stacks, timeout_in_micros);
627+
work_with_timeout(&context, timeout_in_micros);
593628
}
594629

595630
// Flush and publish stacks

src/hotspot/share/gc/z/zMark.hpp

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#include "utilities/globalDefinitions.hpp"
3333

3434
class Thread;
35-
class ZMarkCache;
35+
class ZMarkContext;
3636
class ZPageTable;
3737
class ZWorkers;
3838

@@ -64,15 +64,12 @@ class ZMark {
6464
void follow_partial_array(ZMarkStackEntry entry, bool finalizable);
6565
void follow_array_object(objArrayOop obj, bool finalizable);
6666
void follow_object(oop obj, bool finalizable);
67-
void mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry);
68-
69-
template <typename T> bool drain(ZMarkStripe* stripe,
70-
ZMarkThreadLocalStacks* stacks,
71-
ZMarkCache* cache,
72-
T* timeout);
73-
bool try_steal_local(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks);
74-
bool try_steal_global(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks);
75-
bool try_steal(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks);
67+
void mark_and_follow(ZMarkContext* context, ZMarkStackEntry entry);
68+
69+
template <typename T> bool drain(ZMarkContext* context, T* timeout);
70+
bool try_steal_local(ZMarkContext* context);
71+
bool try_steal_global(ZMarkContext* context);
72+
bool try_steal(ZMarkContext* context);
7673
void idle() const;
7774
bool flush(bool at_safepoint);
7875
bool try_proactive_flush();
@@ -84,13 +81,8 @@ class ZMark {
8481
void prepare_work();
8582
void finish_work();
8683

87-
void work_without_timeout(ZMarkCache* cache,
88-
ZMarkStripe* stripe,
89-
ZMarkThreadLocalStacks* stacks);
90-
void work_with_timeout(ZMarkCache* cache,
91-
ZMarkStripe* stripe,
92-
ZMarkThreadLocalStacks* stacks,
93-
uint64_t timeout_in_micros);
84+
void work_without_timeout(ZMarkContext* context);
85+
void work_with_timeout(ZMarkContext* context, uint64_t timeout_in_micros);
9486
void work(uint64_t timeout_in_micros);
9587

9688
void verify_all_stacks_empty() const;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
#ifndef SHARE_GC_Z_ZMARKCONTEXT_HPP
25+
#define SHARE_GC_Z_ZMARKCONTEXT_HPP
26+
27+
#include "gc/z/zMarkCache.hpp"
28+
#include "gc/shared/stringdedup/stringDedup.hpp"
29+
#include "memory/allocation.hpp"
30+
31+
class ZMarkStripe;
32+
class ZMarkThreadLocalStacks;
33+
34+
class ZMarkContext : public StackObj {
35+
private:
36+
ZMarkCache _cache;
37+
ZMarkStripe* const _stripe;
38+
ZMarkThreadLocalStacks* const _stacks;
39+
StringDedup::Requests _string_dedup_requests;
40+
41+
public:
42+
ZMarkContext(size_t nstripes,
43+
ZMarkStripe* stripe,
44+
ZMarkThreadLocalStacks* stacks);
45+
46+
ZMarkCache* cache();
47+
ZMarkStripe* stripe();
48+
ZMarkThreadLocalStacks* stacks();
49+
StringDedup::Requests* string_dedup_requests();
50+
};
51+
52+
#endif // SHARE_GC_Z_ZMARKCONTEXT_HPP
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
#ifndef SHARE_GC_Z_ZMARKCONTEXT_INLINE_HPP
25+
#define SHARE_GC_Z_ZMARKCONTEXT_INLINE_HPP
26+
27+
#include "gc/z/zMarkContext.hpp"
28+
29+
inline ZMarkContext::ZMarkContext(size_t nstripes,
30+
ZMarkStripe* stripe,
31+
ZMarkThreadLocalStacks* stacks) :
32+
_cache(nstripes),
33+
_stripe(stripe),
34+
_stacks(stacks),
35+
_string_dedup_requests() {}
36+
37+
inline ZMarkCache* ZMarkContext::cache() {
38+
return &_cache;
39+
}
40+
41+
inline ZMarkStripe* ZMarkContext::stripe() {
42+
return _stripe;
43+
}
44+
45+
inline ZMarkThreadLocalStacks* ZMarkContext::stacks() {
46+
return _stacks;
47+
}
48+
49+
inline StringDedup::Requests* ZMarkContext::string_dedup_requests() {
50+
return &_string_dedup_requests;
51+
}
52+
53+
#endif // SHARE_GC_Z_ZMARKCACHE_INLINE_HPP

test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationAgeThreshold.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@
4949
* @run driver gc.stringdedup.TestStringDeduplicationAgeThreshold Shenandoah
5050
*/
5151

52+
/*
53+
* @test TestStringDeduplicationAgeThreshold
54+
* @summary Test string deduplication age threshold
55+
* @bug 8029075
56+
* @requires vm.gc.Z
57+
* @library /test/lib
58+
* @library /
59+
* @modules java.base/jdk.internal.misc:open
60+
* @modules java.base/java.lang:open
61+
* java.management
62+
* @run driver gc.stringdedup.TestStringDeduplicationAgeThreshold Z
63+
*/
64+
5265
public class TestStringDeduplicationAgeThreshold {
5366
public static void main(String[] args) throws Exception {
5467
TestStringDeduplicationTools.selectGC(args);

test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationFullGC.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@
4949
* @run driver gc.stringdedup.TestStringDeduplicationFullGC Shenandoah
5050
*/
5151

52+
/*
53+
* @test TestStringDeduplicationFullGC
54+
* @summary Test string deduplication during full GC
55+
* @bug 8029075
56+
* @requires vm.gc.Z
57+
* @library /test/lib
58+
* @library /
59+
* @modules java.base/jdk.internal.misc:open
60+
* @modules java.base/java.lang:open
61+
* java.management
62+
* @run driver gc.stringdedup.TestStringDeduplicationFullGC Z
63+
*/
64+
5265
public class TestStringDeduplicationFullGC {
5366
public static void main(String[] args) throws Exception {
5467
TestStringDeduplicationTools.selectGC(args);

0 commit comments

Comments
 (0)