--- old/src/hotspot/os/linux/os_linux.cpp 2018-10-03 14:35:19.382840700 -0700 +++ new/src/hotspot/os/linux/os_linux.cpp 2018-10-03 14:35:18.422330700 -0700 @@ -5065,7 +5065,7 @@ // initialize thread priority policy prio_init(); - if (!FLAG_IS_DEFAULT(AllocateHeapAt)) { + if (!FLAG_IS_DEFAULT(AllocateHeapAt) || !FLAG_IS_DEFAULT(AllocateOldGenAt)) { set_coredump_filter(false /*largepages*/, true /*dax_shared*/); } return JNI_OK; --- old/src/hotspot/share/gc/parallel/adjoiningGenerations.cpp 2018-10-03 14:35:32.129335100 -0700 +++ new/src/hotspot/share/gc/parallel/adjoiningGenerations.cpp 2018-10-03 14:35:31.214458800 -0700 @@ -40,8 +40,8 @@ AdjoiningGenerations::AdjoiningGenerations(ReservedSpace old_young_rs, GenerationSizer* policy, size_t alignment) : - _virtual_spaces(old_young_rs, policy->min_old_size(), - policy->min_young_size(), alignment) { + _virtual_spaces(new AdjoiningVirtualSpaces(old_young_rs, policy->min_old_size(), + policy->min_young_size(), alignment)) { size_t init_low_byte_size = policy->initial_old_size(); size_t min_low_byte_size = policy->min_old_size(); size_t max_low_byte_size = policy->max_old_size(); @@ -61,21 +61,21 @@ // generation. // Does the actual creation of the virtual spaces - _virtual_spaces.initialize(max_low_byte_size, - init_low_byte_size, - init_high_byte_size); + _virtual_spaces->initialize(max_low_byte_size, + init_low_byte_size, + init_high_byte_size); // Place the young gen at the high end. Passes in the virtual space. - _young_gen = new ASPSYoungGen(_virtual_spaces.high(), - _virtual_spaces.high()->committed_size(), + _young_gen = new ASPSYoungGen(_virtual_spaces->high(), + _virtual_spaces->high()->committed_size(), min_high_byte_size, - _virtual_spaces.high_byte_size_limit()); + _virtual_spaces->high_byte_size_limit()); // Place the old gen at the low end. Passes in the virtual space. - _old_gen = new ASPSOldGen(_virtual_spaces.low(), - _virtual_spaces.low()->committed_size(), + _old_gen = new ASPSOldGen(_virtual_spaces->low(), + _virtual_spaces->low()->committed_size(), min_low_byte_size, - _virtual_spaces.low_byte_size_limit(), + _virtual_spaces->low_byte_size_limit(), "old", 1); young_gen()->initialize_work(); @@ -92,8 +92,9 @@ } else { // Layout the reserved space for the generations. + // If OldGen is allocated on nv-dimm, we need to split the reservation (this is required for windows). ReservedSpace old_rs = - virtual_spaces()->reserved_space().first_part(max_low_byte_size); + virtual_spaces()->reserved_space().first_part(max_low_byte_size, AllocateOldGenAt != NULL /* split */); ReservedSpace heap_rs = virtual_spaces()->reserved_space().last_part(max_low_byte_size); ReservedSpace young_rs = heap_rs.first_part(max_high_byte_size); @@ -117,6 +118,8 @@ } } +AdjoiningGenerations::AdjoiningGenerations() { } + size_t AdjoiningGenerations::reserved_byte_size() { return virtual_spaces()->reserved_space().size(); } @@ -278,4 +281,4 @@ request_young_gen_expansion(desired_size - committed); } } -} +} \ No newline at end of file --- old/src/hotspot/share/gc/parallel/adjoiningGenerations.hpp 2018-10-03 14:35:44.521312000 -0700 +++ new/src/hotspot/share/gc/parallel/adjoiningGenerations.hpp 2018-10-03 14:35:43.598846400 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, 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 @@ -43,27 +43,29 @@ class AdjoiningGenerations : public CHeapObj { friend class VMStructs; private: - // The young generation and old generation, respectively - PSYoungGen* _young_gen; - PSOldGen* _old_gen; - - // The spaces used by the two generations. - AdjoiningVirtualSpaces _virtual_spaces; - // Move boundary up to expand old gen. Checks are made to // determine if the move can be done with specified limits. void request_old_gen_expansion(size_t desired_change_in_bytes); // Move boundary down to expand young gen. bool request_young_gen_expansion(size_t desired_change_in_bytes); + protected: + // The young generation and old generation, respectively + PSYoungGen* _young_gen; + PSOldGen* _old_gen; + + // The spaces used by the two generations. + AdjoiningVirtualSpaces* _virtual_spaces; + public: AdjoiningGenerations(ReservedSpace rs, GenerationSizer* policy, size_t alignment); + AdjoiningGenerations(); // Accessors PSYoungGen* young_gen() { return _young_gen; } PSOldGen* old_gen() { return _old_gen; } - AdjoiningVirtualSpaces* virtual_spaces() { return &_virtual_spaces; } + AdjoiningVirtualSpaces* virtual_spaces() { return _virtual_spaces; } // Additional space is needed in the old generation. Check // the available space and attempt to move the boundary if more space @@ -74,7 +76,6 @@ // Return the total byte size of the reserved space // for the adjoining generations. - size_t reserved_byte_size(); + virtual size_t reserved_byte_size(); }; - #endif // SHARE_VM_GC_PARALLEL_ADJOININGGENERATIONS_HPP --- old/src/hotspot/share/gc/parallel/adjoiningVirtualSpaces.hpp 2018-10-03 14:35:56.834929300 -0700 +++ new/src/hotspot/share/gc/parallel/adjoiningVirtualSpaces.hpp 2018-10-03 14:35:55.878892200 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, 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 @@ -59,7 +59,8 @@ // moved up consistently. AdjoiningVirtualSpaces provide the // interfaces for moving the this boundary. -class AdjoiningVirtualSpaces { +class AdjoiningVirtualSpaces : public CHeapObj { +protected: // space at the high end and the low end, respectively PSVirtualSpace* _high; PSVirtualSpace* _low; @@ -84,17 +85,17 @@ size_t alignment); // accessors - PSVirtualSpace* high() { return _high; } - PSVirtualSpace* low() { return _low; } + virtual PSVirtualSpace* high() { return _high; } + virtual PSVirtualSpace* low() { return _low; } ReservedSpace reserved_space() { return _reserved_space; } size_t min_low_byte_size() { return _min_low_byte_size; } size_t min_high_byte_size() { return _min_high_byte_size; } size_t alignment() const { return _alignment; } // move boundary between the two spaces up - bool adjust_boundary_up(size_t size_in_bytes); + virtual bool adjust_boundary_up(size_t size_in_bytes); // and down - bool adjust_boundary_down(size_t size_in_bytes); + virtual bool adjust_boundary_down(size_t size_in_bytes); // Maximum byte size for the high space. size_t high_byte_size_limit() { @@ -107,9 +108,8 @@ // Sets the boundaries for the virtual spaces and commits and // initial size; - void initialize(size_t max_low_byte_size, + virtual void initialize(size_t max_low_byte_size, size_t init_low_byte_size, size_t init_high_byte_size); }; - #endif // SHARE_VM_GC_PARALLEL_ADJOININGVIRTUALSPACES_HPP --- old/src/hotspot/share/gc/parallel/asPSOldGen.hpp 2018-10-03 14:36:09.527507700 -0700 +++ new/src/hotspot/share/gc/parallel/asPSOldGen.hpp 2018-10-03 14:36:08.586399600 -0700 @@ -29,6 +29,7 @@ #include "gc/parallel/objectStartArray.hpp" #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psVirtualspace.hpp" +#include "gc/parallel/psFileBackedVirtualspace.hpp" #include "gc/parallel/spaceCounters.hpp" #include "gc/shared/generationCounters.hpp" --- old/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp 2018-10-03 14:36:22.087855600 -0700 +++ new/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp 2018-10-03 14:36:21.148662700 -0700 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" #include "gc/parallel/adjoiningGenerations.hpp" +#include "gc/parallel/adjoiningGenerationsForHeteroHeap.hpp" #include "gc/parallel/adjoiningVirtualSpaces.hpp" #include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/generationSizer.hpp" @@ -58,7 +59,11 @@ GCTaskManager* ParallelScavengeHeap::_gc_task_manager = NULL; jint ParallelScavengeHeap::initialize() { - const size_t heap_size = _collector_policy->max_heap_byte_size(); + size_t heap_size = _collector_policy->max_heap_byte_size(); + + if (AllocateOldGenAt != NULL && UseAdaptiveGCBoundary) { + heap_size = AdjoiningGenerationsForHeteroHeap::required_reserved_memory(_collector_policy); + } ReservedSpace heap_rs = Universe::reserve_heap(heap_size, _collector_policy->heap_alignment()); @@ -86,7 +91,13 @@ double max_gc_pause_sec = ((double) MaxGCPauseMillis)/1000.0; double max_gc_minor_pause_sec = ((double) MaxGCMinorPauseMillis)/1000.0; - _gens = new AdjoiningGenerations(heap_rs, _collector_policy, generation_alignment()); + if (AllocateOldGenAt != NULL && UseAdaptiveGCBoundary) { + _gens = new AdjoiningGenerationsForHeteroHeap(heap_rs, _collector_policy->max_heap_byte_size() /* total_size_limit */, + _collector_policy, generation_alignment()); + } + else { + _gens = new AdjoiningGenerations(heap_rs, _collector_policy, generation_alignment()); + } _old_gen = _gens->old_gen(); _young_gen = _gens->young_gen(); @@ -104,7 +115,7 @@ GCTimeRatio ); - assert(!UseAdaptiveGCBoundary || + assert(AllocateOldGenAt != NULL || !UseAdaptiveGCBoundary || (old_gen()->virtual_space()->high_boundary() == young_gen()->virtual_space()->low_boundary()), "Boundaries must meet"); --- old/src/hotspot/share/gc/parallel/psOldGen.cpp 2018-10-03 14:36:35.601246200 -0700 +++ new/src/hotspot/share/gc/parallel/psOldGen.cpp 2018-10-03 14:36:34.630839800 -0700 @@ -27,6 +27,7 @@ #include "gc/parallel/parallelScavengeHeap.hpp" #include "gc/parallel/psAdaptiveSizePolicy.hpp" #include "gc/parallel/psCardTable.hpp" +#include "gc/parallel/psFileBackedVirtualspace.hpp" #include "gc/parallel/psMarkSweepDecorator.hpp" #include "gc/parallel/psOldGen.hpp" #include "gc/shared/cardTableBarrierSet.hpp" @@ -71,7 +72,14 @@ void PSOldGen::initialize_virtual_space(ReservedSpace rs, size_t alignment) { - _virtual_space = new PSVirtualSpace(rs, alignment); + if(AllocateOldGenAt != NULL) { + _virtual_space = new PSFileBackedVirtualSpace(rs, alignment, AllocateOldGenAt); + if (!(static_cast (_virtual_space))->initialize()) { + vm_exit_during_initialization("Could not map space for PSOldGen at given AllocateOldGenAt path"); + } + } else { + _virtual_space = new PSVirtualSpace(rs, alignment); + } if (!_virtual_space->expand_by(_init_gen_size)) { vm_exit_during_initialization("Could not reserve enough space for " "object heap"); --- old/src/hotspot/share/memory/universe.cpp 2018-10-03 14:36:48.218230700 -0700 +++ new/src/hotspot/share/memory/universe.cpp 2018-10-03 14:36:47.275453400 -0700 @@ -812,6 +812,10 @@ || UseParallelGC || use_large_pages, "Wrong alignment to use large pages"); + // When AllocateOldGenAt is set, we cannot use largepages for entire heap memory. + // Only young gen which is allocated in dram can use large pages, but we currently don't support that. + use_large_pages = (AllocateOldGenAt != NULL) ? false : use_large_pages; + // Now create the space. ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, AllocateHeapAt); --- old/src/hotspot/share/runtime/arguments.cpp 2018-10-03 14:37:00.734747700 -0700 +++ new/src/hotspot/share/runtime/arguments.cpp 2018-10-03 14:36:59.704333800 -0700 @@ -1616,6 +1616,10 @@ void Arguments::set_use_compressed_oops() { #ifndef ZERO #ifdef _LP64 + if(AllocateOldGenAt != NULL) { + FLAG_SET_ERGO(bool, UseCompressedOops, false); + return; + } // MaxHeapSize is not set up properly at this point, but // the only value that can override MaxHeapSize if we are // to use UseCompressedOops is InitialHeapSize. --- old/src/hotspot/share/runtime/globals.hpp 2018-10-03 14:37:13.553328000 -0700 +++ new/src/hotspot/share/runtime/globals.hpp 2018-10-03 14:37:12.597646900 -0700 @@ -2604,7 +2604,10 @@ "Start flight recording with options")) \ \ experimental(bool, UseFastUnorderedTimeStamps, false, \ - "Use platform unstable time where supported for timestamps only") + "Use platform unstable time where supported for timestamps only") \ + \ + experimental(ccstr, AllocateOldGenAt, NULL, \ + "Directory to use for allocating old generation") #define VM_FLAGS(develop, \ develop_pd, \ --- /dev/null 2018-10-03 14:37:27.000000000 -0700 +++ new/src/hotspot/share/gc/parallel/adjoiningGenerationsForHeteroHeap.cpp 2018-10-03 14:37:25.372576800 -0700 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2018, 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. + * + */ + +#include "precompiled.hpp" +#include "gc/parallel/adjoiningGenerationsForHeteroHeap.hpp" +#include "gc/parallel/adjoiningVirtualSpaces.hpp" +#include "gc/parallel/generationSizer.hpp" +#include "gc/parallel/parallelScavengeHeap.hpp" +#include "logging/log.hpp" +#include "logging/logStream.hpp" +#include "memory/resourceArea.hpp" +#include "utilities/align.hpp" +#include "utilities/ostream.hpp" + +// Create two virtual spaces (HeteroVirtualSpaces), low() on nv-dimm memory, high() on dram. +// create ASPSOldGen and ASPSYoungGen the same way as in base class + +AdjoiningGenerationsForHeteroHeap::AdjoiningGenerationsForHeteroHeap(ReservedSpace old_young_rs, size_t total_size_limit, + GenerationSizer* policy, size_t alignment) : _total_size_limit(total_size_limit) { + size_t init_old_byte_size = policy->initial_old_size(); + size_t min_old_byte_size = policy->min_old_size(); + size_t max_old_byte_size = policy->max_old_size(); + size_t init_young_byte_size = policy->initial_young_size(); + size_t min_young_byte_size = policy->min_young_size(); + size_t max_young_byte_size = policy->max_young_size(); + + // create HeteroVirtualSpaces which is composed of non-overlapping virtual spaces. + HeteroVirtualSpaces* hetero_virtual_spaces = new HeteroVirtualSpaces(old_young_rs, min_old_byte_size, + min_young_byte_size, _total_size_limit, alignment); + + assert(min_old_byte_size <= init_old_byte_size && + init_old_byte_size <= max_old_byte_size, "Parameter check"); + assert(min_young_byte_size <= init_young_byte_size && + init_young_byte_size <= max_young_byte_size, "Parameter check"); + + assert(UseAdaptiveGCBoundary, "Should be used only when UseAdaptiveGCBoundary is true"); + + // Initialize the virtual spaces. Then pass a virtual space to each generation + // for initialization of the generation. + + // Does the actual creation of the virtual spaces + hetero_virtual_spaces->initialize(max_old_byte_size, init_old_byte_size, init_young_byte_size); + + _young_gen = new ASPSYoungGen(hetero_virtual_spaces->high(), + hetero_virtual_spaces->high()->committed_size() /* intial_size */, + min_young_byte_size, + hetero_virtual_spaces->max_young_size()); + + _old_gen = new ASPSOldGen(hetero_virtual_spaces->low(), + hetero_virtual_spaces->low()->committed_size() /* intial_size */, + min_old_byte_size, + hetero_virtual_spaces->max_old_size(), "old", 1); + + young_gen()->initialize_work(); + assert(young_gen()->reserved().byte_size() <= young_gen()->gen_size_limit(), "Consistency check"); + assert(old_young_rs.size() >= young_gen()->gen_size_limit(), "Consistency check"); + + old_gen()->initialize_work("old", 1); + assert(old_gen()->reserved().byte_size() <= old_gen()->gen_size_limit(), "Consistency check"); + assert(old_young_rs.size() >= old_gen()->gen_size_limit(), "Consistency check"); + + _virtual_spaces = hetero_virtual_spaces; +} + +size_t AdjoiningGenerationsForHeteroHeap::required_reserved_memory(GenerationSizer* policy) { + // This is the size that young gen can grow to, when AdaptiveGCBoundary is true. + size_t max_yg_size = policy->max_heap_byte_size() - policy->min_old_size(); + // This is the size that old gen can grow to, when AdaptiveGCBoundary is true. + size_t max_old_size = policy->max_heap_byte_size() - policy->min_young_size(); + + return max_yg_size + max_old_size; +} + +// We override this function since size of reservedspace here is more than heap size and +// callers expect this function to return heap size. +size_t AdjoiningGenerationsForHeteroHeap::reserved_byte_size() { + return total_size_limit(); +} + +AdjoiningGenerationsForHeteroHeap::HeteroVirtualSpaces::HeteroVirtualSpaces(ReservedSpace rs, size_t min_old_byte_size, size_t min_yg_byte_size, size_t max_total_size, size_t alignment) : + AdjoiningVirtualSpaces(rs, min_old_byte_size, min_yg_byte_size, alignment), + _min_old_byte_size(min_old_byte_size), _min_young_byte_size(min_yg_byte_size), + _max_old_byte_size(_max_total_size - _min_young_byte_size), + _max_young_byte_size(_max_total_size - _min_old_byte_size), + _max_total_size(max_total_size) { +} + +void AdjoiningGenerationsForHeteroHeap::HeteroVirtualSpaces::initialize(size_t initial_old_reserved_size, size_t init_old_byte_size, + size_t init_young_byte_size) { + + // This is the reserved space exclusively for old generation. + ReservedSpace old_rs = _reserved_space.first_part(_max_old_byte_size, true); + // Intially we only assign 'initial_old_reserved_size' of the reserved space to old virtual space. + old_rs = old_rs.first_part(initial_old_reserved_size); + + // This is the reserved space exclusively for young generation. + ReservedSpace young_rs = _reserved_space.last_part(_max_old_byte_size).first_part(_max_young_byte_size); + + // Carve out 'initial_young_reserved_size' of reserved space. + size_t initial_young_reserved_size = _max_total_size - initial_old_reserved_size; + young_rs = young_rs.last_part(_max_young_byte_size - initial_young_reserved_size); + + _low = new PSFileBackedVirtualSpace(old_rs, alignment(), AllocateOldGenAt); + if (!_low->expand_by(init_old_byte_size)) { + vm_exit_during_initialization("Could not reserve enough space for object heap"); + } + + _high = new PSVirtualSpaceHighToLow(young_rs, alignment()); + if (!_high->expand_by(init_young_byte_size)) { + vm_exit_during_initialization("Could not reserve enough space for object heap"); + } +} + +// Since the virtual spaces are non-overlapping, there is no boundary as such. +// We replicate the same behavior and maintain the same invariants as base class - AdjoiningVirtualSpaces, by +// increasing old generation size and decreasing young generation size by same amount. +bool AdjoiningGenerationsForHeteroHeap::HeteroVirtualSpaces::adjust_boundary_up(size_t change_in_bytes) { + assert(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary, "runtime check"); + DEBUG_ONLY(size_t total_size_before = young_vs()->reserved_size() + old_vs()->reserved_size()); + + size_t bytes_needed = change_in_bytes; + size_t uncommitted_in_old = MIN2(old_vs()->uncommitted_size(), bytes_needed); + bool old_expanded = false; + + // 1. Try to expand old within its reserved space. + if (uncommitted_in_old != 0) { + if (!old_vs()->expand_by(uncommitted_in_old)) { + return false; + } + old_expanded = true; + bytes_needed -= uncommitted_in_old; + if (bytes_needed == 0) { + return true; + } + } + + size_t bytes_to_add_in_old = 0; + + // 2. Get uncommitted memory from Young virtualspace. + size_t young_uncommitted = MIN2(young_vs()->uncommitted_size(), bytes_needed); + if (young_uncommitted > 0) { + young_vs()->set_reserved(young_vs()->reserved_low_addr() + young_uncommitted, + young_vs()->reserved_high_addr(), + young_vs()->special()); + bytes_needed -= young_uncommitted; + bytes_to_add_in_old = young_uncommitted; + } + + // 3. Get committed memory from Young virtualspace + if (bytes_needed > 0) { + size_t shrink_size = align_down(bytes_needed, young_vs()->alignment()); + bool ret = young_vs()->shrink_by(shrink_size); + assert(ret, "We should be able to shrink young space"); + young_vs()->set_reserved(young_vs()->reserved_low_addr() + shrink_size, + young_vs()->reserved_high_addr(), + young_vs()->special()); + + bytes_to_add_in_old += shrink_size; + } + + // 4. Increase size of old space + old_vs()->set_reserved(old_vs()->reserved_low_addr(), + old_vs()->reserved_high_addr() + bytes_to_add_in_old, + old_vs()->special()); + if (!old_vs()->expand_by(bytes_to_add_in_old) && !old_expanded) { + return false; + } + + DEBUG_ONLY(size_t total_size_after = young_vs()->reserved_size() + old_vs()->reserved_size()); + assert(total_size_after == total_size_before, "should be equal"); + + return true; +} + +// Read comment for adjust_boundary_up() +// Increase young generation size and decrease old generation size by same amount. +bool AdjoiningGenerationsForHeteroHeap::HeteroVirtualSpaces::adjust_boundary_down(size_t change_in_bytes) { + assert(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary, "runtime check"); + DEBUG_ONLY(size_t total_size_before = young_vs()->reserved_size() + old_vs()->reserved_size()); + + size_t bytes_needed = change_in_bytes; + size_t uncommitted_in_young = MIN2(young_vs()->uncommitted_size(), bytes_needed); + bool young_expanded = false; + + // 1. Try to expand old within its reserved space. + if (uncommitted_in_young > 0) { + if (!young_vs()->expand_by(uncommitted_in_young)) { + return false; + } + young_expanded = true; + bytes_needed -= uncommitted_in_young; + if (bytes_needed == 0) { + return true; + } + } + + size_t bytes_to_add_in_young = 0; + + // 2. Get uncommitted memory from Old virtualspace. + size_t old_uncommitted = MIN2(old_vs()->uncommitted_size(), bytes_needed); + if (old_uncommitted > 0) { + old_vs()->set_reserved(old_vs()->reserved_low_addr(), + old_vs()->reserved_high_addr() - old_uncommitted, + old_vs()->special()); + bytes_needed -= old_uncommitted; + bytes_to_add_in_young = old_uncommitted; + } + + // 3. Get committed memory from Old virtualspace + if (bytes_needed > 0) { + size_t shrink_size = align_down(bytes_needed, old_vs()->alignment()); + bool ret = old_vs()->shrink_by(shrink_size); + assert(ret, "We should be able to shrink young space"); + old_vs()->set_reserved(old_vs()->reserved_low_addr(), + old_vs()->reserved_high_addr() - shrink_size, + old_vs()->special()); + + bytes_to_add_in_young += shrink_size; + } + + assert(bytes_to_add_in_young <= change_in_bytes, "should not be more than requested size"); + // 4. Increase size of young space + young_vs()->set_reserved(young_vs()->reserved_low_addr() - bytes_to_add_in_young, + young_vs()->reserved_high_addr(), + young_vs()->special()); + if (!young_vs()->expand_by(bytes_to_add_in_young) && !young_expanded) { + return false; + } + + DEBUG_ONLY(size_t total_size_after = young_vs()->reserved_size() + old_vs()->reserved_size()); + assert(total_size_after == total_size_before, "should be equal"); + + return true; +} + --- /dev/null 2018-10-03 14:37:37.000000000 -0700 +++ new/src/hotspot/share/gc/parallel/adjoiningGenerationsForHeteroHeap.hpp 2018-10-03 14:37:34.638213100 -0700 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018, 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_VM_GC_PARALLEL_ADJOININGGENERATIONSFORHETEROHEAP_HPP +#define SHARE_VM_GC_PARALLEL_ADJOININGGENERATIONSFORHETEROHEAP_HPP + +#include "gc/parallel/adjoiningGenerations.hpp" + +class AdjoiningGenerationsForHeteroHeap : public AdjoiningGenerations { + friend class VMStructs; +private: + // Maximum total size of the generations. This is equal to the heap size specified by user. + // When adjusting young and old generation sizes, we need ensure that sum of the generation sizes does not exceed this. + size_t _total_size_limit; + + size_t total_size_limit() const { + return _total_size_limit; + } + + // HeteroVirtualSpaces creates non-overlapping virtual spaces. Here _low and _high do not share a reserved space, i.e. there is no boundary + // separating the two virtual spaces. + class HeteroVirtualSpaces : public AdjoiningVirtualSpaces { + size_t _min_old_byte_size; + size_t _min_young_byte_size; + size_t _max_old_byte_size; + size_t _max_young_byte_size; + size_t _max_total_size; + + // Internally we access the virtual spaces using these methods. It increases readability, since we were not really + // dealing with adjoining virtual spaces separated by a boundary as is the case in base class. + // Externally they are accessed using low() and high() methods of base class. + PSVirtualSpace* young_vs() { return high(); } + PSVirtualSpace* old_vs() { return low(); } + + public: + HeteroVirtualSpaces(ReservedSpace rs, + size_t min_old_byte_size, + size_t min_young_byte_size, size_t max_total_size, + size_t alignment); + + // Increase old generation size and decrease young generation size by same amount + bool adjust_boundary_up(size_t size_in_bytes); + // Increase young generation size and decrease old generation size by same amount + bool adjust_boundary_down(size_t size_in_bytes); + + size_t max_young_size() const { return _max_young_byte_size; } + size_t max_old_size() const { return _max_old_byte_size; } + + void initialize(size_t initial_old_reserved_size, size_t init_low_byte_size, + size_t init_high_byte_size); + }; + +public: + AdjoiningGenerationsForHeteroHeap(ReservedSpace rs, size_t total_size_limit, GenerationSizer* policy, size_t alignment); + + // Given the size policy, calculate the total amount of memory that needs to be reserved. + // We need to reserve more memory than Xmx, since we use non-overlapping virtual spaces for the young and old generations. + static size_t required_reserved_memory(GenerationSizer* policy); + + // Return the total byte size of the reserved space + size_t reserved_byte_size(); +}; +#endif // SHARE_VM_GC_PARALLEL_ADJOININGGENERATIONSFORHETEROHEAP_HPP + --- /dev/null 2018-10-03 14:37:46.000000000 -0700 +++ new/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.cpp 2018-10-03 14:37:44.011971700 -0700 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018, 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. + * + */ + +#include "precompiled.hpp" +#include "gc/parallel/psFileBackedVirtualspace.hpp" +#include "memory/virtualspace.hpp" +#include "runtime/os.hpp" + +PSFileBackedVirtualSpace::PSFileBackedVirtualSpace(ReservedSpace rs, size_t alignment, const char* path) : PSVirtualSpace(rs, alignment), + _file_path(path), _fd(-1), _mapping_succeeded(false) { + assert(!rs.special(), "ReservedSpace passed to PSFileBackedVirtualSpace cannot be special"); +} + +bool PSFileBackedVirtualSpace::initialize() { + _fd = os::create_file_for_heap(_file_path); + if (_fd == -1) { + return false; + } + // We map the reserved space to a file at initialization. + char* ret = os::replace_existing_mapping_with_file_mapping(reserved_low_addr(), reserved_size(), _fd); + if (ret != reserved_low_addr()) { + return false; + } + // _mapping_succeeded is false if we return before this point. + // expand calls later check value of this flag and return error if it is false. + _mapping_succeeded = true; + _special = true; + return true; +} + +PSFileBackedVirtualSpace::PSFileBackedVirtualSpace(ReservedSpace rs, const char* path) { + PSFileBackedVirtualSpace(rs, os::vm_page_size(), path); +} + +bool PSFileBackedVirtualSpace::expand_by(size_t bytes) { + assert(special(), "Since entire space is committed at initialization, _special should always be true for PSFileBackedVirtualSpace"); + + // if mapping did not succeed during intialization return false + if (!_mapping_succeeded) { + return false; + } + return PSVirtualSpace::expand_by(bytes); + +} + +bool PSFileBackedVirtualSpace::shrink_by(size_t bytes) { + assert(special(), "Since entire space is committed at initialization, _special should always be true for PSFileBackedVirtualSpace"); + return PSVirtualSpace::shrink_by(bytes); +} + +size_t PSFileBackedVirtualSpace::expand_into(PSVirtualSpace* space, size_t bytes) { + // not supported. Since doing this will change page mapping which will lead to large TLB penalties. + assert(false, "expand_into() should not be called for PSFileBackedVirtualSpace"); + return 0; +} + +void PSFileBackedVirtualSpace::release() { + os::close(_fd); + _fd = -1; + _file_path = NULL; + + PSVirtualSpace::release(); +} + --- /dev/null 2018-10-03 14:37:55.000000000 -0700 +++ new/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.hpp 2018-10-03 14:37:53.247253100 -0700 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018, 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_VM_GC_PARALLEL_PSFILEBACKEDVIRTUALSPACE_HPP +#define SHARE_VM_GC_PARALLEL_PSFILEBACKEDVIRTUALSPACE_HPP + +#include "gc/parallel/psVirtualspace.hpp" + +class PSFileBackedVirtualSpace : public PSVirtualSpace { +private: + const char* _file_path; + int _fd; + bool _mapping_succeeded; +public: + PSFileBackedVirtualSpace(ReservedSpace rs, size_t alignment, const char* file_path); + PSFileBackedVirtualSpace(ReservedSpace rs, const char* file_path); + + bool initialize(); + bool expand_by(size_t bytes); + bool shrink_by(size_t bytes); + size_t expand_into(PSVirtualSpace* space, size_t bytes); + void release(); +}; +#endif // SHARE_VM_GC_PARALLEL_PSFILEBACKEDVIRTUALSPACE_HPP +