1 /* Copyright (c) 2009, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23
24 /*
25 rdtsc3 -- multi-platform timer code
26 pgulutzan@mysql.com, 2005-08-29
27 modified 2008-11-02
28
29 When you run rdtsc3, it will print the contents of
30 "my_timer_info". The display indicates
31 what timer routine is best for a given platform.
32
33 For example, this is the display on production.mysql.com,
34 a 2.8GHz Xeon with Linux 2.6.17, gcc 3.3.3:
35
36 cycles nanoseconds microseconds milliseconds ticks
37 ------------- ------------- ------------- ------------- -------------
38 1 11 13 18 17
39 2815019607 1000000000 1000000 1049 102
40 1 1000 1 1 1
41 88 4116 3888 4092 2044
42
43 The first line shows routines, e.g. 1 = MY_TIMER_ROUTINE_ASM_X86.
44 The second line shows frequencies, e.g. 2815019607 is nearly 2.8GHz.
45 The third line shows resolutions, e.g. 1000 = very poor resolution.
46 The fourth line shows overheads, e.g. ticks takes 2044 cycles.
47 */
48
49 // First include (the generated) my_config.h, to get correct platform defines.
50 #include "my_config.h"
51 #include <gtest/gtest.h>
52
53 #include "my_global.h"
54 #include "my_rdtsc.h"
55
56 namespace mysys_my_rdtsc_unittest {
57
58 const int LOOP_COUNT= 100;
59
60 class RDTimeStampCounter : public ::testing::Test
61 {
62 protected:
SetUp()63 void SetUp()
64 {
65 test_init();
66 }
67 void test_init();
68
69 MY_TIMER_INFO myt;
70 };
71
test_init()72 void RDTimeStampCounter::test_init()
73 {
74 my_timer_init(&myt);
75
76 fprintf(stdout, "----- Routine ---------------\n");
77 fprintf(stdout, "myt.cycles.routine : %13llu\n", myt.cycles.routine);
78 fprintf(stdout, "myt.nanoseconds.routine : %13llu\n", myt.nanoseconds.routine);
79 fprintf(stdout, "myt.microseconds.routine : %13llu\n", myt.microseconds.routine);
80 fprintf(stdout, "myt.milliseconds.routine : %13llu\n", myt.milliseconds.routine);
81 fprintf(stdout, "myt.ticks.routine : %13llu\n", myt.ticks.routine);
82
83 fprintf(stdout, "----- Frequency -------------\n");
84 fprintf(stdout, "myt.cycles.frequency : %13llu\n", myt.cycles.frequency);
85 fprintf(stdout, "myt.nanoseconds.frequency : %13llu\n", myt.nanoseconds.frequency);
86 fprintf(stdout, "myt.microseconds.frequency : %13llu\n", myt.microseconds.frequency);
87 fprintf(stdout, "myt.milliseconds.frequency : %13llu\n", myt.milliseconds.frequency);
88 fprintf(stdout, "myt.ticks.frequency : %13llu\n", myt.ticks.frequency);
89
90 fprintf(stdout, "----- Resolution ------------\n");
91 fprintf(stdout, "myt.cycles.resolution : %13llu\n", myt.cycles.resolution);
92 fprintf(stdout, "myt.nanoseconds.resolution : %13llu\n", myt.nanoseconds.resolution);
93 fprintf(stdout, "myt.microseconds.resolution : %13llu\n", myt.microseconds.resolution);
94 fprintf(stdout, "myt.milliseconds.resolution : %13llu\n", myt.milliseconds.resolution);
95 fprintf(stdout, "myt.ticks.resolution : %13llu\n", myt.ticks.resolution);
96
97 fprintf(stdout, "----- Overhead --------------\n");
98 fprintf(stdout, "myt.cycles.overhead : %13llu\n", myt.cycles.overhead);
99 fprintf(stdout, "myt.nanoseconds.overhead : %13llu\n", myt.nanoseconds.overhead);
100 fprintf(stdout, "myt.microseconds.overhead : %13llu\n", myt.microseconds.overhead);
101 fprintf(stdout, "myt.milliseconds.overhead : %13llu\n", myt.milliseconds.overhead);
102 fprintf(stdout, "myt.ticks.overhead : %13llu\n", myt.ticks.overhead);
103 }
104
105
TEST_F(RDTimeStampCounter,TestCycle)106 TEST_F(RDTimeStampCounter, TestCycle)
107 {
108 ulonglong t1= my_timer_cycles();
109 ulonglong t2;
110 int i;
111 int backward= 0;
112 int nonzero= 0;
113
114 for (i=0 ; i < LOOP_COUNT ; i++)
115 {
116 t2= my_timer_cycles();
117 if (t1 >= t2)
118 backward++;
119 if (t2 != 0)
120 nonzero++;
121 t1= t2;
122 }
123
124 #if defined(__aarch64__)
125 /* The ARM cycle timer has low resolution */
126 EXPECT_EQ(LOOP_COUNT, nonzero);
127 EXPECT_NE(0, backward);
128 #else
129 /* Expect at most 1 backward, the cycle value can overflow */
130 EXPECT_TRUE((backward <= 1)) << "The cycle timer is strictly increasing";
131 #endif
132
133 if (myt.cycles.routine != 0)
134 EXPECT_TRUE((nonzero != 0)) << "The cycle timer is implemented";
135 else
136 EXPECT_TRUE((nonzero == 0))
137 << "The cycle timer is not implemented and returns 0";
138 }
139
140
TEST_F(RDTimeStampCounter,TestNanosecond)141 TEST_F(RDTimeStampCounter, TestNanosecond)
142 {
143 ulonglong t1= my_timer_nanoseconds();
144 ulonglong t2;
145 int i;
146 int backward= 0;
147 int nonzero= 0;
148
149 for (i=0 ; i < LOOP_COUNT ; i++)
150 {
151 t2= my_timer_nanoseconds();
152 if (t1 > t2)
153 backward++;
154 if (t2 != 0)
155 nonzero++;
156 t1= t2;
157 }
158
159 EXPECT_TRUE((backward == 0)) << "The nanosecond timer is increasing";
160
161 if (myt.nanoseconds.routine != 0)
162 EXPECT_TRUE((nonzero != 0)) << "The nanosecond timer is implemented";
163 else
164 EXPECT_TRUE((nonzero == 0))
165 << "The nanosecond timer is not implemented and returns 0";
166 }
167
168
TEST_F(RDTimeStampCounter,TestMicrosecond)169 TEST_F(RDTimeStampCounter, TestMicrosecond)
170 {
171 ulonglong t1= my_timer_microseconds();
172 ulonglong t2;
173 int i;
174 int backward= 0;
175 int nonzero= 0;
176
177 for (i=0 ; i < LOOP_COUNT ; i++)
178 {
179 t2= my_timer_microseconds();
180 if (t1 > t2)
181 backward++;
182 if (t2 != 0)
183 nonzero++;
184 t1= t2;
185 }
186
187 EXPECT_TRUE((backward == 0)) << "The microsecond timer is increasing";
188
189 if (myt.microseconds.routine != 0)
190 EXPECT_TRUE((nonzero != 0)) << "The microsecond timer is implemented";
191 else
192 EXPECT_TRUE((nonzero == 0))
193 << "The microsecond timer is not implemented and returns 0";
194 }
195
196
TEST_F(RDTimeStampCounter,TestMillisecond)197 TEST_F(RDTimeStampCounter, TestMillisecond)
198 {
199 ulonglong t1= my_timer_milliseconds();
200 ulonglong t2;
201 int i;
202 int backward= 0;
203 int nonzero= 0;
204
205 for (i=0 ; i < LOOP_COUNT ; i++)
206 {
207 t2= my_timer_milliseconds();
208 if (t1 > t2)
209 backward++;
210 if (t2 != 0)
211 nonzero++;
212 t1= t2;
213 }
214
215 EXPECT_TRUE((backward == 0)) << "The millisecond timer is increasing";
216
217 if (myt.milliseconds.routine != 0)
218 EXPECT_TRUE((nonzero != 0)) << "The millisecond timer is implemented";
219 else
220 EXPECT_TRUE((nonzero == 0))
221 << "The millisecond timer is not implemented and returns 0";
222 }
223
224
TEST_F(RDTimeStampCounter,TestTick)225 TEST_F(RDTimeStampCounter, TestTick)
226 {
227 ulonglong t1= my_timer_ticks();
228 ulonglong t2;
229 int i;
230 int backward= 0;
231 int nonzero= 0;
232
233 for (i=0 ; i < LOOP_COUNT ; i++)
234 {
235 t2= my_timer_ticks();
236 if (t1 > t2)
237 backward++;
238 if (t2 != 0)
239 nonzero++;
240 t1= t2;
241 }
242
243 EXPECT_TRUE((backward == 0)) << "The tick timer is increasing";
244
245 if (myt.ticks.routine != 0)
246 EXPECT_TRUE((nonzero != 0)) << "The tick timer is implemented";
247 else
248 EXPECT_TRUE((nonzero == 0))
249 << "The tick timer is not implemented and returns 0";
250 }
251
252
253 }
254