src/cpu/x86/vm/rdtsc_x86.cpp

Sat, 07 Nov 2020 10:30:02 +0800

author
aoqi
date
Sat, 07 Nov 2020 10:30:02 +0800
changeset 10026
8c95980d0b66
parent 9858
b985cbb00e68
permissions
-rw-r--r--

Added tag mips-jdk8u275-b01 for changeset d3b4d62f391f

apetushkov@9858 1 /*
apetushkov@9858 2 * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
apetushkov@9858 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
apetushkov@9858 4 *
apetushkov@9858 5 * This code is free software; you can redistribute it and/or modify it
apetushkov@9858 6 * under the terms of the GNU General Public License version 2 only, as
apetushkov@9858 7 * published by the Free Software Foundation.
apetushkov@9858 8 *
apetushkov@9858 9 * This code is distributed in the hope that it will be useful, but WITHOUT
apetushkov@9858 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
apetushkov@9858 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
apetushkov@9858 12 * version 2 for more details (a copy is included in the LICENSE file that
apetushkov@9858 13 * accompanied this code).
apetushkov@9858 14 *
apetushkov@9858 15 * You should have received a copy of the GNU General Public License version
apetushkov@9858 16 * 2 along with this work; if not, write to the Free Software Foundation,
apetushkov@9858 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
apetushkov@9858 18 *
apetushkov@9858 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
apetushkov@9858 20 * or visit www.oracle.com if you need additional information or have any
apetushkov@9858 21 * questions.
apetushkov@9858 22 *
apetushkov@9858 23 */
apetushkov@9858 24
apetushkov@9858 25 #include "precompiled.hpp"
apetushkov@9858 26
apetushkov@9858 27 //#include "os_linux_x86.inline.hpp"
apetushkov@9858 28 #ifdef TARGET_OS_ARCH_linux_x86
apetushkov@9858 29 # include "os_linux_x86.inline.hpp"
apetushkov@9858 30 #endif
apetushkov@9858 31 #ifdef TARGET_OS_ARCH_bsd_x86
apetushkov@9858 32 # include "os_bsd_x86.inline.hpp"
apetushkov@9858 33 #endif
apetushkov@9858 34 #ifdef TARGET_OS_ARCH_windows_x86
apetushkov@9858 35 # include "os_windows_x86.inline.hpp"
apetushkov@9858 36 #endif
apetushkov@9858 37 #ifdef TARGET_OS_ARCH_solaris_x86
apetushkov@9858 38 # include "os_solaris_x86.inline.hpp"
apetushkov@9858 39 #endif
apetushkov@9858 40
apetushkov@9858 41 #include "rdtsc_x86.hpp"
apetushkov@9858 42 #include "runtime/thread.inline.hpp"
apetushkov@9858 43 #include "vm_version_ext_x86.hpp"
apetushkov@9858 44 #include "runtime/os.hpp"
apetushkov@9858 45
apetushkov@9858 46 // The following header contains the implementations of rdtsc()
apetushkov@9858 47
apetushkov@9858 48 static jlong _epoch = 0;
apetushkov@9858 49 static bool rdtsc_elapsed_counter_enabled = false;
apetushkov@9858 50 static jlong tsc_frequency = 0;
apetushkov@9858 51
apetushkov@9858 52 static jlong set_epoch() {
apetushkov@9858 53 assert(0 == _epoch, "invariant");
apetushkov@9858 54 _epoch = os::rdtsc();
apetushkov@9858 55 return _epoch;
apetushkov@9858 56 }
apetushkov@9858 57
apetushkov@9858 58 // Base loop to estimate ticks frequency for tsc counter from user mode.
apetushkov@9858 59 // Volatiles and sleep() are used to prevent compiler from applying optimizations.
apetushkov@9858 60 static void do_time_measurements(volatile jlong& time_base,
apetushkov@9858 61 volatile jlong& time_fast,
apetushkov@9858 62 volatile jlong& time_base_elapsed,
apetushkov@9858 63 volatile jlong& time_fast_elapsed) {
apetushkov@9858 64 static const unsigned int FT_SLEEP_MILLISECS = 1;
apetushkov@9858 65 const unsigned int loopcount = 3;
apetushkov@9858 66
apetushkov@9858 67 volatile jlong start = 0;
apetushkov@9858 68 volatile jlong fstart = 0;
apetushkov@9858 69 volatile jlong end = 0;
apetushkov@9858 70 volatile jlong fend = 0;
apetushkov@9858 71
apetushkov@9858 72 // Figure out the difference between rdtsc and os provided timer.
apetushkov@9858 73 // base algorithm adopted from JRockit.
apetushkov@9858 74 for (unsigned int times = 0; times < loopcount; times++) {
apetushkov@9858 75 start = os::elapsed_counter();
apetushkov@9858 76 OrderAccess::fence();
apetushkov@9858 77 fstart = os::rdtsc();
apetushkov@9858 78
apetushkov@9858 79 // use sleep to prevent compiler from optimizing
apetushkov@9858 80 os::sleep(Thread::current(), FT_SLEEP_MILLISECS, true);
apetushkov@9858 81
apetushkov@9858 82 end = os::elapsed_counter();
apetushkov@9858 83 OrderAccess::fence();
apetushkov@9858 84 fend = os::rdtsc();
apetushkov@9858 85
apetushkov@9858 86 time_base += end - start;
apetushkov@9858 87 time_fast += fend - fstart;
apetushkov@9858 88
apetushkov@9858 89 // basis for calculating the os tick start
apetushkov@9858 90 // to fast time tick start offset
apetushkov@9858 91 time_base_elapsed += end;
apetushkov@9858 92 time_fast_elapsed += (fend - _epoch);
apetushkov@9858 93 }
apetushkov@9858 94
apetushkov@9858 95 time_base /= loopcount;
apetushkov@9858 96 time_fast /= loopcount;
apetushkov@9858 97 time_base_elapsed /= loopcount;
apetushkov@9858 98 time_fast_elapsed /= loopcount;
apetushkov@9858 99 }
apetushkov@9858 100
apetushkov@9858 101 static jlong initialize_frequency() {
apetushkov@9858 102 assert(0 == tsc_frequency, "invariant");
apetushkov@9858 103 assert(0 == _epoch, "invariant");
apetushkov@9858 104 const jlong initial_counter = set_epoch();
apetushkov@9858 105 if (initial_counter == 0) {
apetushkov@9858 106 return 0;
apetushkov@9858 107 }
apetushkov@9858 108 // os time frequency
apetushkov@9858 109 static double os_freq = (double)os::elapsed_frequency();
apetushkov@9858 110 assert(os_freq > 0, "os_elapsed frequency corruption!");
apetushkov@9858 111
apetushkov@9858 112 double tsc_freq = .0;
apetushkov@9858 113 double os_to_tsc_conv_factor = 1.0;
apetushkov@9858 114
apetushkov@9858 115 // if platform supports invariant tsc,
apetushkov@9858 116 // apply higher resolution and granularity for conversion calculations
apetushkov@9858 117 if (VM_Version_Ext::supports_tscinv_ext()) {
apetushkov@9858 118 // for invariant tsc platforms, take the maximum qualified cpu frequency
apetushkov@9858 119 tsc_freq = (double)VM_Version_Ext::maximum_qualified_cpu_frequency();
apetushkov@9858 120 os_to_tsc_conv_factor = tsc_freq / os_freq;
apetushkov@9858 121 } else {
apetushkov@9858 122 // use measurements to estimate
apetushkov@9858 123 // a conversion factor and the tsc frequency
apetushkov@9858 124
apetushkov@9858 125 volatile jlong time_base = 0;
apetushkov@9858 126 volatile jlong time_fast = 0;
apetushkov@9858 127 volatile jlong time_base_elapsed = 0;
apetushkov@9858 128 volatile jlong time_fast_elapsed = 0;
apetushkov@9858 129
apetushkov@9858 130 // do measurements to get base data
apetushkov@9858 131 // on os timer and fast ticks tsc time relation.
apetushkov@9858 132 do_time_measurements(time_base, time_fast, time_base_elapsed, time_fast_elapsed);
apetushkov@9858 133
apetushkov@9858 134 // if invalid measurements, cannot proceed
apetushkov@9858 135 if (time_fast == 0 || time_base == 0) {
apetushkov@9858 136 return 0;
apetushkov@9858 137 }
apetushkov@9858 138
apetushkov@9858 139 os_to_tsc_conv_factor = (double)time_fast / (double)time_base;
apetushkov@9858 140 if (os_to_tsc_conv_factor > 1) {
apetushkov@9858 141 // estimate on tsc counter frequency
apetushkov@9858 142 tsc_freq = os_to_tsc_conv_factor * os_freq;
apetushkov@9858 143 }
apetushkov@9858 144 }
apetushkov@9858 145
apetushkov@9858 146 if ((tsc_freq < 0) || (tsc_freq > 0 && tsc_freq <= os_freq) || (os_to_tsc_conv_factor <= 1)) {
apetushkov@9858 147 // safer to run with normal os time
apetushkov@9858 148 tsc_freq = .0;
apetushkov@9858 149 }
apetushkov@9858 150
apetushkov@9858 151 // frequency of the tsc_counter
apetushkov@9858 152 return (jlong)tsc_freq;
apetushkov@9858 153 }
apetushkov@9858 154
apetushkov@9858 155 static bool initialize_elapsed_counter() {
apetushkov@9858 156 tsc_frequency = initialize_frequency();
apetushkov@9858 157 return tsc_frequency != 0 && _epoch != 0;
apetushkov@9858 158 }
apetushkov@9858 159
apetushkov@9858 160 static bool ergonomics() {
apetushkov@9858 161 const bool invtsc_support = Rdtsc::is_supported();
apetushkov@9858 162 if (FLAG_IS_DEFAULT(UseFastUnorderedTimeStamps) && invtsc_support) {
apetushkov@9858 163 FLAG_SET_ERGO(bool, UseFastUnorderedTimeStamps, true);
apetushkov@9858 164 }
apetushkov@9858 165
apetushkov@9858 166 bool ft_enabled = UseFastUnorderedTimeStamps && invtsc_support;
apetushkov@9858 167
apetushkov@9858 168 if (!ft_enabled) {
apetushkov@9858 169 if (UseFastUnorderedTimeStamps && VM_Version::supports_tsc()) {
apetushkov@9858 170 warning("\nThe hardware does not support invariant tsc (INVTSC) register and/or cannot guarantee tsc synchronization between sockets at startup.\n"\
apetushkov@9858 171 "Values returned via rdtsc() are not guaranteed to be accurate, esp. when comparing values from cross sockets reads. Enabling UseFastUnorderedTimeStamps on non-invariant tsc hardware should be considered experimental.\n");
apetushkov@9858 172 ft_enabled = true;
apetushkov@9858 173 }
apetushkov@9858 174 }
apetushkov@9858 175
apetushkov@9858 176 if (!ft_enabled) {
apetushkov@9858 177 // Warn if unable to support command-line flag
apetushkov@9858 178 if (UseFastUnorderedTimeStamps && !VM_Version::supports_tsc()) {
apetushkov@9858 179 warning("Ignoring UseFastUnorderedTimeStamps, hardware does not support normal tsc");
apetushkov@9858 180 }
apetushkov@9858 181 }
apetushkov@9858 182
apetushkov@9858 183 return ft_enabled;
apetushkov@9858 184 }
apetushkov@9858 185
apetushkov@9858 186 bool Rdtsc::is_supported() {
apetushkov@9858 187 return VM_Version_Ext::supports_tscinv_ext();
apetushkov@9858 188 }
apetushkov@9858 189
apetushkov@9858 190 bool Rdtsc::is_elapsed_counter_enabled() {
apetushkov@9858 191 return rdtsc_elapsed_counter_enabled;
apetushkov@9858 192 }
apetushkov@9858 193
apetushkov@9858 194 jlong Rdtsc::frequency() {
apetushkov@9858 195 return tsc_frequency;
apetushkov@9858 196 }
apetushkov@9858 197
apetushkov@9858 198 jlong Rdtsc::elapsed_counter() {
apetushkov@9858 199 return os::rdtsc() - _epoch;
apetushkov@9858 200 }
apetushkov@9858 201
apetushkov@9858 202 jlong Rdtsc::epoch() {
apetushkov@9858 203 return _epoch;
apetushkov@9858 204 }
apetushkov@9858 205
apetushkov@9858 206 jlong Rdtsc::raw() {
apetushkov@9858 207 return os::rdtsc();
apetushkov@9858 208 }
apetushkov@9858 209
apetushkov@9858 210 bool Rdtsc::initialize() {
apetushkov@9858 211 static bool initialized = false;
apetushkov@9858 212 if (!initialized) {
apetushkov@9858 213 assert(!rdtsc_elapsed_counter_enabled, "invariant");
apetushkov@9858 214 VM_Version_Ext::initialize();
apetushkov@9858 215 assert(0 == tsc_frequency, "invariant");
apetushkov@9858 216 assert(0 == _epoch, "invariant");
apetushkov@9858 217 bool result = initialize_elapsed_counter(); // init hw
apetushkov@9858 218 if (result) {
apetushkov@9858 219 result = ergonomics(); // check logical state
apetushkov@9858 220 }
apetushkov@9858 221 rdtsc_elapsed_counter_enabled = result;
apetushkov@9858 222 initialized = true;
apetushkov@9858 223 }
apetushkov@9858 224 return rdtsc_elapsed_counter_enabled;
apetushkov@9858 225 }

mercurial