comparison src/os/windows/vm/os_windows.cpp @ 3885:3cd0157e1d4d

7082969: NUMA interleaving Summary: Support interleaving on NUMA systems for collectors that don't have NUMA-awareness. Reviewed-by: iveresov, ysr Contributed-by: Tom Deneau <tom.deneau@amd.com>
author iveresov
date Thu, 25 Aug 2011 02:57:46 -0700
parents 279ef1916773
children a6128a8ed624
comparison
equal deleted inserted replaced
3871:2f27ed2a98fa 3885:3cd0157e1d4d
2612 #endif 2612 #endif
2613 2613
2614 static HANDLE _hProcess; 2614 static HANDLE _hProcess;
2615 static HANDLE _hToken; 2615 static HANDLE _hToken;
2616 2616
2617 // Container for NUMA node list info
2618 class NUMANodeListHolder {
2619 private:
2620 int *_numa_used_node_list; // allocated below
2621 int _numa_used_node_count;
2622
2623 void free_node_list() {
2624 if (_numa_used_node_list != NULL) {
2625 FREE_C_HEAP_ARRAY(int, _numa_used_node_list);
2626 }
2627 }
2628
2629 public:
2630 NUMANodeListHolder() {
2631 _numa_used_node_count = 0;
2632 _numa_used_node_list = NULL;
2633 // do rest of initialization in build routine (after function pointers are set up)
2634 }
2635
2636 ~NUMANodeListHolder() {
2637 free_node_list();
2638 }
2639
2640 bool build() {
2641 DWORD_PTR proc_aff_mask;
2642 DWORD_PTR sys_aff_mask;
2643 if (!GetProcessAffinityMask(GetCurrentProcess(), &proc_aff_mask, &sys_aff_mask)) return false;
2644 ULONG highest_node_number;
2645 if (!os::Kernel32Dll::GetNumaHighestNodeNumber(&highest_node_number)) return false;
2646 free_node_list();
2647 _numa_used_node_list = NEW_C_HEAP_ARRAY(int, highest_node_number);
2648 for (unsigned int i = 0; i <= highest_node_number; i++) {
2649 ULONGLONG proc_mask_numa_node;
2650 if (!os::Kernel32Dll::GetNumaNodeProcessorMask(i, &proc_mask_numa_node)) return false;
2651 if ((proc_aff_mask & proc_mask_numa_node)!=0) {
2652 _numa_used_node_list[_numa_used_node_count++] = i;
2653 }
2654 }
2655 return (_numa_used_node_count > 1);
2656 }
2657
2658 int get_count() {return _numa_used_node_count;}
2659 int get_node_list_entry(int n) {
2660 // for indexes out of range, returns -1
2661 return (n < _numa_used_node_count ? _numa_used_node_list[n] : -1);
2662 }
2663
2664 } numa_node_list_holder;
2665
2666
2667
2617 static size_t _large_page_size = 0; 2668 static size_t _large_page_size = 0;
2618 2669
2619 static bool resolve_functions_for_large_page_init() { 2670 static bool resolve_functions_for_large_page_init() {
2620 return os::Kernel32Dll::GetLargePageMinimumAvailable() && 2671 return os::Kernel32Dll::GetLargePageMinimumAvailable() &&
2621 os::Advapi32Dll::AdvapiAvailable(); 2672 os::Advapi32Dll::AdvapiAvailable();
2650 if (_hProcess) CloseHandle(_hProcess); 2701 if (_hProcess) CloseHandle(_hProcess);
2651 _hProcess = NULL; 2702 _hProcess = NULL;
2652 if (_hToken) CloseHandle(_hToken); 2703 if (_hToken) CloseHandle(_hToken);
2653 _hToken = NULL; 2704 _hToken = NULL;
2654 } 2705 }
2706
2707 static bool numa_interleaving_init() {
2708 bool success = false;
2709 bool use_numa_specified = !FLAG_IS_DEFAULT(UseNUMA);
2710 bool use_numa_interleaving_specified = !FLAG_IS_DEFAULT(UseNUMAInterleaving);
2711
2712 // print a warning if UseNUMA or UseNUMAInterleaving flag is specified on command line
2713 bool warn_on_failure = use_numa_specified || use_numa_interleaving_specified;
2714 # define WARN(msg) if (warn_on_failure) { warning(msg); }
2715
2716 // NUMAInterleaveGranularity cannot be less than vm_allocation_granularity (or _large_page_size if using large pages)
2717 size_t min_interleave_granularity = UseLargePages ? _large_page_size : os::vm_allocation_granularity();
2718 NUMAInterleaveGranularity = align_size_up(NUMAInterleaveGranularity, min_interleave_granularity);
2719
2720 if (os::Kernel32Dll::NumaCallsAvailable()) {
2721 if (numa_node_list_holder.build()) {
2722 if (PrintMiscellaneous && Verbose) {
2723 tty->print("NUMA UsedNodeCount=%d, namely ", os::numa_get_groups_num());
2724 for (int i = 0; i < numa_node_list_holder.get_count(); i++) {
2725 tty->print("%d ", numa_node_list_holder.get_node_list_entry(i));
2726 }
2727 tty->print("\n");
2728 }
2729 success = true;
2730 } else {
2731 WARN("Process does not cover multiple NUMA nodes.");
2732 }
2733 } else {
2734 WARN("NUMA Interleaving is not supported by the operating system.");
2735 }
2736 if (!success) {
2737 if (use_numa_specified) WARN("...Ignoring UseNUMA flag.");
2738 if (use_numa_interleaving_specified) WARN("...Ignoring UseNUMAInterleaving flag.");
2739 }
2740 return success;
2741 #undef WARN
2742 }
2743
2744 // this routine is used whenever we need to reserve a contiguous VA range
2745 // but we need to make separate VirtualAlloc calls for each piece of the range
2746 // Reasons for doing this:
2747 // * UseLargePagesIndividualAllocation was set (normally only needed on WS2003 but possible to be set otherwise)
2748 // * UseNUMAInterleaving requires a separate node for each piece
2749 static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, DWORD prot,
2750 bool should_inject_error=false) {
2751 char * p_buf;
2752 // note: at setup time we guaranteed that NUMAInterleaveGranularity was aligned up to a page size
2753 size_t page_size = UseLargePages ? _large_page_size : os::vm_allocation_granularity();
2754 size_t chunk_size = UseNUMAInterleaving ? NUMAInterleaveGranularity : page_size;
2755
2756 // first reserve enough address space in advance since we want to be
2757 // able to break a single contiguous virtual address range into multiple
2758 // large page commits but WS2003 does not allow reserving large page space
2759 // so we just use 4K pages for reserve, this gives us a legal contiguous
2760 // address space. then we will deallocate that reservation, and re alloc
2761 // using large pages
2762 const size_t size_of_reserve = bytes + chunk_size;
2763 if (bytes > size_of_reserve) {
2764 // Overflowed.
2765 return NULL;
2766 }
2767 p_buf = (char *) VirtualAlloc(addr,
2768 size_of_reserve, // size of Reserve
2769 MEM_RESERVE,
2770 PAGE_READWRITE);
2771 // If reservation failed, return NULL
2772 if (p_buf == NULL) return NULL;
2773
2774 os::release_memory(p_buf, bytes + chunk_size);
2775
2776 // we still need to round up to a page boundary (in case we are using large pages)
2777 // but not to a chunk boundary (in case InterleavingGranularity doesn't align with page size)
2778 // instead we handle this in the bytes_to_rq computation below
2779 p_buf = (char *) align_size_up((size_t)p_buf, page_size);
2780
2781 // now go through and allocate one chunk at a time until all bytes are
2782 // allocated
2783 size_t bytes_remaining = bytes;
2784 // An overflow of align_size_up() would have been caught above
2785 // in the calculation of size_of_reserve.
2786 char * next_alloc_addr = p_buf;
2787 HANDLE hProc = GetCurrentProcess();
2788
2789 #ifdef ASSERT
2790 // Variable for the failure injection
2791 long ran_num = os::random();
2792 size_t fail_after = ran_num % bytes;
2793 #endif
2794
2795 int count=0;
2796 while (bytes_remaining) {
2797 // select bytes_to_rq to get to the next chunk_size boundary
2798
2799 size_t bytes_to_rq = MIN2(bytes_remaining, chunk_size - ((size_t)next_alloc_addr % chunk_size));
2800 // Note allocate and commit
2801 char * p_new;
2802
2803 #ifdef ASSERT
2804 bool inject_error_now = should_inject_error && (bytes_remaining <= fail_after);
2805 #else
2806 const bool inject_error_now = false;
2807 #endif
2808
2809 if (inject_error_now) {
2810 p_new = NULL;
2811 } else {
2812 if (!UseNUMAInterleaving) {
2813 p_new = (char *) VirtualAlloc(next_alloc_addr,
2814 bytes_to_rq,
2815 flags,
2816 prot);
2817 } else {
2818 // get the next node to use from the used_node_list
2819 DWORD node = numa_node_list_holder.get_node_list_entry(count % os::numa_get_groups_num());
2820 p_new = (char *)os::Kernel32Dll::VirtualAllocExNuma(hProc,
2821 next_alloc_addr,
2822 bytes_to_rq,
2823 flags,
2824 prot,
2825 node);
2826 }
2827 }
2828
2829 if (p_new == NULL) {
2830 // Free any allocated pages
2831 if (next_alloc_addr > p_buf) {
2832 // Some memory was committed so release it.
2833 size_t bytes_to_release = bytes - bytes_remaining;
2834 os::release_memory(p_buf, bytes_to_release);
2835 }
2836 #ifdef ASSERT
2837 if (should_inject_error) {
2838 if (TracePageSizes && Verbose) {
2839 tty->print_cr("Reserving pages individually failed.");
2840 }
2841 }
2842 #endif
2843 return NULL;
2844 }
2845 bytes_remaining -= bytes_to_rq;
2846 next_alloc_addr += bytes_to_rq;
2847 count++;
2848 }
2849 // made it this far, success
2850 return p_buf;
2851 }
2852
2853
2655 2854
2656 void os::large_page_init() { 2855 void os::large_page_init() {
2657 if (!UseLargePages) return; 2856 if (!UseLargePages) return;
2658 2857
2659 // print a warning if any large page related flag is specified on command line 2858 // print a warning if any large page related flag is specified on command line
2720 2919
2721 char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) { 2920 char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) {
2722 assert((size_t)addr % os::vm_allocation_granularity() == 0, 2921 assert((size_t)addr % os::vm_allocation_granularity() == 0,
2723 "reserve alignment"); 2922 "reserve alignment");
2724 assert(bytes % os::vm_allocation_granularity() == 0, "reserve block size"); 2923 assert(bytes % os::vm_allocation_granularity() == 0, "reserve block size");
2725 char* res = (char*)VirtualAlloc(addr, bytes, MEM_RESERVE, PAGE_READWRITE); 2924 char* res;
2925 // note that if UseLargePages is on, all the areas that require interleaving
2926 // will go thru reserve_memory_special rather than thru here.
2927 bool use_individual = (UseNUMAInterleaving && !UseLargePages);
2928 if (!use_individual) {
2929 res = (char*)VirtualAlloc(addr, bytes, MEM_RESERVE, PAGE_READWRITE);
2930 } else {
2931 elapsedTimer reserveTimer;
2932 if( Verbose && PrintMiscellaneous ) reserveTimer.start();
2933 // in numa interleaving, we have to allocate pages individually
2934 // (well really chunks of NUMAInterleaveGranularity size)
2935 res = allocate_pages_individually(bytes, addr, MEM_RESERVE, PAGE_READWRITE);
2936 if (res == NULL) {
2937 warning("NUMA page allocation failed");
2938 }
2939 if( Verbose && PrintMiscellaneous ) {
2940 reserveTimer.stop();
2941 tty->print_cr("reserve_memory of %Ix bytes took %ld ms (%ld ticks)", bytes,
2942 reserveTimer.milliseconds(), reserveTimer.ticks());
2943 }
2944 }
2726 assert(res == NULL || addr == NULL || addr == res, 2945 assert(res == NULL || addr == NULL || addr == res,
2727 "Unexpected address from reserve."); 2946 "Unexpected address from reserve.");
2947
2728 return res; 2948 return res;
2729 } 2949 }
2730 2950
2731 // Reserve memory at an arbitrary address, only if that area is 2951 // Reserve memory at an arbitrary address, only if that area is
2732 // available (and not reserved for something else). 2952 // available (and not reserved for something else).
2752 } 2972 }
2753 2973
2754 char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) { 2974 char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) {
2755 2975
2756 const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; 2976 const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
2757 2977 const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
2758 if (UseLargePagesIndividualAllocation) { 2978
2979 // with large pages, there are two cases where we need to use Individual Allocation
2980 // 1) the UseLargePagesIndividualAllocation flag is set (set by default on WS2003)
2981 // 2) NUMA Interleaving is enabled, in which case we use a different node for each page
2982 if (UseLargePagesIndividualAllocation || UseNUMAInterleaving) {
2759 if (TracePageSizes && Verbose) { 2983 if (TracePageSizes && Verbose) {
2760 tty->print_cr("Reserving large pages individually."); 2984 tty->print_cr("Reserving large pages individually.");
2761 } 2985 }
2762 char * p_buf; 2986 char * p_buf = allocate_pages_individually(bytes, addr, flags, prot, LargePagesIndividualAllocationInjectError);
2763 // first reserve enough address space in advance since we want to be 2987 if (p_buf == NULL) {
2764 // able to break a single contiguous virtual address range into multiple 2988 // give an appropriate warning message
2765 // large page commits but WS2003 does not allow reserving large page space 2989 if (UseNUMAInterleaving) {
2766 // so we just use 4K pages for reserve, this gives us a legal contiguous 2990 warning("NUMA large page allocation failed, UseLargePages flag ignored");
2767 // address space. then we will deallocate that reservation, and re alloc 2991 }
2768 // using large pages 2992 if (UseLargePagesIndividualAllocation) {
2769 const size_t size_of_reserve = bytes + _large_page_size; 2993 warning("Individually allocated large pages failed, "
2770 if (bytes > size_of_reserve) { 2994 "use -XX:-UseLargePagesIndividualAllocation to turn off");
2771 // Overflowed. 2995 }
2772 warning("Individually allocated large pages failed, "
2773 "use -XX:-UseLargePagesIndividualAllocation to turn off");
2774 return NULL; 2996 return NULL;
2775 }
2776 p_buf = (char *) VirtualAlloc(addr,
2777 size_of_reserve, // size of Reserve
2778 MEM_RESERVE,
2779 PAGE_READWRITE);
2780 // If reservation failed, return NULL
2781 if (p_buf == NULL) return NULL;
2782
2783 release_memory(p_buf, bytes + _large_page_size);
2784 // round up to page boundary. If the size_of_reserve did not
2785 // overflow and the reservation did not fail, this align up
2786 // should not overflow.
2787 p_buf = (char *) align_size_up((size_t)p_buf, _large_page_size);
2788
2789 // now go through and allocate one page at a time until all bytes are
2790 // allocated
2791 size_t bytes_remaining = align_size_up(bytes, _large_page_size);
2792 // An overflow of align_size_up() would have been caught above
2793 // in the calculation of size_of_reserve.
2794 char * next_alloc_addr = p_buf;
2795
2796 #ifdef ASSERT
2797 // Variable for the failure injection
2798 long ran_num = os::random();
2799 size_t fail_after = ran_num % bytes;
2800 #endif
2801
2802 while (bytes_remaining) {
2803 size_t bytes_to_rq = MIN2(bytes_remaining, _large_page_size);
2804 // Note allocate and commit
2805 char * p_new;
2806
2807 #ifdef ASSERT
2808 bool inject_error = LargePagesIndividualAllocationInjectError &&
2809 (bytes_remaining <= fail_after);
2810 #else
2811 const bool inject_error = false;
2812 #endif
2813
2814 if (inject_error) {
2815 p_new = NULL;
2816 } else {
2817 p_new = (char *) VirtualAlloc(next_alloc_addr,
2818 bytes_to_rq,
2819 MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES,
2820 prot);
2821 }
2822
2823 if (p_new == NULL) {
2824 // Free any allocated pages
2825 if (next_alloc_addr > p_buf) {
2826 // Some memory was committed so release it.
2827 size_t bytes_to_release = bytes - bytes_remaining;
2828 release_memory(p_buf, bytes_to_release);
2829 }
2830 #ifdef ASSERT
2831 if (UseLargePagesIndividualAllocation &&
2832 LargePagesIndividualAllocationInjectError) {
2833 if (TracePageSizes && Verbose) {
2834 tty->print_cr("Reserving large pages individually failed.");
2835 }
2836 }
2837 #endif
2838 return NULL;
2839 }
2840 bytes_remaining -= bytes_to_rq;
2841 next_alloc_addr += bytes_to_rq;
2842 } 2997 }
2843 2998
2844 return p_buf; 2999 return p_buf;
2845 3000
2846 } else { 3001 } else {
2865 } 3020 }
2866 assert((size_t) addr % os::vm_page_size() == 0, "commit on page boundaries"); 3021 assert((size_t) addr % os::vm_page_size() == 0, "commit on page boundaries");
2867 assert(bytes % os::vm_page_size() == 0, "commit in page-sized chunks"); 3022 assert(bytes % os::vm_page_size() == 0, "commit in page-sized chunks");
2868 // Don't attempt to print anything if the OS call fails. We're 3023 // Don't attempt to print anything if the OS call fails. We're
2869 // probably low on resources, so the print itself may cause crashes. 3024 // probably low on resources, so the print itself may cause crashes.
2870 bool result = VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE) != 0; 3025
2871 if (result != NULL && exec) { 3026 // unless we have NUMAInterleaving enabled, the range of a commit
2872 DWORD oldprot; 3027 // is always within a reserve covered by a single VirtualAlloc
2873 // Windows doc says to use VirtualProtect to get execute permissions 3028 // in that case we can just do a single commit for the requested size
2874 return VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &oldprot) != 0; 3029 if (!UseNUMAInterleaving) {
3030 if (VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE) == NULL) return false;
3031 if (exec) {
3032 DWORD oldprot;
3033 // Windows doc says to use VirtualProtect to get execute permissions
3034 if (!VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &oldprot)) return false;
3035 }
3036 return true;
2875 } else { 3037 } else {
2876 return result; 3038
2877 } 3039 // when NUMAInterleaving is enabled, the commit might cover a range that
3040 // came from multiple VirtualAlloc reserves (using allocate_pages_individually).
3041 // VirtualQuery can help us determine that. The RegionSize that VirtualQuery
3042 // returns represents the number of bytes that can be committed in one step.
3043 size_t bytes_remaining = bytes;
3044 char * next_alloc_addr = addr;
3045 while (bytes_remaining > 0) {
3046 MEMORY_BASIC_INFORMATION alloc_info;
3047 VirtualQuery(next_alloc_addr, &alloc_info, sizeof(alloc_info));
3048 size_t bytes_to_rq = MIN2(bytes_remaining, (size_t)alloc_info.RegionSize);
3049 if (VirtualAlloc(next_alloc_addr, bytes_to_rq, MEM_COMMIT, PAGE_READWRITE) == NULL)
3050 return false;
3051 if (exec) {
3052 DWORD oldprot;
3053 if (!VirtualProtect(next_alloc_addr, bytes_to_rq, PAGE_EXECUTE_READWRITE, &oldprot))
3054 return false;
3055 }
3056 bytes_remaining -= bytes_to_rq;
3057 next_alloc_addr += bytes_to_rq;
3058 }
3059 }
3060 // if we made it this far, return true
3061 return true;
2878 } 3062 }
2879 3063
2880 bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, 3064 bool os::commit_memory(char* addr, size_t size, size_t alignment_hint,
2881 bool exec) { 3065 bool exec) {
2882 return commit_memory(addr, size, exec); 3066 return commit_memory(addr, size, exec);
2946 void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { } 3130 void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { }
2947 void os::free_memory(char *addr, size_t bytes) { } 3131 void os::free_memory(char *addr, size_t bytes) { }
2948 void os::numa_make_global(char *addr, size_t bytes) { } 3132 void os::numa_make_global(char *addr, size_t bytes) { }
2949 void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } 3133 void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { }
2950 bool os::numa_topology_changed() { return false; } 3134 bool os::numa_topology_changed() { return false; }
2951 size_t os::numa_get_groups_num() { return 1; } 3135 size_t os::numa_get_groups_num() { return numa_node_list_holder.get_count(); }
2952 int os::numa_get_group_id() { return 0; } 3136 int os::numa_get_group_id() { return 0; }
2953 size_t os::numa_get_leaf_groups(int *ids, size_t size) { 3137 size_t os::numa_get_leaf_groups(int *ids, size_t size) {
2954 if (size > 0) { 3138 // check for size bigger than actual groups_num
2955 ids[0] = 0; 3139 size = MIN2(size, numa_get_groups_num());
2956 return 1; 3140 for (int i = 0; i < (int)size; i++) {
2957 } 3141 ids[i] = numa_node_list_holder.get_node_list_entry(i);
2958 return 0; 3142 }
3143 return size;
2959 } 3144 }
2960 3145
2961 bool os::get_page_info(char *start, page_info* info) { 3146 bool os::get_page_info(char *start, page_info* info) {
2962 return false; 3147 return false;
2963 } 3148 }
3478 3663
3479 #ifndef PRODUCT 3664 #ifndef PRODUCT
3480 if(Verbose && PrintMiscellaneous) 3665 if(Verbose && PrintMiscellaneous)
3481 tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", (intptr_t)mem_serialize_page); 3666 tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", (intptr_t)mem_serialize_page);
3482 #endif 3667 #endif
3483 } 3668 }
3484 3669
3485 os::large_page_init(); 3670 os::large_page_init();
3486 3671
3487 // Setup Windows Exceptions 3672 // Setup Windows Exceptions
3488 3673
3581 #endif 3766 #endif
3582 3767
3583 // initialize thread priority policy 3768 // initialize thread priority policy
3584 prio_init(); 3769 prio_init();
3585 3770
3586 if (UseNUMA && !ForceNUMA) { 3771 if (UseNUMAInterleaving) {
3587 UseNUMA = false; // Currently unsupported. 3772 // first check whether this Windows OS supports VirtualAllocExNuma, if not ignore this flag
3773 bool success = numa_interleaving_init();
3774 if (!success) UseNUMAInterleaving = false;
3588 } 3775 }
3589 3776
3590 return JNI_OK; 3777 return JNI_OK;
3591 } 3778 }
3592 3779
4756 } 4943 }
4757 4944
4758 4945
4759 // Kernel32 API 4946 // Kernel32 API
4760 typedef SIZE_T (WINAPI* GetLargePageMinimum_Fn)(void); 4947 typedef SIZE_T (WINAPI* GetLargePageMinimum_Fn)(void);
4948 typedef LPVOID (WINAPI *VirtualAllocExNuma_Fn) (HANDLE, LPVOID, SIZE_T, DWORD, DWORD, DWORD);
4949 typedef BOOL (WINAPI *GetNumaHighestNodeNumber_Fn) (PULONG);
4950 typedef BOOL (WINAPI *GetNumaNodeProcessorMask_Fn) (UCHAR, PULONGLONG);
4951
4761 GetLargePageMinimum_Fn os::Kernel32Dll::_GetLargePageMinimum = NULL; 4952 GetLargePageMinimum_Fn os::Kernel32Dll::_GetLargePageMinimum = NULL;
4953 VirtualAllocExNuma_Fn os::Kernel32Dll::_VirtualAllocExNuma = NULL;
4954 GetNumaHighestNodeNumber_Fn os::Kernel32Dll::_GetNumaHighestNodeNumber = NULL;
4955 GetNumaNodeProcessorMask_Fn os::Kernel32Dll::_GetNumaNodeProcessorMask = NULL;
4762 BOOL os::Kernel32Dll::initialized = FALSE; 4956 BOOL os::Kernel32Dll::initialized = FALSE;
4763 SIZE_T os::Kernel32Dll::GetLargePageMinimum() { 4957 SIZE_T os::Kernel32Dll::GetLargePageMinimum() {
4764 assert(initialized && _GetLargePageMinimum != NULL, 4958 assert(initialized && _GetLargePageMinimum != NULL,
4765 "GetLargePageMinimumAvailable() not yet called"); 4959 "GetLargePageMinimumAvailable() not yet called");
4766 return _GetLargePageMinimum(); 4960 return _GetLargePageMinimum();
4771 initialize(); 4965 initialize();
4772 } 4966 }
4773 return _GetLargePageMinimum != NULL; 4967 return _GetLargePageMinimum != NULL;
4774 } 4968 }
4775 4969
4776 4970 BOOL os::Kernel32Dll::NumaCallsAvailable() {
4777 #ifndef JDK6_OR_EARLIER 4971 if (!initialized) {
4778 4972 initialize();
4779 void os::Kernel32Dll::initialize() { 4973 }
4974 return _VirtualAllocExNuma != NULL;
4975 }
4976
4977 LPVOID os::Kernel32Dll::VirtualAllocExNuma(HANDLE hProc, LPVOID addr, SIZE_T bytes, DWORD flags, DWORD prot, DWORD node) {
4978 assert(initialized && _VirtualAllocExNuma != NULL,
4979 "NUMACallsAvailable() not yet called");
4980
4981 return _VirtualAllocExNuma(hProc, addr, bytes, flags, prot, node);
4982 }
4983
4984 BOOL os::Kernel32Dll::GetNumaHighestNodeNumber(PULONG ptr_highest_node_number) {
4985 assert(initialized && _GetNumaHighestNodeNumber != NULL,
4986 "NUMACallsAvailable() not yet called");
4987
4988 return _GetNumaHighestNodeNumber(ptr_highest_node_number);
4989 }
4990
4991 BOOL os::Kernel32Dll::GetNumaNodeProcessorMask(UCHAR node, PULONGLONG proc_mask) {
4992 assert(initialized && _GetNumaNodeProcessorMask != NULL,
4993 "NUMACallsAvailable() not yet called");
4994
4995 return _GetNumaNodeProcessorMask(node, proc_mask);
4996 }
4997
4998
4999 void os::Kernel32Dll::initializeCommon() {
4780 if (!initialized) { 5000 if (!initialized) {
4781 HMODULE handle = ::GetModuleHandle("Kernel32.dll"); 5001 HMODULE handle = ::GetModuleHandle("Kernel32.dll");
4782 assert(handle != NULL, "Just check"); 5002 assert(handle != NULL, "Just check");
4783 _GetLargePageMinimum = (GetLargePageMinimum_Fn)::GetProcAddress(handle, "GetLargePageMinimum"); 5003 _GetLargePageMinimum = (GetLargePageMinimum_Fn)::GetProcAddress(handle, "GetLargePageMinimum");
5004 _VirtualAllocExNuma = (VirtualAllocExNuma_Fn)::GetProcAddress(handle, "VirtualAllocExNuma");
5005 _GetNumaHighestNodeNumber = (GetNumaHighestNodeNumber_Fn)::GetProcAddress(handle, "GetNumaHighestNodeNumber");
5006 _GetNumaNodeProcessorMask = (GetNumaNodeProcessorMask_Fn)::GetProcAddress(handle, "GetNumaNodeProcessorMask");
4784 initialized = TRUE; 5007 initialized = TRUE;
4785 } 5008 }
5009 }
5010
5011
5012
5013 #ifndef JDK6_OR_EARLIER
5014
5015 void os::Kernel32Dll::initialize() {
5016 initializeCommon();
4786 } 5017 }
4787 5018
4788 5019
4789 // Kernel32 API 5020 // Kernel32 API
4790 inline BOOL os::Kernel32Dll::SwitchToThread() { 5021 inline BOOL os::Kernel32Dll::SwitchToThread() {
4885 CreateToolhelp32Snapshot_Fn os::Kernel32Dll::_CreateToolhelp32Snapshot = NULL; 5116 CreateToolhelp32Snapshot_Fn os::Kernel32Dll::_CreateToolhelp32Snapshot = NULL;
4886 Module32First_Fn os::Kernel32Dll::_Module32First = NULL; 5117 Module32First_Fn os::Kernel32Dll::_Module32First = NULL;
4887 Module32Next_Fn os::Kernel32Dll::_Module32Next = NULL; 5118 Module32Next_Fn os::Kernel32Dll::_Module32Next = NULL;
4888 GetNativeSystemInfo_Fn os::Kernel32Dll::_GetNativeSystemInfo = NULL; 5119 GetNativeSystemInfo_Fn os::Kernel32Dll::_GetNativeSystemInfo = NULL;
4889 5120
5121
4890 void os::Kernel32Dll::initialize() { 5122 void os::Kernel32Dll::initialize() {
4891 if (!initialized) { 5123 if (!initialized) {
4892 HMODULE handle = ::GetModuleHandle("Kernel32.dll"); 5124 HMODULE handle = ::GetModuleHandle("Kernel32.dll");
4893 assert(handle != NULL, "Just check"); 5125 assert(handle != NULL, "Just check");
4894 5126
4895 _SwitchToThread = (SwitchToThread_Fn)::GetProcAddress(handle, "SwitchToThread"); 5127 _SwitchToThread = (SwitchToThread_Fn)::GetProcAddress(handle, "SwitchToThread");
4896 _GetLargePageMinimum = (GetLargePageMinimum_Fn)::GetProcAddress(handle, "GetLargePageMinimum");
4897 _CreateToolhelp32Snapshot = (CreateToolhelp32Snapshot_Fn) 5128 _CreateToolhelp32Snapshot = (CreateToolhelp32Snapshot_Fn)
4898 ::GetProcAddress(handle, "CreateToolhelp32Snapshot"); 5129 ::GetProcAddress(handle, "CreateToolhelp32Snapshot");
4899 _Module32First = (Module32First_Fn)::GetProcAddress(handle, "Module32First"); 5130 _Module32First = (Module32First_Fn)::GetProcAddress(handle, "Module32First");
4900 _Module32Next = (Module32Next_Fn)::GetProcAddress(handle, "Module32Next"); 5131 _Module32Next = (Module32Next_Fn)::GetProcAddress(handle, "Module32Next");
4901 _GetNativeSystemInfo = (GetNativeSystemInfo_Fn)::GetProcAddress(handle, "GetNativeSystemInfo"); 5132 _GetNativeSystemInfo = (GetNativeSystemInfo_Fn)::GetProcAddress(handle, "GetNativeSystemInfo");
5133 initializeCommon(); // resolve the functions that always need resolving
4902 5134
4903 initialized = TRUE; 5135 initialized = TRUE;
4904 } 5136 }
4905 } 5137 }
4906 5138
4961 assert(initialized && _GetNativeSystemInfo != NULL, 5193 assert(initialized && _GetNativeSystemInfo != NULL,
4962 "GetNativeSystemInfoAvailable() not yet called"); 5194 "GetNativeSystemInfoAvailable() not yet called");
4963 5195
4964 _GetNativeSystemInfo(lpSystemInfo); 5196 _GetNativeSystemInfo(lpSystemInfo);
4965 } 5197 }
5198
5199
4966 5200
4967 // PSAPI API 5201 // PSAPI API
4968 5202
4969 5203
4970 typedef BOOL (WINAPI *EnumProcessModules_Fn)(HANDLE, HMODULE *, DWORD, LPDWORD); 5204 typedef BOOL (WINAPI *EnumProcessModules_Fn)(HANDLE, HMODULE *, DWORD, LPDWORD);