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 
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
40 
41 #include "rdtsc_x86.hpp"
42 #include "runtime/thread.inline.hpp"
43 #include "vm_version_ext_x86.hpp"
44 #include "runtime/os.hpp"
45 
46 // The following header contains the implementations of rdtsc()
47 
48 static jlong _epoch = 0;
49 static bool rdtsc_elapsed_counter_enabled = false;
50 static jlong tsc_frequency = 0;
51 
set_epoch()52 static jlong set_epoch() {
53   assert(0 == _epoch, "invariant");
54   _epoch = os::rdtsc();
55   return _epoch;
56 }
57 
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.
do_time_measurements(volatile jlong & time_base,volatile jlong & time_fast,volatile jlong & time_base_elapsed,volatile jlong & time_fast_elapsed)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;
66 
67   volatile jlong start = 0;
68   volatile jlong fstart = 0;
69   volatile jlong end = 0;
70   volatile jlong fend = 0;
71 
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();
78 
79     // use sleep to prevent compiler from optimizing
80     os::sleep(Thread::current(), FT_SLEEP_MILLISECS, true);
81 
82     end = os::elapsed_counter();
83     OrderAccess::fence();
84     fend = os::rdtsc();
85 
86     time_base += end - start;
87     time_fast += fend - fstart;
88 
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   }
94 
95   time_base /= loopcount;
96   time_fast /= loopcount;
97   time_base_elapsed /= loopcount;
98   time_fast_elapsed /= loopcount;
99 }
100 
initialize_frequency()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!");
111 
112   double tsc_freq = .0;
113   double os_to_tsc_conv_factor = 1.0;
114 
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
124 
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;
129 
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);
133 
134     // if invalid measurements, cannot proceed
135     if (time_fast == 0 || time_base == 0) {
136       return 0;
137     }
138 
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   }
145 
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   }
150 
151   // frequency of the tsc_counter
152   return (jlong)tsc_freq;
153 }
154 
initialize_elapsed_counter()155 static bool initialize_elapsed_counter() {
156   tsc_frequency = initialize_frequency();
157   return tsc_frequency != 0 && _epoch != 0;
158 }
159 
ergonomics()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   }
165 
166   bool ft_enabled = UseFastUnorderedTimeStamps && invtsc_support;
167 
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   }
175 
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   }
182 
183   return ft_enabled;
184 }
185 
is_supported()186 bool Rdtsc::is_supported() {
187   return VM_Version_Ext::supports_tscinv_ext();
188 }
189 
is_elapsed_counter_enabled()190 bool Rdtsc::is_elapsed_counter_enabled() {
191   return rdtsc_elapsed_counter_enabled;
192 }
193 
frequency()194 jlong Rdtsc::frequency() {
195   return tsc_frequency;
196 }
197 
elapsed_counter()198 jlong Rdtsc::elapsed_counter() {
199   return os::rdtsc() - _epoch;
200 }
201 
epoch()202 jlong Rdtsc::epoch() {
203   return _epoch;
204 }
205 
raw()206 jlong Rdtsc::raw() {
207   return os::rdtsc();
208 }
209 
initialize()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 }
226