src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp
changeset 59026 f51714d3385d
equal deleted inserted replaced
59025:b398685dd029 59026:f51714d3385d
       
     1 /*
       
     2  * Copyright (c) 2019, 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 #include "precompiled.hpp"
       
    25 #include "gc/z/zAddress.inline.hpp"
       
    26 #include "gc/z/zGlobals.hpp"
       
    27 #include "gc/z/zLargePages.inline.hpp"
       
    28 #include "gc/z/zPhysicalMemory.inline.hpp"
       
    29 #include "gc/z/zPhysicalMemoryBacking_bsd.hpp"
       
    30 #include "runtime/globals.hpp"
       
    31 #include "runtime/init.hpp"
       
    32 #include "runtime/os.hpp"
       
    33 #include "utilities/align.hpp"
       
    34 #include "utilities/debug.hpp"
       
    35 
       
    36 bool ZPhysicalMemoryBacking::is_initialized() const {
       
    37   return _file.is_initialized();
       
    38 }
       
    39 
       
    40 void ZPhysicalMemoryBacking::warn_commit_limits(size_t max) const {
       
    41   // Does nothing
       
    42 }
       
    43 
       
    44 bool ZPhysicalMemoryBacking::supports_uncommit() {
       
    45   assert(!is_init_completed(), "Invalid state");
       
    46   assert(_file.size() >= ZGranuleSize, "Invalid size");
       
    47 
       
    48   // Test if uncommit is supported by uncommitting and then re-committing a granule
       
    49   return commit(uncommit(ZGranuleSize)) == ZGranuleSize;
       
    50 }
       
    51 
       
    52 size_t ZPhysicalMemoryBacking::commit(size_t size) {
       
    53   size_t committed = 0;
       
    54 
       
    55   // Fill holes in the backing file
       
    56   while (committed < size) {
       
    57     size_t allocated = 0;
       
    58     const size_t remaining = size - committed;
       
    59     const uintptr_t start = _uncommitted.alloc_from_front_at_most(remaining, &allocated);
       
    60     if (start == UINTPTR_MAX) {
       
    61       // No holes to commit
       
    62       break;
       
    63     }
       
    64 
       
    65     // Try commit hole
       
    66     const size_t filled = _file.commit(start, allocated);
       
    67     if (filled > 0) {
       
    68       // Successful or partialy successful
       
    69       _committed.free(start, filled);
       
    70       committed += filled;
       
    71     }
       
    72     if (filled < allocated) {
       
    73       // Failed or partialy failed
       
    74       _uncommitted.free(start + filled, allocated - filled);
       
    75       return committed;
       
    76     }
       
    77   }
       
    78 
       
    79   // Expand backing file
       
    80   if (committed < size) {
       
    81     const size_t remaining = size - committed;
       
    82     const uintptr_t start = _file.size();
       
    83     const size_t expanded = _file.commit(start, remaining);
       
    84     if (expanded > 0) {
       
    85       // Successful or partialy successful
       
    86       _committed.free(start, expanded);
       
    87       committed += expanded;
       
    88     }
       
    89   }
       
    90 
       
    91   return committed;
       
    92 }
       
    93 
       
    94 size_t ZPhysicalMemoryBacking::uncommit(size_t size) {
       
    95   size_t uncommitted = 0;
       
    96 
       
    97   // Punch holes in backing file
       
    98   while (uncommitted < size) {
       
    99     size_t allocated = 0;
       
   100     const size_t remaining = size - uncommitted;
       
   101     const uintptr_t start = _committed.alloc_from_back_at_most(remaining, &allocated);
       
   102     assert(start != UINTPTR_MAX, "Allocation should never fail");
       
   103 
       
   104     // Try punch hole
       
   105     const size_t punched = _file.uncommit(start, allocated);
       
   106     if (punched > 0) {
       
   107       // Successful or partialy successful
       
   108       _uncommitted.free(start, punched);
       
   109       uncommitted += punched;
       
   110     }
       
   111     if (punched < allocated) {
       
   112       // Failed or partialy failed
       
   113       _committed.free(start + punched, allocated - punched);
       
   114       return uncommitted;
       
   115     }
       
   116   }
       
   117 
       
   118   return uncommitted;
       
   119 }
       
   120 
       
   121 ZPhysicalMemory ZPhysicalMemoryBacking::alloc(size_t size) {
       
   122   assert(is_aligned(size, ZGranuleSize), "Invalid size");
       
   123 
       
   124   ZPhysicalMemory pmem;
       
   125 
       
   126   // Allocate segments
       
   127   for (size_t allocated = 0; allocated < size; allocated += ZGranuleSize) {
       
   128     const uintptr_t start = _committed.alloc_from_front(ZGranuleSize);
       
   129     assert(start != UINTPTR_MAX, "Allocation should never fail");
       
   130     pmem.add_segment(ZPhysicalMemorySegment(start, ZGranuleSize));
       
   131   }
       
   132 
       
   133   return pmem;
       
   134 }
       
   135 
       
   136 void ZPhysicalMemoryBacking::free(const ZPhysicalMemory& pmem) {
       
   137   const size_t nsegments = pmem.nsegments();
       
   138 
       
   139   // Free segments
       
   140   for (size_t i = 0; i < nsegments; i++) {
       
   141     const ZPhysicalMemorySegment& segment = pmem.segment(i);
       
   142     _committed.free(segment.start(), segment.size());
       
   143   }
       
   144 }
       
   145 
       
   146 void ZPhysicalMemoryBacking::pretouch_view(uintptr_t addr, size_t size) const {
       
   147   const size_t page_size = ZLargePages::is_explicit() ? ZGranuleSize : os::vm_page_size();
       
   148   os::pretouch_memory((void*)addr, (void*)(addr + size), page_size);
       
   149 }
       
   150 
       
   151 void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const {
       
   152   const size_t nsegments = pmem.nsegments();
       
   153   size_t size = 0;
       
   154 
       
   155   // Map segments
       
   156   for (size_t i = 0; i < nsegments; i++) {
       
   157     const ZPhysicalMemorySegment& segment = pmem.segment(i);
       
   158     const uintptr_t segment_addr = addr + size;
       
   159     _file.map(segment_addr, segment.size(), segment.start());
       
   160     size += segment.size();
       
   161   }
       
   162 
       
   163   // Pre-touch memory
       
   164   if (pretouch) {
       
   165     pretouch_view(addr, size);
       
   166   }
       
   167 }
       
   168 
       
   169 void ZPhysicalMemoryBacking::unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const {
       
   170   _file.unmap(addr, pmem.size());
       
   171 }
       
   172 
       
   173 uintptr_t ZPhysicalMemoryBacking::nmt_address(uintptr_t offset) const {
       
   174   // From an NMT point of view we treat the first heap view (marked0) as committed
       
   175   return ZAddress::marked0(offset);
       
   176 }
       
   177 
       
   178 void ZPhysicalMemoryBacking::map(const ZPhysicalMemory& pmem, uintptr_t offset) const {
       
   179   if (ZVerifyViews) {
       
   180     // Map good view
       
   181     map_view(pmem, ZAddress::good(offset), AlwaysPreTouch);
       
   182   } else {
       
   183     // Map all views
       
   184     map_view(pmem, ZAddress::marked0(offset), AlwaysPreTouch);
       
   185     map_view(pmem, ZAddress::marked1(offset), AlwaysPreTouch);
       
   186     map_view(pmem, ZAddress::remapped(offset), AlwaysPreTouch);
       
   187   }
       
   188 }
       
   189 
       
   190 void ZPhysicalMemoryBacking::unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const {
       
   191   if (ZVerifyViews) {
       
   192     // Unmap good view
       
   193     unmap_view(pmem, ZAddress::good(offset));
       
   194   } else {
       
   195     // Unmap all views
       
   196     unmap_view(pmem, ZAddress::marked0(offset));
       
   197     unmap_view(pmem, ZAddress::marked1(offset));
       
   198     unmap_view(pmem, ZAddress::remapped(offset));
       
   199   }
       
   200 }
       
   201 
       
   202 void ZPhysicalMemoryBacking::debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const {
       
   203   // Map good view
       
   204   assert(ZVerifyViews, "Should be enabled");
       
   205   map_view(pmem, ZAddress::good(offset), false /* pretouch */);
       
   206 }
       
   207 
       
   208 void ZPhysicalMemoryBacking::debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const {
       
   209   // Unmap good view
       
   210   assert(ZVerifyViews, "Should be enabled");
       
   211   unmap_view(pmem, ZAddress::good(offset));
       
   212 }