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