Mercurial > hg > graal-jvmci-8
comparison src/os/linux/vm/os_linux.cpp @ 12110:4c84d351cca9
8007074: SIGSEGV at ParMarkBitMap::verify_clear()
Summary: Replace the broken large pages implementation on Linux. New flag: -XX:+UseTransparentHugePages - Linux specific flag to turn on transparent huge page hinting with madvise(..., MAP_HUGETLB). Changed behavior: -XX:+UseLargePages - tries to use -XX:+UseTransparentHugePages before trying other large pages implementations (on Linux). Changed behavior: -XX:+UseHugeTLBFS - Use upfront allocation of Large Pages instead of using the broken implementation to dynamically committing large pages. Changed behavior: -XX:LargePageSizeInBytes - Turned off the ability to use this flag on Linux and provides warning to user if set to a value different than the OS chosen large page size. Changed behavior: Setting no large page size - Now defaults to use -XX:UseTransparentHugePages if the OS supports it. Previously, -XX:+UseHugeTLBFS was chosen if the OS was configured to use large pages.
Reviewed-by: tschatzl, dcubed, brutisso
author | stefank |
---|---|
date | Fri, 16 Aug 2013 13:22:32 +0200 |
parents | 59b052799158 |
children | d8e99408faad 0d59407e7e09 e2722a66aba7 |
comparison
equal
deleted
inserted
replaced
12108:badf4244ceae | 12110:4c84d351cca9 |
---|---|
2718 #define MADV_HUGEPAGE 14 | 2718 #define MADV_HUGEPAGE 14 |
2719 #endif | 2719 #endif |
2720 | 2720 |
2721 int os::Linux::commit_memory_impl(char* addr, size_t size, | 2721 int os::Linux::commit_memory_impl(char* addr, size_t size, |
2722 size_t alignment_hint, bool exec) { | 2722 size_t alignment_hint, bool exec) { |
2723 int err; | 2723 int err = os::Linux::commit_memory_impl(addr, size, exec); |
2724 if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { | |
2725 int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; | |
2726 uintptr_t res = | |
2727 (uintptr_t) ::mmap(addr, size, prot, | |
2728 MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_HUGETLB, | |
2729 -1, 0); | |
2730 if (res != (uintptr_t) MAP_FAILED) { | |
2731 if (UseNUMAInterleaving) { | |
2732 numa_make_global(addr, size); | |
2733 } | |
2734 return 0; | |
2735 } | |
2736 | |
2737 err = errno; // save errno from mmap() call above | |
2738 | |
2739 if (!recoverable_mmap_error(err)) { | |
2740 // However, it is not clear that this loss of our reserved mapping | |
2741 // happens with large pages on Linux or that we cannot recover | |
2742 // from the loss. For now, we just issue a warning and we don't | |
2743 // call vm_exit_out_of_memory(). This issue is being tracked by | |
2744 // JBS-8007074. | |
2745 warn_fail_commit_memory(addr, size, alignment_hint, exec, err); | |
2746 // vm_exit_out_of_memory(size, OOM_MMAP_ERROR, | |
2747 // "committing reserved memory."); | |
2748 } | |
2749 // Fall through and try to use small pages | |
2750 } | |
2751 | |
2752 err = os::Linux::commit_memory_impl(addr, size, exec); | |
2753 if (err == 0) { | 2724 if (err == 0) { |
2754 realign_memory(addr, size, alignment_hint); | 2725 realign_memory(addr, size, alignment_hint); |
2755 } | 2726 } |
2756 return err; | 2727 return err; |
2757 } | 2728 } |
2772 vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); | 2743 vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); |
2773 } | 2744 } |
2774 } | 2745 } |
2775 | 2746 |
2776 void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { | 2747 void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { |
2777 if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { | 2748 if (UseTransparentHugePages && alignment_hint > (size_t)vm_page_size()) { |
2778 // We don't check the return value: madvise(MADV_HUGEPAGE) may not | 2749 // We don't check the return value: madvise(MADV_HUGEPAGE) may not |
2779 // be supported or the memory may already be backed by huge pages. | 2750 // be supported or the memory may already be backed by huge pages. |
2780 ::madvise(addr, bytes, MADV_HUGEPAGE); | 2751 ::madvise(addr, bytes, MADV_HUGEPAGE); |
2781 } | 2752 } |
2782 } | 2753 } |
2785 // This method works by doing an mmap over an existing mmaping and effectively discarding | 2756 // This method works by doing an mmap over an existing mmaping and effectively discarding |
2786 // the existing pages. However it won't work for SHM-based large pages that cannot be | 2757 // the existing pages. However it won't work for SHM-based large pages that cannot be |
2787 // uncommitted at all. We don't do anything in this case to avoid creating a segment with | 2758 // uncommitted at all. We don't do anything in this case to avoid creating a segment with |
2788 // small pages on top of the SHM segment. This method always works for small pages, so we | 2759 // small pages on top of the SHM segment. This method always works for small pages, so we |
2789 // allow that in any case. | 2760 // allow that in any case. |
2790 if (alignment_hint <= (size_t)os::vm_page_size() || !UseSHM) { | 2761 if (alignment_hint <= (size_t)os::vm_page_size() || can_commit_large_page_memory()) { |
2791 commit_memory(addr, bytes, alignment_hint, !ExecMem); | 2762 commit_memory(addr, bytes, alignment_hint, !ExecMem); |
2792 } | 2763 } |
2793 } | 2764 } |
2794 | 2765 |
2795 void os::numa_make_global(char *addr, size_t bytes) { | 2766 void os::numa_make_global(char *addr, size_t bytes) { |
3155 | 3126 |
3156 bool os::unguard_memory(char* addr, size_t size) { | 3127 bool os::unguard_memory(char* addr, size_t size) { |
3157 return linux_mprotect(addr, size, PROT_READ|PROT_WRITE); | 3128 return linux_mprotect(addr, size, PROT_READ|PROT_WRITE); |
3158 } | 3129 } |
3159 | 3130 |
3131 bool os::Linux::transparent_huge_pages_sanity_check(bool warn, size_t page_size) { | |
3132 bool result = false; | |
3133 void *p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE, | |
3134 MAP_ANONYMOUS|MAP_PRIVATE, | |
3135 -1, 0); | |
3136 if (p != MAP_FAILED) { | |
3137 void *aligned_p = align_ptr_up(p, page_size); | |
3138 | |
3139 result = madvise(aligned_p, page_size, MADV_HUGEPAGE) == 0; | |
3140 | |
3141 munmap(p, page_size * 2); | |
3142 } | |
3143 | |
3144 if (warn && !result) { | |
3145 warning("TransparentHugePages is not supported by the operating system."); | |
3146 } | |
3147 | |
3148 return result; | |
3149 } | |
3150 | |
3160 bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) { | 3151 bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) { |
3161 bool result = false; | 3152 bool result = false; |
3162 void *p = mmap (NULL, page_size, PROT_READ|PROT_WRITE, | 3153 void *p = mmap(NULL, page_size, PROT_READ|PROT_WRITE, |
3163 MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, | 3154 MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, |
3164 -1, 0); | 3155 -1, 0); |
3165 | 3156 |
3166 if (p != MAP_FAILED) { | 3157 if (p != MAP_FAILED) { |
3167 // We don't know if this really is a huge page or not. | 3158 // We don't know if this really is a huge page or not. |
3168 FILE *fp = fopen("/proc/self/maps", "r"); | 3159 FILE *fp = fopen("/proc/self/maps", "r"); |
3169 if (fp) { | 3160 if (fp) { |
3180 } | 3171 } |
3181 } | 3172 } |
3182 } | 3173 } |
3183 fclose(fp); | 3174 fclose(fp); |
3184 } | 3175 } |
3185 munmap (p, page_size); | 3176 munmap(p, page_size); |
3186 if (result) | 3177 } |
3187 return true; | 3178 |
3188 } | 3179 if (warn && !result) { |
3189 | |
3190 if (warn) { | |
3191 warning("HugeTLBFS is not supported by the operating system."); | 3180 warning("HugeTLBFS is not supported by the operating system."); |
3192 } | 3181 } |
3193 | 3182 |
3194 return result; | 3183 return result; |
3195 } | 3184 } |
3233 | 3222 |
3234 // Large page support | 3223 // Large page support |
3235 | 3224 |
3236 static size_t _large_page_size = 0; | 3225 static size_t _large_page_size = 0; |
3237 | 3226 |
3238 void os::large_page_init() { | 3227 size_t os::Linux::find_large_page_size() { |
3239 if (!UseLargePages) { | 3228 size_t large_page_size = 0; |
3240 UseHugeTLBFS = false; | 3229 |
3241 UseSHM = false; | 3230 // large_page_size on Linux is used to round up heap size. x86 uses either |
3242 return; | 3231 // 2M or 4M page, depending on whether PAE (Physical Address Extensions) |
3243 } | 3232 // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use |
3244 | 3233 // page as large as 256M. |
3245 if (FLAG_IS_DEFAULT(UseHugeTLBFS) && FLAG_IS_DEFAULT(UseSHM)) { | 3234 // |
3246 // If UseLargePages is specified on the command line try both methods, | 3235 // Here we try to figure out page size by parsing /proc/meminfo and looking |
3247 // if it's default, then try only HugeTLBFS. | 3236 // for a line with the following format: |
3248 if (FLAG_IS_DEFAULT(UseLargePages)) { | 3237 // Hugepagesize: 2048 kB |
3249 UseHugeTLBFS = true; | 3238 // |
3250 } else { | 3239 // If we can't determine the value (e.g. /proc is not mounted, or the text |
3251 UseHugeTLBFS = UseSHM = true; | 3240 // format has been changed), we'll use the largest page size supported by |
3252 } | 3241 // the processor. |
3253 } | |
3254 | |
3255 if (LargePageSizeInBytes) { | |
3256 _large_page_size = LargePageSizeInBytes; | |
3257 } else { | |
3258 // large_page_size on Linux is used to round up heap size. x86 uses either | |
3259 // 2M or 4M page, depending on whether PAE (Physical Address Extensions) | |
3260 // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use | |
3261 // page as large as 256M. | |
3262 // | |
3263 // Here we try to figure out page size by parsing /proc/meminfo and looking | |
3264 // for a line with the following format: | |
3265 // Hugepagesize: 2048 kB | |
3266 // | |
3267 // If we can't determine the value (e.g. /proc is not mounted, or the text | |
3268 // format has been changed), we'll use the largest page size supported by | |
3269 // the processor. | |
3270 | 3242 |
3271 #ifndef ZERO | 3243 #ifndef ZERO |
3272 _large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M) | 3244 large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M) |
3273 ARM_ONLY(2 * M) PPC_ONLY(4 * M); | 3245 ARM_ONLY(2 * M) PPC_ONLY(4 * M); |
3274 #endif // ZERO | 3246 #endif // ZERO |
3275 | 3247 |
3276 FILE *fp = fopen("/proc/meminfo", "r"); | 3248 FILE *fp = fopen("/proc/meminfo", "r"); |
3277 if (fp) { | 3249 if (fp) { |
3278 while (!feof(fp)) { | 3250 while (!feof(fp)) { |
3279 int x = 0; | 3251 int x = 0; |
3280 char buf[16]; | 3252 char buf[16]; |
3281 if (fscanf(fp, "Hugepagesize: %d", &x) == 1) { | 3253 if (fscanf(fp, "Hugepagesize: %d", &x) == 1) { |
3282 if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) { | 3254 if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) { |
3283 _large_page_size = x * K; | 3255 large_page_size = x * K; |
3284 break; | 3256 break; |
3285 } | 3257 } |
3286 } else { | 3258 } else { |
3287 // skip to next line | 3259 // skip to next line |
3288 for (;;) { | 3260 for (;;) { |
3289 int ch = fgetc(fp); | 3261 int ch = fgetc(fp); |
3290 if (ch == EOF || ch == (int)'\n') break; | 3262 if (ch == EOF || ch == (int)'\n') break; |
3291 } | |
3292 } | 3263 } |
3293 } | 3264 } |
3294 fclose(fp); | 3265 } |
3295 } | 3266 fclose(fp); |
3296 } | 3267 } |
3297 | 3268 |
3298 // print a warning if any large page related flag is specified on command line | 3269 if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != large_page_size) { |
3299 bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS); | 3270 warning("Setting LargePageSizeInBytes has no effect on this OS. Large page size is " |
3300 | 3271 SIZE_FORMAT "%s.", byte_size_in_proper_unit(large_page_size), |
3272 proper_unit_for_byte_size(large_page_size)); | |
3273 } | |
3274 | |
3275 return large_page_size; | |
3276 } | |
3277 | |
3278 size_t os::Linux::setup_large_page_size() { | |
3279 _large_page_size = Linux::find_large_page_size(); | |
3301 const size_t default_page_size = (size_t)Linux::page_size(); | 3280 const size_t default_page_size = (size_t)Linux::page_size(); |
3302 if (_large_page_size > default_page_size) { | 3281 if (_large_page_size > default_page_size) { |
3303 _page_sizes[0] = _large_page_size; | 3282 _page_sizes[0] = _large_page_size; |
3304 _page_sizes[1] = default_page_size; | 3283 _page_sizes[1] = default_page_size; |
3305 _page_sizes[2] = 0; | 3284 _page_sizes[2] = 0; |
3306 } | 3285 } |
3307 UseHugeTLBFS = UseHugeTLBFS && | 3286 |
3308 Linux::hugetlbfs_sanity_check(warn_on_failure, _large_page_size); | 3287 return _large_page_size; |
3309 | 3288 } |
3310 if (UseHugeTLBFS) | 3289 |
3290 bool os::Linux::setup_large_page_type(size_t page_size) { | |
3291 if (FLAG_IS_DEFAULT(UseHugeTLBFS) && | |
3292 FLAG_IS_DEFAULT(UseSHM) && | |
3293 FLAG_IS_DEFAULT(UseTransparentHugePages)) { | |
3294 // If UseLargePages is specified on the command line try all methods, | |
3295 // if it's default, then try only UseTransparentHugePages. | |
3296 if (FLAG_IS_DEFAULT(UseLargePages)) { | |
3297 UseTransparentHugePages = true; | |
3298 } else { | |
3299 UseHugeTLBFS = UseTransparentHugePages = UseSHM = true; | |
3300 } | |
3301 } | |
3302 | |
3303 if (UseTransparentHugePages) { | |
3304 bool warn_on_failure = !FLAG_IS_DEFAULT(UseTransparentHugePages); | |
3305 if (transparent_huge_pages_sanity_check(warn_on_failure, page_size)) { | |
3306 UseHugeTLBFS = false; | |
3307 UseSHM = false; | |
3308 return true; | |
3309 } | |
3310 UseTransparentHugePages = false; | |
3311 } | |
3312 | |
3313 if (UseHugeTLBFS) { | |
3314 bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS); | |
3315 if (hugetlbfs_sanity_check(warn_on_failure, page_size)) { | |
3316 UseSHM = false; | |
3317 return true; | |
3318 } | |
3319 UseHugeTLBFS = false; | |
3320 } | |
3321 | |
3322 return UseSHM; | |
3323 } | |
3324 | |
3325 void os::large_page_init() { | |
3326 if (!UseLargePages) { | |
3327 UseHugeTLBFS = false; | |
3328 UseTransparentHugePages = false; | |
3311 UseSHM = false; | 3329 UseSHM = false; |
3312 | 3330 return; |
3313 UseLargePages = UseHugeTLBFS || UseSHM; | 3331 } |
3332 | |
3333 size_t large_page_size = Linux::setup_large_page_size(); | |
3334 UseLargePages = Linux::setup_large_page_type(large_page_size); | |
3314 | 3335 |
3315 set_coredump_filter(); | 3336 set_coredump_filter(); |
3316 } | 3337 } |
3317 | 3338 |
3318 #ifndef SHM_HUGETLB | 3339 #ifndef SHM_HUGETLB |
3319 #define SHM_HUGETLB 04000 | 3340 #define SHM_HUGETLB 04000 |
3320 #endif | 3341 #endif |
3321 | 3342 |
3322 char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { | 3343 char* os::Linux::reserve_memory_special_shm(size_t bytes, size_t alignment, char* req_addr, bool exec) { |
3323 // "exec" is passed in but not used. Creating the shared image for | 3344 // "exec" is passed in but not used. Creating the shared image for |
3324 // the code cache doesn't have an SHM_X executable permission to check. | 3345 // the code cache doesn't have an SHM_X executable permission to check. |
3325 assert(UseLargePages && UseSHM, "only for SHM large pages"); | 3346 assert(UseLargePages && UseSHM, "only for SHM large pages"); |
3347 assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address"); | |
3348 | |
3349 if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) { | |
3350 return NULL; // Fallback to small pages. | |
3351 } | |
3326 | 3352 |
3327 key_t key = IPC_PRIVATE; | 3353 key_t key = IPC_PRIVATE; |
3328 char *addr; | 3354 char *addr; |
3329 | 3355 |
3330 bool warn_on_failure = UseLargePages && | 3356 bool warn_on_failure = UseLargePages && |
3331 (!FLAG_IS_DEFAULT(UseLargePages) || | 3357 (!FLAG_IS_DEFAULT(UseLargePages) || |
3358 !FLAG_IS_DEFAULT(UseSHM) || | |
3332 !FLAG_IS_DEFAULT(LargePageSizeInBytes) | 3359 !FLAG_IS_DEFAULT(LargePageSizeInBytes) |
3333 ); | 3360 ); |
3334 char msg[128]; | 3361 char msg[128]; |
3335 | 3362 |
3336 // Create a large shared memory region to attach to based on size. | 3363 // Create a large shared memory region to attach to based on size. |
3374 warning(msg); | 3401 warning(msg); |
3375 } | 3402 } |
3376 return NULL; | 3403 return NULL; |
3377 } | 3404 } |
3378 | 3405 |
3379 if ((addr != NULL) && UseNUMAInterleaving) { | |
3380 numa_make_global(addr, bytes); | |
3381 } | |
3382 | |
3383 // The memory is committed | |
3384 MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); | |
3385 | |
3386 return addr; | 3406 return addr; |
3387 } | 3407 } |
3388 | 3408 |
3409 static void warn_on_large_pages_failure(char* req_addr, size_t bytes, int error) { | |
3410 assert(error == ENOMEM, "Only expect to fail if no memory is available"); | |
3411 | |
3412 bool warn_on_failure = UseLargePages && | |
3413 (!FLAG_IS_DEFAULT(UseLargePages) || | |
3414 !FLAG_IS_DEFAULT(UseHugeTLBFS) || | |
3415 !FLAG_IS_DEFAULT(LargePageSizeInBytes)); | |
3416 | |
3417 if (warn_on_failure) { | |
3418 char msg[128]; | |
3419 jio_snprintf(msg, sizeof(msg), "Failed to reserve large pages memory req_addr: " | |
3420 PTR_FORMAT " bytes: " SIZE_FORMAT " (errno = %d).", req_addr, bytes, error); | |
3421 warning(msg); | |
3422 } | |
3423 } | |
3424 | |
3425 char* os::Linux::reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec) { | |
3426 assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages"); | |
3427 assert(is_size_aligned(bytes, os::large_page_size()), "Unaligned size"); | |
3428 assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address"); | |
3429 | |
3430 int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; | |
3431 char* addr = (char*)::mmap(req_addr, bytes, prot, | |
3432 MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, | |
3433 -1, 0); | |
3434 | |
3435 if (addr == MAP_FAILED) { | |
3436 warn_on_large_pages_failure(req_addr, bytes, errno); | |
3437 return NULL; | |
3438 } | |
3439 | |
3440 assert(is_ptr_aligned(addr, os::large_page_size()), "Must be"); | |
3441 | |
3442 return addr; | |
3443 } | |
3444 | |
3445 char* os::Linux::reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec) { | |
3446 size_t large_page_size = os::large_page_size(); | |
3447 | |
3448 assert(bytes >= large_page_size, "Shouldn't allocate large pages for small sizes"); | |
3449 | |
3450 // Allocate small pages. | |
3451 | |
3452 char* start; | |
3453 if (req_addr != NULL) { | |
3454 assert(is_ptr_aligned(req_addr, alignment), "Must be"); | |
3455 assert(is_size_aligned(bytes, alignment), "Must be"); | |
3456 start = os::reserve_memory(bytes, req_addr); | |
3457 assert(start == NULL || start == req_addr, "Must be"); | |
3458 } else { | |
3459 start = os::reserve_memory_aligned(bytes, alignment); | |
3460 } | |
3461 | |
3462 if (start == NULL) { | |
3463 return NULL; | |
3464 } | |
3465 | |
3466 assert(is_ptr_aligned(start, alignment), "Must be"); | |
3467 | |
3468 // os::reserve_memory_special will record this memory area. | |
3469 // Need to release it here to prevent overlapping reservations. | |
3470 MemTracker::record_virtual_memory_release((address)start, bytes); | |
3471 | |
3472 char* end = start + bytes; | |
3473 | |
3474 // Find the regions of the allocated chunk that can be promoted to large pages. | |
3475 char* lp_start = (char*)align_ptr_up(start, large_page_size); | |
3476 char* lp_end = (char*)align_ptr_down(end, large_page_size); | |
3477 | |
3478 size_t lp_bytes = lp_end - lp_start; | |
3479 | |
3480 assert(is_size_aligned(lp_bytes, large_page_size), "Must be"); | |
3481 | |
3482 if (lp_bytes == 0) { | |
3483 // The mapped region doesn't even span the start and the end of a large page. | |
3484 // Fall back to allocate a non-special area. | |
3485 ::munmap(start, end - start); | |
3486 return NULL; | |
3487 } | |
3488 | |
3489 int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; | |
3490 | |
3491 | |
3492 void* result; | |
3493 | |
3494 if (start != lp_start) { | |
3495 result = ::mmap(start, lp_start - start, prot, | |
3496 MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, | |
3497 -1, 0); | |
3498 if (result == MAP_FAILED) { | |
3499 ::munmap(lp_start, end - lp_start); | |
3500 return NULL; | |
3501 } | |
3502 } | |
3503 | |
3504 result = ::mmap(lp_start, lp_bytes, prot, | |
3505 MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_HUGETLB, | |
3506 -1, 0); | |
3507 if (result == MAP_FAILED) { | |
3508 warn_on_large_pages_failure(req_addr, bytes, errno); | |
3509 // If the mmap above fails, the large pages region will be unmapped and we | |
3510 // have regions before and after with small pages. Release these regions. | |
3511 // | |
3512 // | mapped | unmapped | mapped | | |
3513 // ^ ^ ^ ^ | |
3514 // start lp_start lp_end end | |
3515 // | |
3516 ::munmap(start, lp_start - start); | |
3517 ::munmap(lp_end, end - lp_end); | |
3518 return NULL; | |
3519 } | |
3520 | |
3521 if (lp_end != end) { | |
3522 result = ::mmap(lp_end, end - lp_end, prot, | |
3523 MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, | |
3524 -1, 0); | |
3525 if (result == MAP_FAILED) { | |
3526 ::munmap(start, lp_end - start); | |
3527 return NULL; | |
3528 } | |
3529 } | |
3530 | |
3531 return start; | |
3532 } | |
3533 | |
3534 char* os::Linux::reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, char* req_addr, bool exec) { | |
3535 assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages"); | |
3536 assert(is_ptr_aligned(req_addr, alignment), "Must be"); | |
3537 assert(is_power_of_2(alignment), "Must be"); | |
3538 assert(is_power_of_2(os::large_page_size()), "Must be"); | |
3539 assert(bytes >= os::large_page_size(), "Shouldn't allocate large pages for small sizes"); | |
3540 | |
3541 if (is_size_aligned(bytes, os::large_page_size()) && alignment <= os::large_page_size()) { | |
3542 return reserve_memory_special_huge_tlbfs_only(bytes, req_addr, exec); | |
3543 } else { | |
3544 return reserve_memory_special_huge_tlbfs_mixed(bytes, alignment, req_addr, exec); | |
3545 } | |
3546 } | |
3547 | |
3548 char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) { | |
3549 assert(UseLargePages, "only for large pages"); | |
3550 | |
3551 char* addr; | |
3552 if (UseSHM) { | |
3553 addr = os::Linux::reserve_memory_special_shm(bytes, alignment, req_addr, exec); | |
3554 } else { | |
3555 assert(UseHugeTLBFS, "must be"); | |
3556 addr = os::Linux::reserve_memory_special_huge_tlbfs(bytes, alignment, req_addr, exec); | |
3557 } | |
3558 | |
3559 if (addr != NULL) { | |
3560 if (UseNUMAInterleaving) { | |
3561 numa_make_global(addr, bytes); | |
3562 } | |
3563 | |
3564 // The memory is committed | |
3565 MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); | |
3566 } | |
3567 | |
3568 return addr; | |
3569 } | |
3570 | |
3571 bool os::Linux::release_memory_special_shm(char* base, size_t bytes) { | |
3572 // detaching the SHM segment will also delete it, see reserve_memory_special_shm() | |
3573 return shmdt(base) == 0; | |
3574 } | |
3575 | |
3576 bool os::Linux::release_memory_special_huge_tlbfs(char* base, size_t bytes) { | |
3577 return pd_release_memory(base, bytes); | |
3578 } | |
3579 | |
3389 bool os::release_memory_special(char* base, size_t bytes) { | 3580 bool os::release_memory_special(char* base, size_t bytes) { |
3581 assert(UseLargePages, "only for large pages"); | |
3582 | |
3390 MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); | 3583 MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); |
3391 // detaching the SHM segment will also delete it, see reserve_memory_special() | 3584 |
3392 int rslt = shmdt(base); | 3585 bool res; |
3393 if (rslt == 0) { | 3586 if (UseSHM) { |
3587 res = os::Linux::release_memory_special_shm(base, bytes); | |
3588 } else { | |
3589 assert(UseHugeTLBFS, "must be"); | |
3590 res = os::Linux::release_memory_special_huge_tlbfs(base, bytes); | |
3591 } | |
3592 | |
3593 if (res) { | |
3394 tkr.record((address)base, bytes); | 3594 tkr.record((address)base, bytes); |
3395 return true; | |
3396 } else { | 3595 } else { |
3397 tkr.discard(); | 3596 tkr.discard(); |
3398 return false; | 3597 } |
3399 } | 3598 |
3599 return res; | |
3400 } | 3600 } |
3401 | 3601 |
3402 size_t os::large_page_size() { | 3602 size_t os::large_page_size() { |
3403 return _large_page_size; | 3603 return _large_page_size; |
3404 } | 3604 } |
3405 | 3605 |
3406 // HugeTLBFS allows application to commit large page memory on demand; | 3606 // With SysV SHM the entire memory region must be allocated as shared |
3407 // with SysV SHM the entire memory region must be allocated as shared | |
3408 // memory. | 3607 // memory. |
3608 // HugeTLBFS allows application to commit large page memory on demand. | |
3609 // However, when committing memory with HugeTLBFS fails, the region | |
3610 // that was supposed to be committed will lose the old reservation | |
3611 // and allow other threads to steal that memory region. Because of this | |
3612 // behavior we can't commit HugeTLBFS memory. | |
3409 bool os::can_commit_large_page_memory() { | 3613 bool os::can_commit_large_page_memory() { |
3410 return UseHugeTLBFS; | 3614 return UseTransparentHugePages; |
3411 } | 3615 } |
3412 | 3616 |
3413 bool os::can_execute_large_page_memory() { | 3617 bool os::can_execute_large_page_memory() { |
3414 return UseHugeTLBFS; | 3618 return UseTransparentHugePages || UseHugeTLBFS; |
3415 } | 3619 } |
3416 | 3620 |
3417 // Reserve memory at an arbitrary address, only if that area is | 3621 // Reserve memory at an arbitrary address, only if that area is |
3418 // available (and not reserved for something else). | 3622 // available (and not reserved for something else). |
3419 | 3623 |
4561 if ((Linux::numa_max_node() < 1)) { | 4765 if ((Linux::numa_max_node() < 1)) { |
4562 // There's only one node(they start from 0), disable NUMA. | 4766 // There's only one node(they start from 0), disable NUMA. |
4563 UseNUMA = false; | 4767 UseNUMA = false; |
4564 } | 4768 } |
4565 } | 4769 } |
4566 // With SHM large pages we cannot uncommit a page, so there's not way | 4770 // With SHM and HugeTLBFS large pages we cannot uncommit a page, so there's no way |
4567 // we can make the adaptive lgrp chunk resizing work. If the user specified | 4771 // we can make the adaptive lgrp chunk resizing work. If the user specified |
4568 // both UseNUMA and UseLargePages (or UseSHM) on the command line - warn and | 4772 // both UseNUMA and UseLargePages (or UseSHM/UseHugeTLBFS) on the command line - warn and |
4569 // disable adaptive resizing. | 4773 // disable adaptive resizing. |
4570 if (UseNUMA && UseLargePages && UseSHM) { | 4774 if (UseNUMA && UseLargePages && !can_commit_large_page_memory()) { |
4571 if (!FLAG_IS_DEFAULT(UseNUMA)) { | 4775 if (FLAG_IS_DEFAULT(UseNUMA)) { |
4572 if (FLAG_IS_DEFAULT(UseLargePages) && FLAG_IS_DEFAULT(UseSHM)) { | 4776 UseNUMA = false; |
4777 } else { | |
4778 if (FLAG_IS_DEFAULT(UseLargePages) && | |
4779 FLAG_IS_DEFAULT(UseSHM) && | |
4780 FLAG_IS_DEFAULT(UseHugeTLBFS)) { | |
4573 UseLargePages = false; | 4781 UseLargePages = false; |
4574 } else { | 4782 } else { |
4575 warning("UseNUMA is not fully compatible with SHM large pages, disabling adaptive resizing"); | 4783 warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing"); |
4576 UseAdaptiveSizePolicy = false; | 4784 UseAdaptiveSizePolicy = false; |
4577 UseAdaptiveNUMAChunkSizing = false; | 4785 UseAdaptiveNUMAChunkSizing = false; |
4578 } | 4786 } |
4579 } else { | |
4580 UseNUMA = false; | |
4581 } | 4787 } |
4582 } | 4788 } |
4583 if (!UseNUMA && ForceNUMA) { | 4789 if (!UseNUMA && ForceNUMA) { |
4584 UseNUMA = true; | 4790 UseNUMA = true; |
4585 } | 4791 } |
5846 new MemNotifyThread(fd); | 6052 new MemNotifyThread(fd); |
5847 } | 6053 } |
5848 } | 6054 } |
5849 | 6055 |
5850 #endif // JAVASE_EMBEDDED | 6056 #endif // JAVASE_EMBEDDED |
6057 | |
6058 | |
6059 /////////////// Unit tests /////////////// | |
6060 | |
6061 #ifndef PRODUCT | |
6062 | |
6063 #define test_log(...) \ | |
6064 do {\ | |
6065 if (VerboseInternalVMTests) { \ | |
6066 tty->print_cr(__VA_ARGS__); \ | |
6067 tty->flush(); \ | |
6068 }\ | |
6069 } while (false) | |
6070 | |
6071 class TestReserveMemorySpecial : AllStatic { | |
6072 public: | |
6073 static void small_page_write(void* addr, size_t size) { | |
6074 size_t page_size = os::vm_page_size(); | |
6075 | |
6076 char* end = (char*)addr + size; | |
6077 for (char* p = (char*)addr; p < end; p += page_size) { | |
6078 *p = 1; | |
6079 } | |
6080 } | |
6081 | |
6082 static void test_reserve_memory_special_huge_tlbfs_only(size_t size) { | |
6083 if (!UseHugeTLBFS) { | |
6084 return; | |
6085 } | |
6086 | |
6087 test_log("test_reserve_memory_special_huge_tlbfs_only(" SIZE_FORMAT ")", size); | |
6088 | |
6089 char* addr = os::Linux::reserve_memory_special_huge_tlbfs_only(size, NULL, false); | |
6090 | |
6091 if (addr != NULL) { | |
6092 small_page_write(addr, size); | |
6093 | |
6094 os::Linux::release_memory_special_huge_tlbfs(addr, size); | |
6095 } | |
6096 } | |
6097 | |
6098 static void test_reserve_memory_special_huge_tlbfs_only() { | |
6099 if (!UseHugeTLBFS) { | |
6100 return; | |
6101 } | |
6102 | |
6103 size_t lp = os::large_page_size(); | |
6104 | |
6105 for (size_t size = lp; size <= lp * 10; size += lp) { | |
6106 test_reserve_memory_special_huge_tlbfs_only(size); | |
6107 } | |
6108 } | |
6109 | |
6110 static void test_reserve_memory_special_huge_tlbfs_mixed(size_t size, size_t alignment) { | |
6111 if (!UseHugeTLBFS) { | |
6112 return; | |
6113 } | |
6114 | |
6115 test_log("test_reserve_memory_special_huge_tlbfs_mixed(" SIZE_FORMAT ", " SIZE_FORMAT ")", | |
6116 size, alignment); | |
6117 | |
6118 assert(size >= os::large_page_size(), "Incorrect input to test"); | |
6119 | |
6120 char* addr = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, NULL, false); | |
6121 | |
6122 if (addr != NULL) { | |
6123 small_page_write(addr, size); | |
6124 | |
6125 os::Linux::release_memory_special_huge_tlbfs(addr, size); | |
6126 } | |
6127 } | |
6128 | |
6129 static void test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(size_t size) { | |
6130 size_t lp = os::large_page_size(); | |
6131 size_t ag = os::vm_allocation_granularity(); | |
6132 | |
6133 for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) { | |
6134 test_reserve_memory_special_huge_tlbfs_mixed(size, alignment); | |
6135 } | |
6136 } | |
6137 | |
6138 static void test_reserve_memory_special_huge_tlbfs_mixed() { | |
6139 size_t lp = os::large_page_size(); | |
6140 size_t ag = os::vm_allocation_granularity(); | |
6141 | |
6142 test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp); | |
6143 test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + ag); | |
6144 test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + lp / 2); | |
6145 test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2); | |
6146 test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + ag); | |
6147 test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 - ag); | |
6148 test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + lp / 2); | |
6149 test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10); | |
6150 test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10 + lp / 2); | |
6151 } | |
6152 | |
6153 static void test_reserve_memory_special_huge_tlbfs() { | |
6154 if (!UseHugeTLBFS) { | |
6155 return; | |
6156 } | |
6157 | |
6158 test_reserve_memory_special_huge_tlbfs_only(); | |
6159 test_reserve_memory_special_huge_tlbfs_mixed(); | |
6160 } | |
6161 | |
6162 static void test_reserve_memory_special_shm(size_t size, size_t alignment) { | |
6163 if (!UseSHM) { | |
6164 return; | |
6165 } | |
6166 | |
6167 test_log("test_reserve_memory_special_shm(" SIZE_FORMAT ", " SIZE_FORMAT ")", size, alignment); | |
6168 | |
6169 char* addr = os::Linux::reserve_memory_special_shm(size, alignment, NULL, false); | |
6170 | |
6171 if (addr != NULL) { | |
6172 assert(is_ptr_aligned(addr, alignment), "Check"); | |
6173 assert(is_ptr_aligned(addr, os::large_page_size()), "Check"); | |
6174 | |
6175 small_page_write(addr, size); | |
6176 | |
6177 os::Linux::release_memory_special_shm(addr, size); | |
6178 } | |
6179 } | |
6180 | |
6181 static void test_reserve_memory_special_shm() { | |
6182 size_t lp = os::large_page_size(); | |
6183 size_t ag = os::vm_allocation_granularity(); | |
6184 | |
6185 for (size_t size = ag; size < lp * 3; size += ag) { | |
6186 for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) { | |
6187 test_reserve_memory_special_shm(size, alignment); | |
6188 } | |
6189 } | |
6190 } | |
6191 | |
6192 static void test() { | |
6193 test_reserve_memory_special_huge_tlbfs(); | |
6194 test_reserve_memory_special_shm(); | |
6195 } | |
6196 }; | |
6197 | |
6198 void TestReserveMemorySpecial_test() { | |
6199 TestReserveMemorySpecial::test(); | |
6200 } | |
6201 | |
6202 #endif |