src/hotspot/cpu/x86/rdtsc_x86.cpp
changeset 50113 caf115bb98ad
child 54983 81becad91321
equal deleted inserted replaced
50112:7a2a740815b7 50113:caf115bb98ad
       
     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  */
       
    24 
       
    25 #include "precompiled.hpp"
       
    26 #include "rdtsc_x86.hpp"
       
    27 #include "runtime/thread.inline.hpp"
       
    28 #include "vm_version_ext_x86.hpp"
       
    29 
       
    30 // The following header contains the implementations of rdtsc()
       
    31 #include OS_CPU_HEADER_INLINE(os)
       
    32 
       
    33 static jlong _epoch = 0;
       
    34 static bool rdtsc_elapsed_counter_enabled = false;
       
    35 static jlong tsc_frequency = 0;
       
    36 
       
    37 static jlong set_epoch() {
       
    38   assert(0 == _epoch, "invariant");
       
    39   _epoch = os::rdtsc();
       
    40   return _epoch;
       
    41 }
       
    42 
       
    43 // Base loop to estimate ticks frequency for tsc counter from user mode.
       
    44 // Volatiles and sleep() are used to prevent compiler from applying optimizations.
       
    45 static void do_time_measurements(volatile jlong& time_base,
       
    46                                  volatile jlong& time_fast,
       
    47                                  volatile jlong& time_base_elapsed,
       
    48                                  volatile jlong& time_fast_elapsed) {
       
    49   static const unsigned int FT_SLEEP_MILLISECS = 1;
       
    50   const unsigned int loopcount = 3;
       
    51 
       
    52   volatile jlong start = 0;
       
    53   volatile jlong fstart = 0;
       
    54   volatile jlong end = 0;
       
    55   volatile jlong fend = 0;
       
    56 
       
    57   // Figure out the difference between rdtsc and os provided timer.
       
    58   // base algorithm adopted from JRockit.
       
    59   for (unsigned int times = 0; times < loopcount; times++) {
       
    60     start = os::elapsed_counter();
       
    61     OrderAccess::fence();
       
    62     fstart = os::rdtsc();
       
    63 
       
    64     // use sleep to prevent compiler from optimizing
       
    65     os::sleep(Thread::current(), FT_SLEEP_MILLISECS, true);
       
    66 
       
    67     end = os::elapsed_counter();
       
    68     OrderAccess::fence();
       
    69     fend = os::rdtsc();
       
    70 
       
    71     time_base += end - start;
       
    72     time_fast += fend - fstart;
       
    73 
       
    74     // basis for calculating the os tick start
       
    75     // to fast time tick start offset
       
    76     time_base_elapsed += end;
       
    77     time_fast_elapsed += (fend - _epoch);
       
    78   }
       
    79 
       
    80   time_base /= loopcount;
       
    81   time_fast /= loopcount;
       
    82   time_base_elapsed /= loopcount;
       
    83   time_fast_elapsed /= loopcount;
       
    84 }
       
    85 
       
    86 static jlong initialize_frequency() {
       
    87   assert(0 == tsc_frequency, "invariant");
       
    88   assert(0 == _epoch, "invariant");
       
    89   const jlong initial_counter = set_epoch();
       
    90   if (initial_counter == 0) {
       
    91     return 0;
       
    92   }
       
    93   // os time frequency
       
    94   static double os_freq = (double)os::elapsed_frequency();
       
    95   assert(os_freq > 0, "os_elapsed frequency corruption!");
       
    96 
       
    97   double tsc_freq = .0;
       
    98   double os_to_tsc_conv_factor = 1.0;
       
    99 
       
   100   // if platform supports invariant tsc,
       
   101   // apply higher resolution and granularity for conversion calculations
       
   102   if (VM_Version_Ext::supports_tscinv_ext()) {
       
   103     // for invariant tsc platforms, take the maximum qualified cpu frequency
       
   104     tsc_freq = (double)VM_Version_Ext::maximum_qualified_cpu_frequency();
       
   105     os_to_tsc_conv_factor = tsc_freq / os_freq;
       
   106   } else {
       
   107     // use measurements to estimate
       
   108     // a conversion factor and the tsc frequency
       
   109 
       
   110     volatile jlong time_base = 0;
       
   111     volatile jlong time_fast = 0;
       
   112     volatile jlong time_base_elapsed = 0;
       
   113     volatile jlong time_fast_elapsed = 0;
       
   114 
       
   115     // do measurements to get base data
       
   116     // on os timer and fast ticks tsc time relation.
       
   117     do_time_measurements(time_base, time_fast, time_base_elapsed, time_fast_elapsed);
       
   118 
       
   119     // if invalid measurements, cannot proceed
       
   120     if (time_fast == 0 || time_base == 0) {
       
   121       return 0;
       
   122     }
       
   123 
       
   124     os_to_tsc_conv_factor = (double)time_fast / (double)time_base;
       
   125     if (os_to_tsc_conv_factor > 1) {
       
   126       // estimate on tsc counter frequency
       
   127       tsc_freq = os_to_tsc_conv_factor * os_freq;
       
   128     }
       
   129   }
       
   130 
       
   131   if ((tsc_freq < 0) || (tsc_freq > 0 && tsc_freq <= os_freq) || (os_to_tsc_conv_factor <= 1)) {
       
   132     // safer to run with normal os time
       
   133     tsc_freq = .0;
       
   134   }
       
   135 
       
   136   // frequency of the tsc_counter
       
   137   return (jlong)tsc_freq;
       
   138 }
       
   139 
       
   140 static bool initialize_elapsed_counter() {
       
   141   tsc_frequency = initialize_frequency();
       
   142   return tsc_frequency != 0 && _epoch != 0;
       
   143 }
       
   144 
       
   145 static bool ergonomics() {
       
   146   const bool invtsc_support = Rdtsc::is_supported();
       
   147   if (FLAG_IS_DEFAULT(UseFastUnorderedTimeStamps) && invtsc_support) {
       
   148     FLAG_SET_ERGO(bool, UseFastUnorderedTimeStamps, true);
       
   149   }
       
   150 
       
   151   bool ft_enabled = UseFastUnorderedTimeStamps && invtsc_support;
       
   152 
       
   153   if (!ft_enabled) {
       
   154     if (UseFastUnorderedTimeStamps && VM_Version::supports_tsc()) {
       
   155       warning("\nThe hardware does not support invariant tsc (INVTSC) register and/or cannot guarantee tsc synchronization between sockets at startup.\n"\
       
   156         "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");
       
   157       ft_enabled = true;
       
   158     }
       
   159   }
       
   160 
       
   161   if (!ft_enabled) {
       
   162     // Warn if unable to support command-line flag
       
   163     if (UseFastUnorderedTimeStamps && !VM_Version::supports_tsc()) {
       
   164       warning("Ignoring UseFastUnorderedTimeStamps, hardware does not support normal tsc");
       
   165     }
       
   166   }
       
   167 
       
   168   return ft_enabled;
       
   169 }
       
   170 
       
   171 bool Rdtsc::is_supported() {
       
   172   return VM_Version_Ext::supports_tscinv_ext();
       
   173 }
       
   174 
       
   175 bool Rdtsc::is_elapsed_counter_enabled() {
       
   176   return rdtsc_elapsed_counter_enabled;
       
   177 }
       
   178 
       
   179 jlong Rdtsc::frequency() {
       
   180   return tsc_frequency;
       
   181 }
       
   182 
       
   183 jlong Rdtsc::elapsed_counter() {
       
   184   return os::rdtsc() - _epoch;
       
   185 }
       
   186 
       
   187 jlong Rdtsc::epoch() {
       
   188   return _epoch;
       
   189 }
       
   190 
       
   191 jlong Rdtsc::raw() {
       
   192   return os::rdtsc();
       
   193 }
       
   194 
       
   195 bool Rdtsc::initialize() {
       
   196   static bool initialized = false;
       
   197   if (!initialized) {
       
   198     assert(!rdtsc_elapsed_counter_enabled, "invariant");
       
   199     VM_Version_Ext::initialize();
       
   200     assert(0 == tsc_frequency, "invariant");
       
   201     assert(0 == _epoch, "invariant");
       
   202     bool result = initialize_elapsed_counter(); // init hw
       
   203     if (result) {
       
   204       result = ergonomics(); // check logical state
       
   205     }
       
   206     rdtsc_elapsed_counter_enabled = result;
       
   207     initialized = true;
       
   208   }
       
   209   return rdtsc_elapsed_counter_enabled;
       
   210 }