Mercurial > hg > graal-jvmci-8
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); |