5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2007 - 2008 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 /****h* silcutil/Timer Interface
24 * SILC Timer interface provides a simple way to measure time intervals.
25 * The SILC Timer works with microsecond resolution, depending on platform.
27 * The interface also provides utility functions to get currenet CPU tick
28 * count and to delay process/thread execution.
32 * SilcTimerStruct timer;
34 * silc_timer_start(&timer);
36 * silc_timer_stop(&timer);
37 * silc_timer_value(&timer, &elapsed_sec, &elapsed_usec);
44 /****s* silcutil/SilcTimer
48 * typedef struct SilcTimerObject *SilcTimer, SilcTimerStruct;
52 * The timer context. The context is given as argument to all
53 * silc_timer_* functions.
56 typedef struct SilcTimerObject *SilcTimer, SilcTimerStruct;
58 /****f* silcutil/silc_timer_start
62 * SilcBool silc_timer_start(SilcTimer timer);
66 * Starts the timer. If the timer is already running this will reset
67 * the timer and continue.
71 * SilcTimerStruct timer;
73 * silc_timer_start(&timer);
75 * silc_timer_stop(&timer);
76 * silc_timer_value(&timer, &elapsed_sec, &elapsed_usec);
79 void silc_timer_start(SilcTimer timer);
81 /****f* silcutil/silc_timer_stop
85 * void silc_timer_stop(SilcTimer timer);
89 * Stop the timer. The elapsed time can be retrieved by calling the
90 * silc_timer_value function.
93 void silc_timer_stop(SilcTimer timer);
95 /****f* silcutil/silc_timer_continue
99 * void silc_timer_continue(SilcTimer timer);
103 * Continue stopped timer. If timer is running already this does nothing.
106 void silc_timer_continue(SilcTimer timer);
108 /****f* silcutil/silc_timer_value
112 * void silc_timer_value(SilcTimer timer,
113 * SilcUInt64 *elapsed_time_seconds,
114 * SilcUInt32 *elapsed_time_microseconds);
118 * Returns either the current value or the end value of the timer. If the
119 * timer is currently running this returns the currently elapsed time. If
120 * the timer is stopped this returns the cumulative elapsed time.
123 void silc_timer_value(SilcTimer timer,
124 SilcUInt64 *elapsed_time_seconds,
125 SilcUInt32 *elapsed_time_microseconds);
127 /****f* silcutil/silc_timer_value_time
131 * void silc_timer_value_time(SilcTimer timer, SilcTime ret_time);
135 * Same as silc_timer_value but returns the elapsed time to `ret_time'
136 * SilcTime structure as absolute date and time. This is useful if the
137 * returned time needs to be converted into some other format such as
138 * time and date strings.
141 void silc_timer_value_time(SilcTimer timer, SilcTime ret_time);
143 /****f* silcutil/silc_timer_start_time
147 * void silc_timer_start_time(SilcTimer timer, SilcTime ret_start_time);
151 * Returns the timer's start time into `ret_start_time' SilcTime structure.
154 void silc_timer_start_time(SilcTimer timer, SilcTime ret_start_time);
156 /****f* silcutil/silc_timer_is_running
160 * SilcBool silc_timer_is_running(SilcTimer timer);
164 * Returns TRUE if the timer is currently running, FALSE otherwise.
167 SilcBool silc_timer_is_running(SilcTimer timer);
169 #include "silctimer_i.h"
171 /****f* silcutil/silc_timer_tick
175 * SilcUInt64 silc_timer_tick(SilcTimer &timer, SilcBool adjust)
179 * Returns the current CPU tick count. You should call the
180 * silc_timer_synchronize before using this function to make sure the
181 * overhead of measuring the CPU tick count is not included in the
182 * tick count. If the `adjust' is TRUE and the silc_timer_synchronize
183 * has been called the returned value is adjusted to be more accurate.
187 * // Synchronize timer for more accurate CPU tick counts
188 * silc_timer_synchronize(&timer);
189 * start = silc_timer_tick(&timer, FALSE);
191 * stop = silc_timer_tick(&timer, TRUE);
196 SilcUInt64 silc_timer_tick(SilcTimer timer, SilcBool adjust)
198 #if defined(__GNUC__) || defined(__ICC)
199 #if defined(SILC_I486)
201 asm volatile ("rdtsc" : "=A" (x));
202 return adjust ? x - timer->sync_tdiff : x;
204 #elif defined(SILC_X86_64)
207 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
208 x = ((SilcUInt64)lo | ((SilcUInt64)hi << 32));
209 return adjust ? x - timer->sync_tdiff : x;
211 #elif defined(SILC_POWERPC)
212 SilcUInt32 hi, lo, tmp;
213 asm volatile ("0: \n\t"
219 : "=r" (hi), "=r" (lo), "=r" (tmp));
220 x = ((SilcUInt64)lo | ((SilcUInt64)hi << 32));
221 return adjust ? x - timer->sync_tdiff : x;
222 #endif /* SILC_I486 */
224 #elif defined(SILC_WIN32)
229 #endif /* __GNUC__ || __ICC */
232 /****f* silcutil/silc_timer_synchronize
236 * void silc_timer_synchronize(SilcTimer timer);
240 * Synchronizes the `timer'. This call will attempt to synchronize the
241 * timer for more accurate results with high resolution timing. Call
242 * this before you start using the `timer'.
246 * // Synchronize timer
247 * silc_timer_synchronize(&timer);
248 * silc_timer_start(&timer);
249 * ... time passes ...
250 * silc_timer_stop(&timer);
251 * silc_timer_value(&timer, &elapsed_sec, &elapsed_usec);
256 void silc_timer_synchronize(SilcTimer timer)
258 SilcUInt32 tdiff, cumu, i;
261 /* Sync normal timer */
262 for (i = 0, cumu = 0; i < 5; i++) {
263 silc_timer_start(timer);
264 silc_timer_stop(timer);
265 silc_timer_value(timer, NULL, &tdiff);
269 timer->sync_diff = cumu;
270 if (timer->sync_diff > 5)
271 timer->sync_diff /= 5;
273 /* Sync CPU tick count */
275 t1 = silc_timer_tick(timer, FALSE);
276 t2 = silc_timer_tick(timer, FALSE);
278 t1 = silc_timer_tick(timer, FALSE);
279 t2 = silc_timer_tick(timer, FALSE);
281 t1 = silc_timer_tick(timer, FALSE);
282 t2 = silc_timer_tick(timer, FALSE);
285 timer->sync_tdiff = cumu / 3;
287 t1 = silc_timer_tick(timer, FALSE);
288 t2 = silc_timer_tick(timer, TRUE);
289 timer->sync_tdiff += (int)(t2 - t1);
292 /****f* silcutil/silc_usleep
296 * void silc_usleep(unsigned long microseconds);
300 * Delays the execution of process/thread for the specified amount of
301 * time, which is in microseconds.
305 * The delay is only approximate and on some platforms the resolution is
306 * in fact milliseconds.
310 void silc_usleep(unsigned long microseconds)
313 #ifdef HAVE_NANOSLEEP
316 tv.tv_nsec = microseconds * 1000;
317 #endif /* HAVE_NANOSLEEP */
318 #endif /* SILC_UNIX */
321 #ifdef HAVE_NANOSLEEP
322 nanosleep(&tv, NULL);
324 usleep(microseconds);
325 #endif /* HAVE_NANOSLEEP */
326 #endif /* SILC_UNIX */
328 Sleep(microseconds / 1000);
329 #endif /* SILC_WIN32 */
331 silc_symbian_usleep(microseconds);
332 #endif /* SILC_SYMBIAN */
335 #endif /* SILCTIMER_H */