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 } |
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 |