3 * \brief time stamp counter related functions
5 * \date Frank Mehnert <fm3@os.inf.tu-dresden.de>
10 * (c) 2003-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
11 * Alexander Warg <warg@os.inf.tu-dresden.de>,
12 * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
13 * economic rights: Technische Universität Dresden (Germany)
14 * This file is part of TUD:OS and distributed under the terms of the
15 * GNU Lesser General Public License 2.1.
16 * Please see the COPYING-LGPL-2.1 file for details.
23 * \defgroup l4util_tsc Timestamp Counter
27 #include <l4/sys/compiler.h>
28 #include <l4/sys/l4int.h>
29 #include <l4/sys/kip.h>
35 * \addtogroup l4util_tsc
39 #define L4_TSC_INIT_AUTO 0 ///< Automatic init
40 #define L4_TSC_INIT_KERNEL 1 ///< Initialized by kernel
41 #define L4_TSC_INIT_CALIBRATE 2 ///< Initialized by user-level
43 extern l4_uint32_t l4_scaler_tsc_to_ns;
44 extern l4_uint32_t l4_scaler_tsc_to_us;
45 extern l4_uint32_t l4_scaler_ns_to_tsc;
46 extern l4_uint32_t l4_scaler_tsc_linux;
49 * \brief Read current value of CPU-internal time stamp counter.
50 * \return 64-bit time stamp
52 L4_INLINE l4_cpu_time_t
56 * \brief Read the lest significant 32 bit of the TSC.
58 * Useful for smaller differences, needs less cycles.
61 l4_uint32_t l4_rdtsc_32(void);
64 * \brief Return current value of CPU-internal performance measurement counter.
65 * \param nr Number of counter (0 or 1)
66 * \return 64-bit PMC */
67 L4_INLINE l4_cpu_time_t
71 * \brief Return the least significant 32 bit of a performance counter.
73 * Useful for smaller differences, needs less cycles.
76 l4_uint32_t l4_rdpmc_32(int nr);
78 /** Convert time stamp to ns value.
79 * \param tsc time value in CPU ticks
80 * \return time value in ns
83 l4_tsc_to_ns (l4_cpu_time_t tsc);
85 /** Convert time stamp into micro seconds value.
86 * \param tsc time value in CPU ticks
87 * \return time value in micro seconds
90 l4_tsc_to_us (l4_cpu_time_t tsc);
92 /** Convert time stamp to s.ns value.
93 * \param tsc time value in CPU ticks
95 * \retval ns nano seconds
98 l4_tsc_to_s_and_ns (l4_cpu_time_t tsc, l4_uint32_t *s, l4_uint32_t *ns);
101 * \brief Convert nano seconds into CPU ticks.
102 * \param ns nano seconds
105 L4_INLINE l4_cpu_time_t
106 l4_ns_to_tsc (l4_uint64_t ns);
109 * \brief Wait busy for a small amount of time.
110 * \param ns nano seconds to wait
111 * \attention Not intendet for any use!
114 l4_busy_wait_ns (l4_uint64_t ns);
117 * \brief Wait busy for a small amount of time.
118 * \param us micro seconds to wait
119 * \attention Not intendet for any use!
122 l4_busy_wait_us (l4_uint64_t us);
127 * \brief Calibrate scalers for time stamp calculations.
129 * Determine some scalers to be able to convert between real time and CPU
130 * ticks. This test uses channel 0 of the PIT (i8254) or the kernel KIP,
131 * depending on availability.
132 * Just calls l4_tsc_init(L4_TSC_INIT_AUTO).
134 L4_INLINE l4_uint32_t
135 l4_calibrate_tsc (l4_kernel_info_t *kip);
138 * \brief Initialitze scaler for TSC calicaltions.
140 * Initialize the scalers needed by l4_tsc_to_ns()/l4_ns_to_tsc() and so on.
141 * Current versions of Fiasco export these scalers from kernel into userland.
142 * The programmer may decide whether he allows to use these scalers or if an
143 * calibration should be performed.
144 * \param constraint programmers constraint:
145 * - #L4_TSC_INIT_AUTO if the kernel exports the scalers
146 * then use them. If not, perform calibration using
147 * channel 0 of the PIT (i8254). The latter case may
148 * lead into short (unpredictable) periods where
149 * interrupts are disabled.
150 * - #L4_TSC_INIT_KERNEL depend on retrieving the scalers
151 * from kernel. If the scalers are not available,
153 * - #L4_TSC_INIT_CALIBRATE Ignore possible scalers
154 * exported by the scaler, instead insist on
155 * calibration using the PIT.
156 * \param kip KIP pointer
157 * \return 0 on error (no scalers exported by kernel, calibrating failed ...)
158 * otherwise returns (2^32 / (tsc per µsec)). This value has the
159 * same semantics as the value returned by the calibrate_delay_loop()
160 * function of the Linux kernel.
163 l4_tsc_init (int constraint, l4_kernel_info_t *kip);
166 * \brief Get CPU frequency in Hz
167 * \return frequency in Hz
178 L4_INLINE l4_uint32_t
179 l4_calibrate_tsc (l4_kernel_info_t *kip)
181 return l4_tsc_init(L4_TSC_INIT_AUTO, kip);
184 L4_INLINE l4_cpu_time_t
190 (".byte 0x0f, 0x31 \n\t"
191 "mov $0xffffffff, %%rcx \n\t" /* clears the upper 32 bits! */
192 "and %%rcx,%%rax \n\t"
193 "shlq $32,%%rdx \n\t"
194 "orq %%rdx,%%rax \n\t"
204 L4_INLINE l4_cpu_time_t
210 __asm__ __volatile__ (
212 "mov $0xffffffff, %%rcx \n\t" /* clears the upper 32 bits! */
213 "and %%rcx,%%rax \n\t"
214 "shlq $32,%%rdx \n\t"
215 "orq %%rdx,%%rax \n\t"
217 "=a" (v), "=c"(dummy)
225 /* the same, but only 32 bit. Useful for smaller differences */
227 l4_uint32_t l4_rdpmc_32(int nr)
232 __asm__ __volatile__ (
234 "mov $0xffffffff, %%rcx \n\t" /* clears the upper 32 bits! */
235 "and %%rcx,%%rax \n\t"
236 : "=a" (x), "=c"(dummy)
243 /* the same, but only 32 bit. Useful for smaller differences,
244 needs less cycles. */
246 l4_uint32_t l4_rdtsc_32(void)
250 __asm__ __volatile__ (
251 ".byte 0x0f, 0x31\n\t" // rdtsc
259 L4_INLINE l4_uint64_t
260 l4_tsc_to_ns (l4_cpu_time_t tsc)
262 l4_uint64_t ns, dummy;
266 "shrd $27, %%rdx, %%rax \n\t"
267 :"=a" (ns), "=d"(dummy)
268 :"a" (tsc), "r" ((l4_uint64_t)l4_scaler_tsc_to_ns)
273 L4_INLINE l4_uint64_t
274 l4_tsc_to_us (l4_cpu_time_t tsc)
276 l4_uint64_t ns, dummy;
280 "shrd $32, %%rdx, %%rax \n\t"
281 :"=a" (ns), "=d" (dummy)
282 :"a" (tsc), "r" ((l4_uint64_t)l4_scaler_tsc_to_us)
288 l4_tsc_to_s_and_ns (l4_cpu_time_t tsc, l4_uint32_t *s, l4_uint32_t *ns)
293 "shrd $27, %%rdx, %%rax \n\t"
294 "xorq %%rdx, %%rdx \n\t"
296 :"=a" (*s), "=&d" (*ns)
297 : "a" (tsc), "r" ((l4_uint64_t)l4_scaler_tsc_to_ns),
302 L4_INLINE l4_cpu_time_t
303 l4_ns_to_tsc (l4_uint64_t ns)
305 l4_uint64_t tsc, dummy;
309 "shrd $27, %%rdx, %%rax \n\t"
310 :"=a" (tsc), "=d" (dummy)
311 :"a" (ns), "r" ((l4_uint64_t)l4_scaler_ns_to_tsc)
317 l4_busy_wait_ns (l4_uint64_t ns)
319 l4_cpu_time_t stop = l4_rdtsc();
320 stop += l4_ns_to_tsc(ns);
322 while (l4_rdtsc() < stop)
327 l4_busy_wait_us (l4_uint64_t us)
329 l4_cpu_time_t stop = l4_rdtsc ();
330 stop += l4_ns_to_tsc(us*1000ULL);
332 while (l4_rdtsc() < stop)
338 #endif /* __l4_rdtsc_h */