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

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

mercurial