8252660: Shenandoah: support manageable SoftMaxHeapSize option

Reviewed-by: zgu
This commit is contained in:
Aleksey Shipilev 2020-09-02 18:37:31 +02:00
parent 261eb76ea2
commit c61204b3f3
11 changed files with 314 additions and 33 deletions

View file

@ -60,7 +60,7 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand
// we hit max_cset. When max_cset is hit, we terminate the cset selection. Note that in this scheme, // we hit max_cset. When max_cset is hit, we terminate the cset selection. Note that in this scheme,
// ShenandoahGarbageThreshold is the soft threshold which would be ignored until min_garbage is hit. // ShenandoahGarbageThreshold is the soft threshold which would be ignored until min_garbage is hit.
size_t capacity = ShenandoahHeap::heap()->max_capacity(); size_t capacity = ShenandoahHeap::heap()->soft_max_capacity();
size_t max_cset = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste); size_t max_cset = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste);
size_t free_target = (capacity / 100 * ShenandoahMinFreeThreshold) + max_cset; size_t free_target = (capacity / 100 * ShenandoahMinFreeThreshold) + max_cset;
size_t min_garbage = (free_target > actual_free ? (free_target - actual_free) : 0); size_t min_garbage = (free_target > actual_free ? (free_target - actual_free) : 0);
@ -102,9 +102,14 @@ void ShenandoahAdaptiveHeuristics::record_cycle_start() {
bool ShenandoahAdaptiveHeuristics::should_start_gc() const { bool ShenandoahAdaptiveHeuristics::should_start_gc() const {
ShenandoahHeap* heap = ShenandoahHeap::heap(); ShenandoahHeap* heap = ShenandoahHeap::heap();
size_t capacity = heap->max_capacity(); size_t max_capacity = heap->max_capacity();
size_t capacity = heap->soft_max_capacity();
size_t available = heap->free_set()->available(); size_t available = heap->free_set()->available();
// Make sure the code below treats available without the soft tail.
size_t soft_tail = max_capacity - capacity;
available = (available > soft_tail) ? (available - soft_tail) : 0;
// Check if we are falling below the worst limit, time to trigger the GC, regardless of // Check if we are falling below the worst limit, time to trigger the GC, regardless of
// anything else. // anything else.
size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold; size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold;

View file

@ -47,9 +47,14 @@ ShenandoahCompactHeuristics::ShenandoahCompactHeuristics() : ShenandoahHeuristic
bool ShenandoahCompactHeuristics::should_start_gc() const { bool ShenandoahCompactHeuristics::should_start_gc() const {
ShenandoahHeap* heap = ShenandoahHeap::heap(); ShenandoahHeap* heap = ShenandoahHeap::heap();
size_t capacity = heap->max_capacity(); size_t max_capacity = heap->max_capacity();
size_t capacity = heap->soft_max_capacity();
size_t available = heap->free_set()->available(); size_t available = heap->free_set()->available();
// Make sure the code below treats available without the soft tail.
size_t soft_tail = max_capacity - capacity;
available = (available > soft_tail) ? (available - soft_tail) : 0;
size_t threshold_bytes_allocated = capacity / 100 * ShenandoahAllocationThreshold; size_t threshold_bytes_allocated = capacity / 100 * ShenandoahAllocationThreshold;
size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold; size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold;

View file

@ -58,8 +58,8 @@ void ShenandoahPassiveHeuristics::choose_collection_set_from_regiondata(Shenando
// Do not select too large CSet that would overflow the available free space. // Do not select too large CSet that would overflow the available free space.
// Take at least the entire evacuation reserve, and be free to overflow to free space. // Take at least the entire evacuation reserve, and be free to overflow to free space.
size_t capacity = ShenandoahHeap::heap()->max_capacity(); size_t max_capacity = ShenandoahHeap::heap()->max_capacity();
size_t available = MAX2(capacity / 100 * ShenandoahEvacReserve, actual_free); size_t available = MAX2(max_capacity / 100 * ShenandoahEvacReserve, actual_free);
size_t max_cset = (size_t)(available / ShenandoahEvacWaste); size_t max_cset = (size_t)(available / ShenandoahEvacWaste);
log_info(gc, ergo)("CSet Selection. Actual Free: " SIZE_FORMAT "%s, Max CSet: " SIZE_FORMAT "%s", log_info(gc, ergo)("CSet Selection. Actual Free: " SIZE_FORMAT "%s, Max CSet: " SIZE_FORMAT "%s",

View file

@ -42,8 +42,14 @@ ShenandoahStaticHeuristics::~ShenandoahStaticHeuristics() {}
bool ShenandoahStaticHeuristics::should_start_gc() const { bool ShenandoahStaticHeuristics::should_start_gc() const {
ShenandoahHeap* heap = ShenandoahHeap::heap(); ShenandoahHeap* heap = ShenandoahHeap::heap();
size_t capacity = heap->max_capacity(); size_t max_capacity = heap->max_capacity();
size_t capacity = heap->soft_max_capacity();
size_t available = heap->free_set()->available(); size_t available = heap->free_set()->available();
// Make sure the code below treats available without the soft tail.
size_t soft_tail = max_capacity - capacity;
available = (available > soft_tail) ? (available - soft_tail) : 0;
size_t threshold_available = capacity / 100 * ShenandoahMinFreeThreshold; size_t threshold_available = capacity / 100 * ShenandoahMinFreeThreshold;
if (available < threshold_available) { if (available < threshold_available) {

View file

@ -103,6 +103,9 @@ void ShenandoahControlThread::run_service() {
// This control loop iteration have seen this much allocations. // This control loop iteration have seen this much allocations.
size_t allocs_seen = Atomic::xchg(&_allocs_seen, (size_t)0); size_t allocs_seen = Atomic::xchg(&_allocs_seen, (size_t)0);
// Check if we have seen a new target for soft max heap size.
bool soft_max_changed = check_soft_max_changed();
// Choose which GC mode to run in. The block below should select a single mode. // Choose which GC mode to run in. The block below should select a single mode.
GCMode mode = none; GCMode mode = none;
GCCause::Cause cause = GCCause::_last_gc_cause; GCCause::Cause cause = GCCause::_last_gc_cause;
@ -291,13 +294,20 @@ void ShenandoahControlThread::run_service() {
double current = os::elapsedTime(); double current = os::elapsedTime();
if (ShenandoahUncommit && (explicit_gc_requested || (current - last_shrink_time > shrink_period))) { if (ShenandoahUncommit && (explicit_gc_requested || soft_max_changed || (current - last_shrink_time > shrink_period))) {
// Try to uncommit enough stale regions. Explicit GC tries to uncommit everything. // Explicit GC tries to uncommit everything down to min capacity.
// Regular paths uncommit only occasionally. // Soft max change tries to uncommit everything down to target capacity.
double shrink_before = explicit_gc_requested ? // Periodic uncommit tries to uncommit suitable regions down to min capacity.
double shrink_before = (explicit_gc_requested || soft_max_changed) ?
current : current :
current - (ShenandoahUncommitDelay / 1000.0); current - (ShenandoahUncommitDelay / 1000.0);
service_uncommit(shrink_before);
size_t shrink_until = soft_max_changed ?
heap->soft_max_capacity() :
heap->min_capacity();
service_uncommit(shrink_before, shrink_until);
heap->phase_timings()->flush_cycle_to_global(); heap->phase_timings()->flush_cycle_to_global();
last_shrink_time = current; last_shrink_time = current;
} }
@ -320,6 +330,25 @@ void ShenandoahControlThread::run_service() {
} }
} }
bool ShenandoahControlThread::check_soft_max_changed() const {
ShenandoahHeap* heap = ShenandoahHeap::heap();
size_t new_soft_max = Atomic::load(&SoftMaxHeapSize);
size_t old_soft_max = heap->soft_max_capacity();
if (new_soft_max != old_soft_max) {
new_soft_max = MAX2(heap->min_capacity(), new_soft_max);
new_soft_max = MIN2(heap->max_capacity(), new_soft_max);
if (new_soft_max != old_soft_max) {
log_info(gc)("Soft Max Heap Size: " SIZE_FORMAT "%s -> " SIZE_FORMAT "%s",
byte_size_in_proper_unit(old_soft_max), proper_unit_for_byte_size(old_soft_max),
byte_size_in_proper_unit(new_soft_max), proper_unit_for_byte_size(new_soft_max)
);
heap->set_soft_max_capacity(new_soft_max);
return true;
}
}
return false;
}
void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cause) { void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cause) {
// Normal cycle goes via all concurrent phases. If allocation failure (af) happens during // Normal cycle goes via all concurrent phases. If allocation failure (af) happens during
// any of the concurrent phases, it first degrades to Degenerated GC and completes GC there. // any of the concurrent phases, it first degrades to Degenerated GC and completes GC there.
@ -479,14 +508,14 @@ void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause
heap->shenandoah_policy()->record_success_degenerated(); heap->shenandoah_policy()->record_success_degenerated();
} }
void ShenandoahControlThread::service_uncommit(double shrink_before) { void ShenandoahControlThread::service_uncommit(double shrink_before, size_t shrink_until) {
ShenandoahHeap* heap = ShenandoahHeap::heap(); ShenandoahHeap* heap = ShenandoahHeap::heap();
// Determine if there is work to do. This avoids taking heap lock if there is // Determine if there is work to do. This avoids taking heap lock if there is
// no work available, avoids spamming logs with superfluous logging messages, // no work available, avoids spamming logs with superfluous logging messages,
// and minimises the amount of work while locks are taken. // and minimises the amount of work while locks are taken.
if (heap->committed() <= heap->min_capacity()) return; if (heap->committed() <= shrink_until) return;
bool has_work = false; bool has_work = false;
for (size_t i = 0; i < heap->num_regions(); i++) { for (size_t i = 0; i < heap->num_regions(); i++) {
@ -498,7 +527,7 @@ void ShenandoahControlThread::service_uncommit(double shrink_before) {
} }
if (has_work) { if (has_work) {
heap->entry_uncommit(shrink_before); heap->entry_uncommit(shrink_before, shrink_until);
} }
} }

View file

@ -103,7 +103,7 @@ private:
void service_concurrent_normal_cycle(GCCause::Cause cause); void service_concurrent_normal_cycle(GCCause::Cause cause);
void service_stw_full_cycle(GCCause::Cause cause); void service_stw_full_cycle(GCCause::Cause cause);
void service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahHeap::ShenandoahDegenPoint point); void service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahHeap::ShenandoahDegenPoint point);
void service_uncommit(double shrink_before); void service_uncommit(double shrink_before, size_t shrink_until);
bool try_set_alloc_failure_gc(); bool try_set_alloc_failure_gc();
void notify_alloc_failure_waiters(); void notify_alloc_failure_waiters();
@ -120,6 +120,9 @@ private:
void handle_requested_gc(GCCause::Cause cause); void handle_requested_gc(GCCause::Cause cause);
bool is_explicit_gc(GCCause::Cause cause) const; bool is_explicit_gc(GCCause::Cause cause) const;
bool check_soft_max_changed() const;
public: public:
// Constructor // Constructor
ShenandoahControlThread(); ShenandoahControlThread();

View file

@ -163,6 +163,9 @@ jint ShenandoahHeap::initialize() {
assert(num_min_regions <= _num_regions, "sanity"); assert(num_min_regions <= _num_regions, "sanity");
_minimum_size = num_min_regions * reg_size_bytes; _minimum_size = num_min_regions * reg_size_bytes;
// Default to max heap size.
_soft_max_size = _num_regions * reg_size_bytes;
_committed = _initial_size; _committed = _initial_size;
size_t heap_page_size = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size(); size_t heap_page_size = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size();
@ -538,8 +541,9 @@ void ShenandoahHeap::reset_mark_bitmap() {
void ShenandoahHeap::print_on(outputStream* st) const { void ShenandoahHeap::print_on(outputStream* st) const {
st->print_cr("Shenandoah Heap"); st->print_cr("Shenandoah Heap");
st->print_cr(" " SIZE_FORMAT "%s total, " SIZE_FORMAT "%s committed, " SIZE_FORMAT "%s used", st->print_cr(" " SIZE_FORMAT "%s max, " SIZE_FORMAT "%s soft max, " SIZE_FORMAT "%s committed, " SIZE_FORMAT "%s used",
byte_size_in_proper_unit(max_capacity()), proper_unit_for_byte_size(max_capacity()), byte_size_in_proper_unit(max_capacity()), proper_unit_for_byte_size(max_capacity()),
byte_size_in_proper_unit(soft_max_capacity()), proper_unit_for_byte_size(soft_max_capacity()),
byte_size_in_proper_unit(committed()), proper_unit_for_byte_size(committed()), byte_size_in_proper_unit(committed()), proper_unit_for_byte_size(committed()),
byte_size_in_proper_unit(used()), proper_unit_for_byte_size(used())); byte_size_in_proper_unit(used()), proper_unit_for_byte_size(used()));
st->print_cr(" " SIZE_FORMAT " x " SIZE_FORMAT"%s regions", st->print_cr(" " SIZE_FORMAT " x " SIZE_FORMAT"%s regions",
@ -676,6 +680,21 @@ size_t ShenandoahHeap::max_capacity() const {
return _num_regions * ShenandoahHeapRegion::region_size_bytes(); return _num_regions * ShenandoahHeapRegion::region_size_bytes();
} }
size_t ShenandoahHeap::soft_max_capacity() const {
size_t v = Atomic::load(&_soft_max_size);
assert(min_capacity() <= v && v <= max_capacity(),
"Should be in bounds: " SIZE_FORMAT " <= " SIZE_FORMAT " <= " SIZE_FORMAT,
min_capacity(), v, max_capacity());
return v;
}
void ShenandoahHeap::set_soft_max_capacity(size_t v) {
assert(min_capacity() <= v && v <= max_capacity(),
"Should be in bounds: " SIZE_FORMAT " <= " SIZE_FORMAT " <= " SIZE_FORMAT,
min_capacity(), v, max_capacity());
Atomic::store(&_soft_max_size, v);
}
size_t ShenandoahHeap::min_capacity() const { size_t ShenandoahHeap::min_capacity() const {
return _minimum_size; return _minimum_size;
} }
@ -690,7 +709,7 @@ bool ShenandoahHeap::is_in(const void* p) const {
return p >= heap_base && p < last_region_end; return p >= heap_base && p < last_region_end;
} }
void ShenandoahHeap::op_uncommit(double shrink_before) { void ShenandoahHeap::op_uncommit(double shrink_before, size_t shrink_until) {
assert (ShenandoahUncommit, "should be enabled"); assert (ShenandoahUncommit, "should be enabled");
// Application allocates from the beginning of the heap, and GC allocates at // Application allocates from the beginning of the heap, and GC allocates at
@ -704,8 +723,7 @@ void ShenandoahHeap::op_uncommit(double shrink_before) {
if (r->is_empty_committed() && (r->empty_time() < shrink_before)) { if (r->is_empty_committed() && (r->empty_time() < shrink_before)) {
ShenandoahHeapLocker locker(lock()); ShenandoahHeapLocker locker(lock());
if (r->is_empty_committed()) { if (r->is_empty_committed()) {
// Do not uncommit below minimal capacity if (committed() < shrink_until + ShenandoahHeapRegion::region_size_bytes()) {
if (committed() < min_capacity() + ShenandoahHeapRegion::region_size_bytes()) {
break; break;
} }
@ -2960,12 +2978,12 @@ void ShenandoahHeap::entry_preclean() {
} }
} }
void ShenandoahHeap::entry_uncommit(double shrink_before) { void ShenandoahHeap::entry_uncommit(double shrink_before, size_t shrink_until) {
static const char *msg = "Concurrent uncommit"; static const char *msg = "Concurrent uncommit";
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_uncommit, true /* log_heap_usage */); ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_uncommit, true /* log_heap_usage */);
EventMark em("%s", msg); EventMark em("%s", msg);
op_uncommit(shrink_before); op_uncommit(shrink_before, shrink_until);
} }
void ShenandoahHeap::try_inject_alloc_failure() { void ShenandoahHeap::try_inject_alloc_failure() {

View file

@ -158,6 +158,7 @@ public:
private: private:
size_t _initial_size; size_t _initial_size;
size_t _minimum_size; size_t _minimum_size;
volatile size_t _soft_max_size;
shenandoah_padding(0); shenandoah_padding(0);
volatile size_t _used; volatile size_t _used;
volatile size_t _committed; volatile size_t _committed;
@ -178,11 +179,14 @@ public:
size_t min_capacity() const; size_t min_capacity() const;
size_t max_capacity() const; size_t max_capacity() const;
size_t soft_max_capacity() const;
size_t initial_capacity() const; size_t initial_capacity() const;
size_t capacity() const; size_t capacity() const;
size_t used() const; size_t used() const;
size_t committed() const; size_t committed() const;
void set_soft_max_capacity(size_t v);
// ---------- Workers handling // ---------- Workers handling
// //
private: private:
@ -390,7 +394,7 @@ public:
void entry_evac(); void entry_evac();
void entry_updaterefs(); void entry_updaterefs();
void entry_cleanup_complete(); void entry_cleanup_complete();
void entry_uncommit(double shrink_before); void entry_uncommit(double shrink_before, size_t shrink_until);
private: private:
// Actual work for the phases // Actual work for the phases
@ -415,7 +419,7 @@ private:
void op_stw_evac(); void op_stw_evac();
void op_updaterefs(); void op_updaterefs();
void op_cleanup_complete(); void op_cleanup_complete();
void op_uncommit(double shrink_before); void op_uncommit(double shrink_before, size_t shrink_until);
void rendezvous_threads(); void rendezvous_threads();

View file

@ -106,26 +106,26 @@
"How much heap should be free before some heuristics trigger the "\ "How much heap should be free before some heuristics trigger the "\
"initial (learning) cycles. Affects cycle frequency on startup " \ "initial (learning) cycles. Affects cycle frequency on startup " \
"and after drastic state changes, e.g. after degenerated/full " \ "and after drastic state changes, e.g. after degenerated/full " \
"GC cycles. In percents of total heap size.") \ "GC cycles. In percents of (soft) max heap size.") \
range(0,100) \ range(0,100) \
\ \
experimental(uintx, ShenandoahMinFreeThreshold, 10, \ experimental(uintx, ShenandoahMinFreeThreshold, 10, \
"How much heap should be free before most heuristics trigger the "\ "How much heap should be free before most heuristics trigger the "\
"collection, even without other triggers. Provides the safety " \ "collection, even without other triggers. Provides the safety " \
"margin for many heuristics. In percents of total heap size.") \ "margin for many heuristics. In percents of (soft) max heap size.")\
range(0,100) \ range(0,100) \
\ \
experimental(uintx, ShenandoahAllocationThreshold, 0, \ experimental(uintx, ShenandoahAllocationThreshold, 0, \
"How many new allocations should happen since the last GC cycle " \ "How many new allocations should happen since the last GC cycle " \
"before some heuristics trigger the collection. In percents of " \ "before some heuristics trigger the collection. In percents of " \
"total heap size. Set to zero to effectively disable.") \ "(soft) max heap size. Set to zero to effectively disable.") \
range(0,100) \ range(0,100) \
\ \
experimental(uintx, ShenandoahAllocSpikeFactor, 5, \ experimental(uintx, ShenandoahAllocSpikeFactor, 5, \
"How much of heap should some heuristics reserve for absorbing " \ "How much of heap should some heuristics reserve for absorbing " \
"the allocation spikes. Larger value wastes more memory in " \ "the allocation spikes. Larger value wastes more memory in " \
"non-emergency cases, but provides more safety in emergency " \ "non-emergency cases, but provides more safety in emergency " \
"cases. In percents of total heap size.") \ "cases. In percents of (soft) max heap size.") \
range(0,100) \ range(0,100) \
\ \
experimental(uintx, ShenandoahLearningSteps, 5, \ experimental(uintx, ShenandoahLearningSteps, 5, \

View file

@ -0,0 +1,137 @@
/*
* Copyright (c) 2020, Red Hat, Inc. 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.
*
*/
/*
* @test TestDynamicSoftMaxHeapSize
* @requires vm.gc.Shenandoah & !vm.graal.enabled
* @library /test/lib
*
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
* -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive
* -XX:+ShenandoahDegeneratedGC
* -Dtarget=10000
* TestDynamicSoftMaxHeapSize
*
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
* -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive
* -XX:-ShenandoahDegeneratedGC
* -Dtarget=10000
* TestDynamicSoftMaxHeapSize
*/
/*
* @test TestDynamicSoftMaxHeapSize
* @requires vm.gc.Shenandoah & !vm.graal.enabled
* @library /test/lib
*
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
* -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive
* -Dtarget=1000
* TestDynamicSoftMaxHeapSize
*/
/*
* @test TestDynamicSoftMaxHeapSize
* @requires vm.gc.Shenandoah & !vm.graal.enabled
* @library /test/lib
*
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
* -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive
* -Dtarget=10000
* TestDynamicSoftMaxHeapSize
*/
/*
* @test TestDynamicSoftMaxHeapSize
* @requires vm.gc.Shenandoah & !vm.graal.enabled
* @library /test/lib
*
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
* -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=static
* -Dtarget=10000
* TestDynamicSoftMaxHeapSize
*/
/*
* @test TestDynamicSoftMaxHeapSize
* @requires vm.gc.Shenandoah & !vm.graal.enabled
* @library /test/lib
*
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
* -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact
* -Dtarget=1000
* TestDynamicSoftMaxHeapSize
*/
/*
* @test TestDynamicSoftMaxHeapSize
* @requires vm.gc.Shenandoah & !vm.graal.enabled
* @library /test/lib
*
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
* -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
* -Dtarget=1000
* TestDynamicSoftMaxHeapSize
*/
/*
* @test TestDynamicSoftMaxHeapSize
* @requires vm.gc.Shenandoah & !vm.graal.enabled
* @library /test/lib
*
* @run main/othervm -Xms16m -Xmx512m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
* -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
* -Dtarget=10000
* TestDynamicSoftMaxHeapSize
*/
import java.util.Random;
import jdk.test.lib.Utils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.dcmd.PidJcmdExecutor;
public class TestDynamicSoftMaxHeapSize {
static final long TARGET_MB = Long.getLong("target", 10_000); // 10 Gb allocation
static final long STRIDE = 10_000_000;
static volatile Object sink;
public static void main(String[] args) throws Exception {
long count = TARGET_MB * 1024 * 1024 / 16;
Random r = Utils.getRandomInstance();
PidJcmdExecutor jcmd = new PidJcmdExecutor();
for (long c = 0; c < count; c += STRIDE) {
// Sizes specifically include heaps below Xms and above Xmx to test saturation code.
jcmd.execute("VM.set_flag SoftMaxHeapSize " + r.nextInt(768*1024*1024), true);
for (long s = 0; s < STRIDE; s++) {
sink = new Object();
}
Thread.sleep(1);
}
}
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2020, Red Hat, Inc. 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.
*
*/
/*
* @test TestSoftMaxHeapSize
* @summary Test that Shenandoah checks SoftMaxHeapSize
* @requires vm.gc.Shenandoah & !vm.graal.enabled
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.management
* @run driver TestSoftMaxHeapSize
*/
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
public class TestSoftMaxHeapSize {
public static void main(String[] args) throws Exception {
{
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions",
"-XX:+UseShenandoahGC",
"-Xms4m",
"-Xmx128m",
"-XX:SoftMaxHeapSize=4m",
"-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
}
{
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions",
"-XX:+UseShenandoahGC",
"-Xms4m",
"-Xmx128m",
"-XX:SoftMaxHeapSize=128m",
"-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
}
{
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockExperimentalVMOptions",
"-XX:+UseShenandoahGC",
"-Xms4m",
"-Xmx128m",
"-XX:SoftMaxHeapSize=129m",
"-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(1);
output.shouldContain("SoftMaxHeapSize must be less than or equal to the maximum heap size");
}
}
}