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/zPhysicalMemory.inline.hpp" 26 #include "logging/log.hpp" 27 #include "memory/allocation.inline.hpp" 28 #include "services/memTracker.hpp" 29 #include "utilities/debug.hpp" 30 #include "utilities/globalDefinitions.hpp" 31 32 ZPhysicalMemory::ZPhysicalMemory() : 33 _nsegments(0), 34 _segments(NULL) {} 35 36 ZPhysicalMemory::ZPhysicalMemory(const ZPhysicalMemorySegment& segment) : 37 _nsegments(0), 38 _segments(NULL) { 39 add_segment(segment); 40 } 41 42 ZPhysicalMemory::ZPhysicalMemory(const ZPhysicalMemory& pmem) : 43 _nsegments(0), 44 _segments(NULL) { 45 46 // Copy segments 47 for (size_t i = 0; i < pmem.nsegments(); i++) { 48 add_segment(pmem.segment(i)); 114 // Transfer segment 115 pmem.add_segment(segment); 116 } else { 117 // Split segment 118 const size_t split_size = size - pmem.size(); 119 pmem.add_segment(ZPhysicalMemorySegment(segment.start(), split_size)); 120 _segments[nsegments++] = ZPhysicalMemorySegment(segment.start() + split_size, segment.size() - split_size); 121 } 122 } else { 123 // Keep segment 124 _segments[nsegments++] = segment; 125 } 126 } 127 128 _nsegments = nsegments; 129 130 return pmem; 131 } 132 133 bool ZPhysicalMemoryManager::is_initialized() const { 134 return _backing.is_initialized(); 135 } 136 137 void ZPhysicalMemoryManager::warn_commit_limits(size_t max) const { 138 _backing.warn_commit_limits(max); 139 } 140 141 bool ZPhysicalMemoryManager::supports_uncommit() { 142 return _backing.supports_uncommit(); 143 } 144 145 void ZPhysicalMemoryManager::nmt_commit(const ZPhysicalMemory& pmem, uintptr_t offset) const { 146 const uintptr_t addr = _backing.nmt_address(offset); 147 const size_t size = pmem.size(); 148 MemTracker::record_virtual_memory_commit((void*)addr, size, CALLER_PC); 149 } 150 151 void ZPhysicalMemoryManager::nmt_uncommit(const ZPhysicalMemory& pmem, uintptr_t offset) const { 152 if (MemTracker::tracking_level() > NMT_minimal) { 153 const uintptr_t addr = _backing.nmt_address(offset); 154 const size_t size = pmem.size(); 155 Tracker tracker(Tracker::uncommit); 156 tracker.record((address)addr, size); 157 } 158 } 159 160 size_t ZPhysicalMemoryManager::commit(size_t size) { 161 return _backing.commit(size); 162 } 163 164 size_t ZPhysicalMemoryManager::uncommit(size_t size) { 165 return _backing.uncommit(size); 166 } 167 168 ZPhysicalMemory ZPhysicalMemoryManager::alloc(size_t size) { 169 return _backing.alloc(size); 170 } 171 172 void ZPhysicalMemoryManager::free(const ZPhysicalMemory& pmem) { 173 _backing.free(pmem); 174 } 175 176 void ZPhysicalMemoryManager::pretouch(uintptr_t offset, size_t size) const { 177 _backing.pretouch(offset, size); 178 } 179 180 void ZPhysicalMemoryManager::map(const ZPhysicalMemory& pmem, uintptr_t offset) const { 181 _backing.map(pmem, offset); 182 nmt_commit(pmem, offset); 183 } 184 185 void ZPhysicalMemoryManager::unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const { 186 nmt_uncommit(pmem, offset); 187 _backing.unmap(pmem, offset); 188 } 189 190 void ZPhysicalMemoryManager::debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const { 191 _backing.debug_map(pmem, offset); 192 } 193 194 void ZPhysicalMemoryManager::debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const { 195 _backing.debug_unmap(pmem, offset); 196 } | 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/zNUMA.inline.hpp" 29 #include "gc/z/zPhysicalMemory.inline.hpp" 30 #include "runtime/init.hpp" 31 #include "runtime/os.hpp" 32 #include "services/memTracker.hpp" 33 #include "utilities/align.hpp" 34 #include "utilities/debug.hpp" 35 #include "utilities/globalDefinitions.hpp" 36 37 ZPhysicalMemory::ZPhysicalMemory() : 38 _nsegments(0), 39 _segments(NULL) {} 40 41 ZPhysicalMemory::ZPhysicalMemory(const ZPhysicalMemorySegment& segment) : 42 _nsegments(0), 43 _segments(NULL) { 44 add_segment(segment); 45 } 46 47 ZPhysicalMemory::ZPhysicalMemory(const ZPhysicalMemory& pmem) : 48 _nsegments(0), 49 _segments(NULL) { 50 51 // Copy segments 52 for (size_t i = 0; i < pmem.nsegments(); i++) { 53 add_segment(pmem.segment(i)); 119 // Transfer segment 120 pmem.add_segment(segment); 121 } else { 122 // Split segment 123 const size_t split_size = size - pmem.size(); 124 pmem.add_segment(ZPhysicalMemorySegment(segment.start(), split_size)); 125 _segments[nsegments++] = ZPhysicalMemorySegment(segment.start() + split_size, segment.size() - split_size); 126 } 127 } else { 128 // Keep segment 129 _segments[nsegments++] = segment; 130 } 131 } 132 133 _nsegments = nsegments; 134 135 return pmem; 136 } 137 138 bool ZPhysicalMemoryManager::is_initialized() const { 139 return _file.is_initialized(); 140 } 141 142 void ZPhysicalMemoryManager::warn_commit_limits(size_t max) const { 143 _file.warn_commit_limits(max); 144 } 145 146 bool ZPhysicalMemoryManager::supports_uncommit() { 147 assert(!is_init_completed(), "Invalid state"); 148 assert(_file.size() >= ZGranuleSize, "Invalid size"); 149 150 // Test if uncommit is supported by uncommitting and then re-committing a granule 151 return commit(uncommit(ZGranuleSize)) == ZGranuleSize; 152 } 153 154 void ZPhysicalMemoryManager::nmt_commit(const ZPhysicalMemory& pmem, uintptr_t offset) const { 155 // From an NMT point of view we treat the first heap view (marked0) as committed 156 const uintptr_t addr = ZAddress::marked0(offset); 157 const size_t size = pmem.size(); 158 MemTracker::record_virtual_memory_commit((void*)addr, size, CALLER_PC); 159 } 160 161 void ZPhysicalMemoryManager::nmt_uncommit(const ZPhysicalMemory& pmem, uintptr_t offset) const { 162 if (MemTracker::tracking_level() > NMT_minimal) { 163 const uintptr_t addr = ZAddress::marked0(offset); 164 const size_t size = pmem.size(); 165 Tracker tracker(Tracker::uncommit); 166 tracker.record((address)addr, size); 167 } 168 } 169 170 size_t ZPhysicalMemoryManager::commit(size_t size) { 171 size_t committed = 0; 172 173 // Fill holes in the backing file 174 while (committed < size) { 175 size_t allocated = 0; 176 const size_t remaining = size - committed; 177 const uintptr_t start = _uncommitted.alloc_from_front_at_most(remaining, &allocated); 178 if (start == UINTPTR_MAX) { 179 // No holes to commit 180 break; 181 } 182 183 // Try commit hole 184 const size_t filled = _file.commit(start, allocated); 185 if (filled > 0) { 186 // Successful or partialy successful 187 _committed.free(start, filled); 188 committed += filled; 189 } 190 if (filled < allocated) { 191 // Failed or partialy failed 192 _uncommitted.free(start + filled, allocated - filled); 193 return committed; 194 } 195 } 196 197 // Expand backing file 198 if (committed < size) { 199 const size_t remaining = size - committed; 200 const uintptr_t start = _file.size(); 201 const size_t expanded = _file.commit(start, remaining); 202 if (expanded > 0) { 203 // Successful or partialy successful 204 _committed.free(start, expanded); 205 committed += expanded; 206 } 207 } 208 209 return committed; 210 } 211 212 size_t ZPhysicalMemoryManager::uncommit(size_t size) { 213 size_t uncommitted = 0; 214 215 // Punch holes in backing file 216 while (uncommitted < size) { 217 size_t allocated = 0; 218 const size_t remaining = size - uncommitted; 219 const uintptr_t start = _committed.alloc_from_back_at_most(remaining, &allocated); 220 assert(start != UINTPTR_MAX, "Allocation should never fail"); 221 222 // Try punch hole 223 const size_t punched = _file.uncommit(start, allocated); 224 if (punched > 0) { 225 // Successful or partialy successful 226 _uncommitted.free(start, punched); 227 uncommitted += punched; 228 } 229 if (punched < allocated) { 230 // Failed or partialy failed 231 _committed.free(start + punched, allocated - punched); 232 return uncommitted; 233 } 234 } 235 236 return uncommitted; 237 } 238 239 ZPhysicalMemory ZPhysicalMemoryManager::alloc(size_t size) { 240 assert(is_aligned(size, ZGranuleSize), "Invalid size"); 241 242 ZPhysicalMemory pmem; 243 244 // Allocate segments 245 for (size_t allocated = 0; allocated < size; allocated += ZGranuleSize) { 246 const uintptr_t start = _committed.alloc_from_front(ZGranuleSize); 247 assert(start != UINTPTR_MAX, "Allocation should never fail"); 248 pmem.add_segment(ZPhysicalMemorySegment(start, ZGranuleSize)); 249 } 250 251 return pmem; 252 } 253 254 void ZPhysicalMemoryManager::free(const ZPhysicalMemory& pmem) { 255 const size_t nsegments = pmem.nsegments(); 256 257 // Free segments 258 for (size_t i = 0; i < nsegments; i++) { 259 const ZPhysicalMemorySegment& segment = pmem.segment(i); 260 _committed.free(segment.start(), segment.size()); 261 } 262 } 263 264 void ZPhysicalMemoryManager::pretouch_view(uintptr_t addr, size_t size) const { 265 const size_t page_size = ZLargePages::is_explicit() ? ZGranuleSize : os::vm_page_size(); 266 os::pretouch_memory((void*)addr, (void*)(addr + size), page_size); 267 } 268 269 void ZPhysicalMemoryManager::map_view(const ZPhysicalMemory& pmem, uintptr_t addr) const { 270 const size_t nsegments = pmem.nsegments(); 271 size_t size = 0; 272 273 // Map segments 274 for (size_t i = 0; i < nsegments; i++) { 275 const ZPhysicalMemorySegment& segment = pmem.segment(i); 276 _file.map(addr + size, segment.size(), segment.start()); 277 size += segment.size(); 278 } 279 280 // Setup use of transparent huge pages before touching it 281 if (ZLargePages::is_transparent()) { 282 os::realign_memory((char*)addr, size, os::large_page_size()); 283 } 284 285 // Setup NUMA interleaving before touching it 286 if (ZNUMA::is_enabled()) { 287 os::numa_make_global((char*)addr, size); 288 } 289 } 290 291 void ZPhysicalMemoryManager::unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const { 292 _file.unmap(addr, pmem.size()); 293 } 294 295 void ZPhysicalMemoryManager::pretouch(uintptr_t offset, size_t size) const { 296 if (ZVerifyViews) { 297 // Pre-touch good view 298 pretouch_view(ZAddress::good(offset), size); 299 } else { 300 // Pre-touch all views 301 pretouch_view(ZAddress::marked0(offset), size); 302 pretouch_view(ZAddress::marked1(offset), size); 303 pretouch_view(ZAddress::remapped(offset), size); 304 } 305 } 306 307 void ZPhysicalMemoryManager::map(const ZPhysicalMemory& pmem, uintptr_t offset) const { 308 if (ZVerifyViews) { 309 // Map good view 310 map_view(pmem, ZAddress::good(offset)); 311 } else { 312 // Map all views 313 map_view(pmem, ZAddress::marked0(offset)); 314 map_view(pmem, ZAddress::marked1(offset)); 315 map_view(pmem, ZAddress::remapped(offset)); 316 } 317 318 nmt_commit(pmem, offset); 319 } 320 321 void ZPhysicalMemoryManager::unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const { 322 if (ZVerifyViews) { 323 // Unmap good view 324 unmap_view(pmem, ZAddress::good(offset)); 325 } else { 326 // Unmap all views 327 unmap_view(pmem, ZAddress::marked0(offset)); 328 unmap_view(pmem, ZAddress::marked1(offset)); 329 unmap_view(pmem, ZAddress::remapped(offset)); 330 } 331 332 nmt_uncommit(pmem, offset); 333 } 334 335 void ZPhysicalMemoryManager::debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const { 336 // Map good view 337 assert(ZVerifyViews, "Should be enabled"); 338 map_view(pmem, ZAddress::good(offset)); 339 } 340 341 void ZPhysicalMemoryManager::debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const { 342 // Unmap good view 343 assert(ZVerifyViews, "Should be enabled"); 344 unmap_view(pmem, ZAddress::good(offset)); 345 } |