1 | /* Copyright (c) 2008 MySQL AB, 2009 Sun Microsystems, Inc. |
2 | Use is subject to license terms. |
3 | |
4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by |
6 | the Free Software Foundation; version 2 of the License. |
7 | |
8 | This program is distributed in the hope that it will be useful, |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | GNU General Public License for more details. |
12 | |
13 | You should have received a copy of the GNU General Public License |
14 | along with this program; if not, write to the Free Software |
15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
16 | |
17 | /* |
18 | rdtsc3 -- multi-platform timer code |
19 | pgulutzan@mysql.com, 2005-08-29 |
20 | modified 2008-11-02 |
21 | |
22 | When you run rdtsc3, it will print the contents of |
23 | "my_timer_info". The display indicates |
24 | what timer routine is best for a given platform. |
25 | |
26 | For example, this is the display on production.mysql.com, |
27 | a 2.8GHz Xeon with Linux 2.6.17, gcc 3.3.3: |
28 | |
29 | cycles nanoseconds microseconds milliseconds ticks |
30 | ------------- ------------- ------------- ------------- ------------- |
31 | 1 11 13 18 17 |
32 | 2815019607 1000000000 1000000 1049 102 |
33 | 1 1000 1 1 1 |
34 | 88 4116 3888 4092 2044 |
35 | |
36 | The first line shows routines, e.g. 1 = MY_TIMER_ROUTINE_ASM_X86. |
37 | The second line shows frequencies, e.g. 2815019607 is nearly 2.8GHz. |
38 | The third line shows resolutions, e.g. 1000 = very poor resolution. |
39 | The fourth line shows overheads, e.g. ticks takes 2044 cycles. |
40 | */ |
41 | |
42 | #include "my_global.h" |
43 | #include "my_rdtsc.h" |
44 | #include "tap.h" |
45 | |
46 | #define LOOP_COUNT 100 |
47 | |
48 | MY_TIMER_INFO myt; |
49 | |
50 | void test_init() |
51 | { |
52 | my_timer_init(&myt); |
53 | |
54 | diag("----- Routine ---------------" ); |
55 | diag("myt.cycles.routine : %13llu" , myt.cycles.routine); |
56 | diag("myt.nanoseconds.routine : %13llu" , myt.nanoseconds.routine); |
57 | diag("myt.microseconds.routine : %13llu" , myt.microseconds.routine); |
58 | diag("myt.milliseconds.routine : %13llu" , myt.milliseconds.routine); |
59 | diag("myt.ticks.routine : %13llu" , myt.ticks.routine); |
60 | |
61 | diag("----- Frequency -------------" ); |
62 | diag("myt.cycles.frequency : %13llu" , myt.cycles.frequency); |
63 | diag("myt.nanoseconds.frequency : %13llu" , myt.nanoseconds.frequency); |
64 | diag("myt.microseconds.frequency : %13llu" , myt.microseconds.frequency); |
65 | diag("myt.milliseconds.frequency : %13llu" , myt.milliseconds.frequency); |
66 | diag("myt.ticks.frequency : %13llu" , myt.ticks.frequency); |
67 | |
68 | diag("----- Resolution ------------" ); |
69 | diag("myt.cycles.resolution : %13llu" , myt.cycles.resolution); |
70 | diag("myt.nanoseconds.resolution : %13llu" , myt.nanoseconds.resolution); |
71 | diag("myt.microseconds.resolution : %13llu" , myt.microseconds.resolution); |
72 | diag("myt.milliseconds.resolution : %13llu" , myt.milliseconds.resolution); |
73 | diag("myt.ticks.resolution : %13llu" , myt.ticks.resolution); |
74 | |
75 | diag("----- Overhead --------------" ); |
76 | diag("myt.cycles.overhead : %13llu" , myt.cycles.overhead); |
77 | diag("myt.nanoseconds.overhead : %13llu" , myt.nanoseconds.overhead); |
78 | diag("myt.microseconds.overhead : %13llu" , myt.microseconds.overhead); |
79 | diag("myt.milliseconds.overhead : %13llu" , myt.milliseconds.overhead); |
80 | diag("myt.ticks.overhead : %13llu" , myt.ticks.overhead); |
81 | |
82 | ok(1, "my_timer_init() did not crash" ); |
83 | } |
84 | |
85 | void test_cycle() |
86 | { |
87 | ulonglong t1= my_timer_cycles(); |
88 | ulonglong t2; |
89 | int i; |
90 | int backward= 0; |
91 | int nonzero= 0; |
92 | |
93 | for (i=0 ; i < LOOP_COUNT ; i++) |
94 | { |
95 | t2= my_timer_cycles(); |
96 | if (t1 >= t2) |
97 | backward++; |
98 | if (t2 != 0) |
99 | nonzero++; |
100 | t1= t2; |
101 | } |
102 | |
103 | /* Expect at most 1 backward, the cycle value can overflow */ |
104 | ok((backward <= 1), "The cycle timer is strictly increasing" ); |
105 | |
106 | if (myt.cycles.routine != 0) |
107 | ok((nonzero != 0), "The cycle timer is implemented" ); |
108 | else |
109 | ok((nonzero == 0), "The cycle timer is not implemented and returns 0" ); |
110 | } |
111 | |
112 | void test_nanosecond() |
113 | { |
114 | ulonglong t1= my_timer_nanoseconds(); |
115 | ulonglong t2; |
116 | int i; |
117 | int backward= 0; |
118 | int nonzero= 0; |
119 | |
120 | for (i=0 ; i < LOOP_COUNT ; i++) |
121 | { |
122 | t2= my_timer_nanoseconds(); |
123 | if (t1 > t2) |
124 | backward++; |
125 | if (t2 != 0) |
126 | nonzero++; |
127 | t1= t2; |
128 | } |
129 | |
130 | ok((backward == 0), "The nanosecond timer is increasing" ); |
131 | |
132 | if (myt.nanoseconds.routine != 0) |
133 | ok((nonzero != 0), "The nanosecond timer is implemented" ); |
134 | else |
135 | ok((nonzero == 0), "The nanosecond timer is not implemented and returns 0" ); |
136 | } |
137 | |
138 | void test_microsecond() |
139 | { |
140 | ulonglong t1= my_timer_microseconds(); |
141 | ulonglong t2; |
142 | int i; |
143 | int backward= 0; |
144 | int nonzero= 0; |
145 | |
146 | for (i=0 ; i < LOOP_COUNT ; i++) |
147 | { |
148 | t2= my_timer_microseconds(); |
149 | if (t1 > t2) |
150 | backward++; |
151 | if (t2 != 0) |
152 | nonzero++; |
153 | t1= t2; |
154 | } |
155 | |
156 | ok((backward == 0), "The microsecond timer is increasing" ); |
157 | |
158 | if (myt.microseconds.routine != 0) |
159 | ok((nonzero != 0), "The microsecond timer is implemented" ); |
160 | else |
161 | ok((nonzero == 0), "The microsecond timer is not implemented and returns 0" ); |
162 | } |
163 | |
164 | void test_millisecond() |
165 | { |
166 | ulonglong t1= my_timer_milliseconds(); |
167 | ulonglong t2; |
168 | int i; |
169 | int backward= 0; |
170 | int nonzero= 0; |
171 | |
172 | for (i=0 ; i < LOOP_COUNT ; i++) |
173 | { |
174 | t2= my_timer_milliseconds(); |
175 | if (t1 > t2) |
176 | backward++; |
177 | if (t2 != 0) |
178 | nonzero++; |
179 | t1= t2; |
180 | } |
181 | |
182 | ok((backward == 0), "The millisecond timer is increasing" ); |
183 | |
184 | if (myt.milliseconds.routine != 0) |
185 | ok((nonzero != 0), "The millisecond timer is implemented" ); |
186 | else |
187 | ok((nonzero == 0), "The millisecond timer is not implemented and returns 0" ); |
188 | } |
189 | |
190 | void test_tick() |
191 | { |
192 | ulonglong t1= my_timer_ticks(); |
193 | ulonglong t2; |
194 | int i; |
195 | int backward= 0; |
196 | int nonzero= 0; |
197 | |
198 | for (i=0 ; i < LOOP_COUNT ; i++) |
199 | { |
200 | t2= my_timer_ticks(); |
201 | if (t1 > t2) |
202 | backward++; |
203 | if (t2 != 0) |
204 | nonzero++; |
205 | t1= t2; |
206 | } |
207 | |
208 | ok((backward == 0), "The tick timer is increasing" ); |
209 | |
210 | if (myt.ticks.routine != 0) |
211 | ok((nonzero != 0), "The tick timer is implemented" ); |
212 | else |
213 | ok((nonzero == 0), "The tick timer is not implemented and returns 0" ); |
214 | } |
215 | |
216 | int main(int argc __attribute__((unused)), |
217 | char ** argv __attribute__((unused))) |
218 | { |
219 | plan(11); |
220 | |
221 | test_init(); |
222 | test_cycle(); |
223 | test_nanosecond(); |
224 | test_microsecond(); |
225 | test_millisecond(); |
226 | test_tick(); |
227 | |
228 | return 0; |
229 | } |
230 | |
231 | |