root / include / qemu / timer.h @ 6a1751b7
History | View | Annotate | Download (17.6 kB)
1 |
#ifndef QEMU_TIMER_H
|
---|---|
2 |
#define QEMU_TIMER_H
|
3 |
|
4 |
#include "qemu/typedefs.h" |
5 |
#include "qemu-common.h" |
6 |
#include "qemu/notify.h" |
7 |
|
8 |
/* timers */
|
9 |
|
10 |
#define SCALE_MS 1000000 |
11 |
#define SCALE_US 1000 |
12 |
#define SCALE_NS 1 |
13 |
|
14 |
/**
|
15 |
* QEMUClockType:
|
16 |
*
|
17 |
* The following clock types are available:
|
18 |
*
|
19 |
* @QEMU_CLOCK_REALTIME: Real time clock
|
20 |
*
|
21 |
* The real time clock should be used only for stuff which does not
|
22 |
* change the virtual machine state, as it is run even if the virtual
|
23 |
* machine is stopped. The real time clock has a frequency of 1000
|
24 |
* Hz.
|
25 |
*
|
26 |
* Formerly rt_clock
|
27 |
*
|
28 |
* @QEMU_CLOCK_VIRTUAL: virtual clock
|
29 |
*
|
30 |
* The virtual clock is only run during the emulation. It is stopped
|
31 |
* when the virtual machine is stopped. Virtual timers use a high
|
32 |
* precision clock, usually cpu cycles (use ticks_per_sec).
|
33 |
*
|
34 |
* Formerly vm_clock
|
35 |
*
|
36 |
* @QEMU_CLOCK_HOST: host clock
|
37 |
*
|
38 |
* The host clock should be use for device models that emulate accurate
|
39 |
* real time sources. It will continue to run when the virtual machine
|
40 |
* is suspended, and it will reflect system time changes the host may
|
41 |
* undergo (e.g. due to NTP). The host clock has the same precision as
|
42 |
* the virtual clock.
|
43 |
*
|
44 |
* Formerly host_clock
|
45 |
*/
|
46 |
|
47 |
typedef enum { |
48 |
QEMU_CLOCK_REALTIME = 0,
|
49 |
QEMU_CLOCK_VIRTUAL = 1,
|
50 |
QEMU_CLOCK_HOST = 2,
|
51 |
QEMU_CLOCK_MAX |
52 |
} QEMUClockType; |
53 |
|
54 |
typedef struct QEMUClock QEMUClock; |
55 |
typedef struct QEMUTimerList QEMUTimerList; |
56 |
typedef void QEMUTimerCB(void *opaque); |
57 |
|
58 |
struct QEMUTimer {
|
59 |
int64_t expire_time; /* in nanoseconds */
|
60 |
QEMUTimerList *timer_list; |
61 |
QEMUTimerCB *cb; |
62 |
void *opaque;
|
63 |
QEMUTimer *next; |
64 |
int scale;
|
65 |
}; |
66 |
|
67 |
extern QEMUClock *qemu_clocks[QEMU_CLOCK_MAX];
|
68 |
|
69 |
/**
|
70 |
* qemu_clock_ptr:
|
71 |
* @type: type of clock
|
72 |
*
|
73 |
* Translate a clock type into a pointer to QEMUClock object.
|
74 |
*
|
75 |
* Returns: a pointer to the QEMUClock object
|
76 |
*/
|
77 |
static inline QEMUClock *qemu_clock_ptr(QEMUClockType type) |
78 |
{ |
79 |
return qemu_clocks[type];
|
80 |
} |
81 |
|
82 |
/* These three clocks are maintained here with separate variable
|
83 |
* names for compatibility only.
|
84 |
*/
|
85 |
#define rt_clock (qemu_clock_ptr(QEMU_CLOCK_REALTIME))
|
86 |
#define vm_clock (qemu_clock_ptr(QEMU_CLOCK_VIRTUAL))
|
87 |
#define host_clock (qemu_clock_ptr(QEMU_CLOCK_HOST))
|
88 |
|
89 |
int64_t qemu_get_clock_ns(QEMUClock *clock); |
90 |
bool qemu_clock_has_timers(QEMUClock *clock);
|
91 |
bool qemu_clock_expired(QEMUClock *clock);
|
92 |
int64_t qemu_clock_deadline(QEMUClock *clock); |
93 |
|
94 |
/**
|
95 |
* qemu_clock_deadline_ns:
|
96 |
* @clock: the clock to operate on
|
97 |
*
|
98 |
* Calculate the timeout of the earliest expiring timer
|
99 |
* in nanoseconds, or -1 if no timer is set to expire.
|
100 |
*
|
101 |
* Returns: time until expiry in nanoseconds or -1
|
102 |
*/
|
103 |
int64_t qemu_clock_deadline_ns(QEMUClock *clock); |
104 |
|
105 |
/**
|
106 |
* qemu_clock_use_for_deadline:
|
107 |
* @clock: the clock to operate on
|
108 |
*
|
109 |
* Determine whether a clock should be used for deadline
|
110 |
* calculations. Some clocks, for instance vm_clock with
|
111 |
* use_icount set, do not count in nanoseconds. Such clocks
|
112 |
* are not used for deadline calculations, and are presumed
|
113 |
* to interrupt any poll using qemu_notify/aio_notify
|
114 |
* etc.
|
115 |
*
|
116 |
* Returns: true if the clock runs in nanoseconds and
|
117 |
* should be used for a deadline.
|
118 |
*/
|
119 |
bool qemu_clock_use_for_deadline(QEMUClock *clock);
|
120 |
|
121 |
/**
|
122 |
* qemu_clock_get_main_loop_timerlist:
|
123 |
* @clock: the clock to operate on
|
124 |
*
|
125 |
* Return the default timer list assocatiated with a clock.
|
126 |
*
|
127 |
* Returns: the default timer list
|
128 |
*/
|
129 |
QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClock *clock); |
130 |
|
131 |
/**
|
132 |
* timerlist_new:
|
133 |
* @type: the clock type to associate with the timerlist
|
134 |
*
|
135 |
* Create a new timerlist associated with the clock of
|
136 |
* type @type.
|
137 |
*
|
138 |
* Returns: a pointer to the QEMUTimerList created
|
139 |
*/
|
140 |
QEMUTimerList *timerlist_new(QEMUClockType type); |
141 |
|
142 |
/**
|
143 |
* timerlist_free:
|
144 |
* @timer_list: the timer list to free
|
145 |
*
|
146 |
* Frees a timer_list. It must have no active timers.
|
147 |
*/
|
148 |
void timerlist_free(QEMUTimerList *timer_list);
|
149 |
|
150 |
/**
|
151 |
* timerlist_has_timers:
|
152 |
* @timer_list: the timer list to operate on
|
153 |
*
|
154 |
* Determine whether a timer list has active timers
|
155 |
*
|
156 |
* Returns: true if the timer list has timers.
|
157 |
*/
|
158 |
bool timerlist_has_timers(QEMUTimerList *timer_list);
|
159 |
|
160 |
/**
|
161 |
* timerlist_expired:
|
162 |
* @timer_list: the timer list to operate on
|
163 |
*
|
164 |
* Determine whether a timer list has any timers which
|
165 |
* are expired.
|
166 |
*
|
167 |
* Returns: true if the timer list has timers which
|
168 |
* have expired.
|
169 |
*/
|
170 |
bool timerlist_expired(QEMUTimerList *timer_list);
|
171 |
|
172 |
/**
|
173 |
* timerlist_deadline:
|
174 |
* @timer_list: the timer list to operate on
|
175 |
*
|
176 |
* Determine the deadline for a timer_list. This is
|
177 |
* a legacy function which returns INT32_MAX if the
|
178 |
* timer list has no timers or if the earliest timer
|
179 |
* expires later than INT32_MAX nanoseconds away.
|
180 |
*
|
181 |
* Returns: the number of nanoseconds until the earliest
|
182 |
* timer expires or INT32_MAX in the situations listed
|
183 |
* above
|
184 |
*/
|
185 |
int64_t timerlist_deadline(QEMUTimerList *timer_list); |
186 |
|
187 |
/**
|
188 |
* timerlist_deadline_ns:
|
189 |
* @timer_list: the timer list to operate on
|
190 |
*
|
191 |
* Determine the deadline for a timer_list, i.e.
|
192 |
* the number of nanoseconds until the first timer
|
193 |
* expires. Return -1 if there are no timers.
|
194 |
*
|
195 |
* Returns: the number of nanoseconds until the earliest
|
196 |
* timer expires -1 if none
|
197 |
*/
|
198 |
int64_t timerlist_deadline_ns(QEMUTimerList *timer_list); |
199 |
|
200 |
/**
|
201 |
* timerlist_getclock:
|
202 |
* @timer_list: the timer list to operate on
|
203 |
*
|
204 |
* Determine the clock associated with a timer list.
|
205 |
*
|
206 |
* Returns: the clock associated with the timer list.
|
207 |
*/
|
208 |
QEMUClock *timerlist_get_clock(QEMUTimerList *timer_list); |
209 |
|
210 |
/**
|
211 |
* timerlist_run_timers:
|
212 |
* @timer_list: the timer list to use
|
213 |
*
|
214 |
* Call all expired timers associated with the timer list.
|
215 |
*
|
216 |
* Returns: true if any timer expired
|
217 |
*/
|
218 |
bool timerlist_run_timers(QEMUTimerList *timer_list);
|
219 |
|
220 |
/**
|
221 |
* qemu_timeout_ns_to_ms:
|
222 |
* @ns: nanosecond timeout value
|
223 |
*
|
224 |
* Convert a nanosecond timeout value (or -1) to
|
225 |
* a millisecond value (or -1), always rounding up.
|
226 |
*
|
227 |
* Returns: millisecond timeout value
|
228 |
*/
|
229 |
int qemu_timeout_ns_to_ms(int64_t ns);
|
230 |
|
231 |
/**
|
232 |
* qemu_poll_ns:
|
233 |
* @fds: Array of file descriptors
|
234 |
* @nfds: number of file descriptors
|
235 |
* @timeout: timeout in nanoseconds
|
236 |
*
|
237 |
* Perform a poll like g_poll but with a timeout in nanoseconds.
|
238 |
* See g_poll documentation for further details.
|
239 |
*
|
240 |
* Returns: number of fds ready
|
241 |
*/
|
242 |
int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout);
|
243 |
void qemu_clock_enable(QEMUClock *clock, bool enabled); |
244 |
void qemu_clock_warp(QEMUClock *clock);
|
245 |
|
246 |
void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier);
|
247 |
void qemu_unregister_clock_reset_notifier(QEMUClock *clock,
|
248 |
Notifier *notifier); |
249 |
|
250 |
QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
|
251 |
QEMUTimerCB *cb, void *opaque);
|
252 |
|
253 |
/**
|
254 |
* timer_init:
|
255 |
* @ts: the timer to be initialised
|
256 |
* @timer_list: the timer list to attach the timer to
|
257 |
* @scale: the scale value for the tiemr
|
258 |
* @cb: the callback to be called when the timer expires
|
259 |
* @opaque: the opaque pointer to be passed to the callback
|
260 |
*
|
261 |
* Initialise a new timer and associate it with @timer_list.
|
262 |
* The caller is responsible for allocating the memory.
|
263 |
*
|
264 |
* You need not call an explicit deinit call. Simply make
|
265 |
* sure it is not on a list with timer_del.
|
266 |
*/
|
267 |
void timer_init(QEMUTimer *ts,
|
268 |
QEMUTimerList *timer_list, int scale,
|
269 |
QEMUTimerCB *cb, void *opaque);
|
270 |
|
271 |
/**
|
272 |
* timer_new_tl:
|
273 |
* @timer_list: the timer list to attach the timer to
|
274 |
* @scale: the scale value for the tiemr
|
275 |
* @cb: the callback to be called when the timer expires
|
276 |
* @opaque: the opaque pointer to be passed to the callback
|
277 |
*
|
278 |
* Creeate a new timer and associate it with @timer_list.
|
279 |
* The memory is allocated by the function.
|
280 |
*
|
281 |
* This is not the preferred interface unless you know you
|
282 |
* are going to call timer_free. Use timer_init instead.
|
283 |
*
|
284 |
* Returns: a pointer to the timer
|
285 |
*/
|
286 |
static inline QEMUTimer *timer_new_tl(QEMUTimerList *timer_list, |
287 |
int scale,
|
288 |
QEMUTimerCB *cb, |
289 |
void *opaque)
|
290 |
{ |
291 |
QEMUTimer *ts = g_malloc0(sizeof(QEMUTimer));
|
292 |
timer_init(ts, timer_list, scale, cb, opaque); |
293 |
return ts;
|
294 |
} |
295 |
|
296 |
void qemu_free_timer(QEMUTimer *ts);
|
297 |
void qemu_del_timer(QEMUTimer *ts);
|
298 |
void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time);
|
299 |
void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
|
300 |
bool timer_pending(QEMUTimer *ts);
|
301 |
bool timer_expired(QEMUTimer *timer_head, int64_t current_time);
|
302 |
uint64_t timer_expire_time_ns(QEMUTimer *ts); |
303 |
|
304 |
/* New format calling conventions for timers */
|
305 |
|
306 |
/**
|
307 |
* timer_free:
|
308 |
* @ts: the timer
|
309 |
*
|
310 |
* Free a timer (it must not be on the active list)
|
311 |
*/
|
312 |
static inline void timer_free(QEMUTimer *ts) |
313 |
{ |
314 |
qemu_free_timer(ts); |
315 |
} |
316 |
|
317 |
/**
|
318 |
* timer_del:
|
319 |
* @ts: the timer
|
320 |
*
|
321 |
* Delete a timer from the active list.
|
322 |
*/
|
323 |
static inline void timer_del(QEMUTimer *ts) |
324 |
{ |
325 |
qemu_del_timer(ts); |
326 |
} |
327 |
|
328 |
/**
|
329 |
* timer_mod_ns:
|
330 |
* @ts: the timer
|
331 |
* @expire_time: the expiry time in nanoseconds
|
332 |
*
|
333 |
* Modify a timer to expire at @expire_time
|
334 |
*/
|
335 |
static inline void timer_mod_ns(QEMUTimer *ts, int64_t expire_time) |
336 |
{ |
337 |
qemu_mod_timer_ns(ts, expire_time); |
338 |
} |
339 |
|
340 |
/**
|
341 |
* timer_mod:
|
342 |
* @ts: the timer
|
343 |
* @expire_time: the expire time in the units associated with the timer
|
344 |
*
|
345 |
* Modify a timer to expiry at @expire_time, taking into
|
346 |
* account the scale associated with the timer.
|
347 |
*/
|
348 |
static inline void timer_mod(QEMUTimer *ts, int64_t expire_timer) |
349 |
{ |
350 |
qemu_mod_timer(ts, expire_timer); |
351 |
} |
352 |
|
353 |
/**
|
354 |
* qemu_run_timers:
|
355 |
* @clock: clock on which to operate
|
356 |
*
|
357 |
* Run all the timers associated with the default timer list
|
358 |
* of a clock.
|
359 |
*
|
360 |
* Returns: true if any timer ran.
|
361 |
*/
|
362 |
bool qemu_run_timers(QEMUClock *clock);
|
363 |
|
364 |
/**
|
365 |
* qemu_run_all_timers:
|
366 |
*
|
367 |
* Run all the timers associated with the default timer list
|
368 |
* of every clock.
|
369 |
*
|
370 |
* Returns: true if any timer ran.
|
371 |
*/
|
372 |
bool qemu_run_all_timers(void); |
373 |
|
374 |
void configure_alarms(char const *opt); |
375 |
void init_clocks(void); |
376 |
int init_timer_alarm(void); |
377 |
|
378 |
int64_t cpu_get_ticks(void);
|
379 |
void cpu_enable_ticks(void); |
380 |
void cpu_disable_ticks(void); |
381 |
|
382 |
/**
|
383 |
* qemu_soonest_timeout:
|
384 |
* @timeout1: first timeout in nanoseconds (or -1 for infinite)
|
385 |
* @timeout2: second timeout in nanoseconds (or -1 for infinite)
|
386 |
*
|
387 |
* Calculates the soonest of two timeout values. -1 means infinite, which
|
388 |
* is later than any other value.
|
389 |
*
|
390 |
* Returns: soonest timeout value in nanoseconds (or -1 for infinite)
|
391 |
*/
|
392 |
static inline int64_t qemu_soonest_timeout(int64_t timeout1, int64_t timeout2) |
393 |
{ |
394 |
/* we can abuse the fact that -1 (which means infinite) is a maximal
|
395 |
* value when cast to unsigned. As this is disgusting, it's kept in
|
396 |
* one inline function.
|
397 |
*/
|
398 |
return ((uint64_t) timeout1 < (uint64_t) timeout2) ? timeout1 : timeout2;
|
399 |
} |
400 |
|
401 |
/**
|
402 |
* qemu_new_timer_ns:
|
403 |
* @clock: the clock to associate with the timer
|
404 |
* @callback: the callback to call when the timer expires
|
405 |
* @opaque: the opaque pointer to pass to the callback
|
406 |
*
|
407 |
* Create a new timer with nanosecond scale on the default timer list
|
408 |
* associated with the clock.
|
409 |
*
|
410 |
* Returns: a pointer to the newly created timer
|
411 |
*/
|
412 |
static inline QEMUTimer *qemu_new_timer_ns(QEMUClock *clock, QEMUTimerCB *cb, |
413 |
void *opaque)
|
414 |
{ |
415 |
return qemu_new_timer(clock, SCALE_NS, cb, opaque);
|
416 |
} |
417 |
|
418 |
/**
|
419 |
* qemu_new_timer_us:
|
420 |
* @clock: the clock to associate with the timer
|
421 |
* @callback: the callback to call when the timer expires
|
422 |
* @opaque: the opaque pointer to pass to the callback
|
423 |
*
|
424 |
* Create a new timer with microsecond scale on the default timer list
|
425 |
* associated with the clock.
|
426 |
*
|
427 |
* Returns: a pointer to the newly created timer
|
428 |
*/
|
429 |
static inline QEMUTimer *qemu_new_timer_us(QEMUClock *clock, |
430 |
QEMUTimerCB *cb, |
431 |
void *opaque)
|
432 |
{ |
433 |
return qemu_new_timer(clock, SCALE_US, cb, opaque);
|
434 |
} |
435 |
|
436 |
/**
|
437 |
* qemu_new_timer_ms:
|
438 |
* @clock: the clock to associate with the timer
|
439 |
* @callback: the callback to call when the timer expires
|
440 |
* @opaque: the opaque pointer to pass to the callback
|
441 |
*
|
442 |
* Create a new timer with millisecond scale on the default timer list
|
443 |
* associated with the clock.
|
444 |
*
|
445 |
* Returns: a pointer to the newly created timer
|
446 |
*/
|
447 |
static inline QEMUTimer *qemu_new_timer_ms(QEMUClock *clock, |
448 |
QEMUTimerCB *cb, |
449 |
void *opaque)
|
450 |
{ |
451 |
return qemu_new_timer(clock, SCALE_MS, cb, opaque);
|
452 |
} |
453 |
|
454 |
static inline int64_t qemu_get_clock_ms(QEMUClock *clock) |
455 |
{ |
456 |
return qemu_get_clock_ns(clock) / SCALE_MS;
|
457 |
} |
458 |
|
459 |
static inline int64_t get_ticks_per_sec(void) |
460 |
{ |
461 |
return 1000000000LL; |
462 |
} |
463 |
|
464 |
/* real time host monotonic timer */
|
465 |
static inline int64_t get_clock_realtime(void) |
466 |
{ |
467 |
struct timeval tv;
|
468 |
|
469 |
gettimeofday(&tv, NULL);
|
470 |
return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); |
471 |
} |
472 |
|
473 |
/* Warning: don't insert tracepoints into these functions, they are
|
474 |
also used by simpletrace backend and tracepoints would cause
|
475 |
an infinite recursion! */
|
476 |
#ifdef _WIN32
|
477 |
extern int64_t clock_freq;
|
478 |
|
479 |
static inline int64_t get_clock(void) |
480 |
{ |
481 |
LARGE_INTEGER ti; |
482 |
QueryPerformanceCounter(&ti); |
483 |
return muldiv64(ti.QuadPart, get_ticks_per_sec(), clock_freq);
|
484 |
} |
485 |
|
486 |
#else
|
487 |
|
488 |
extern int use_rt_clock; |
489 |
|
490 |
static inline int64_t get_clock(void) |
491 |
{ |
492 |
#ifdef CLOCK_MONOTONIC
|
493 |
if (use_rt_clock) {
|
494 |
struct timespec ts;
|
495 |
clock_gettime(CLOCK_MONOTONIC, &ts); |
496 |
return ts.tv_sec * 1000000000LL + ts.tv_nsec; |
497 |
} else
|
498 |
#endif
|
499 |
{ |
500 |
/* XXX: using gettimeofday leads to problems if the date
|
501 |
changes, so it should be avoided. */
|
502 |
return get_clock_realtime();
|
503 |
} |
504 |
} |
505 |
#endif
|
506 |
|
507 |
void qemu_get_timer(QEMUFile *f, QEMUTimer *ts);
|
508 |
void qemu_put_timer(QEMUFile *f, QEMUTimer *ts);
|
509 |
|
510 |
/* icount */
|
511 |
int64_t cpu_get_icount(void);
|
512 |
int64_t cpu_get_clock(void);
|
513 |
|
514 |
/*******************************************/
|
515 |
/* host CPU ticks (if available) */
|
516 |
|
517 |
#if defined(_ARCH_PPC)
|
518 |
|
519 |
static inline int64_t cpu_get_real_ticks(void) |
520 |
{ |
521 |
int64_t retval; |
522 |
#ifdef _ARCH_PPC64
|
523 |
/* This reads timebase in one 64bit go and includes Cell workaround from:
|
524 |
http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html
|
525 |
*/
|
526 |
__asm__ __volatile__ ("mftb %0\n\t"
|
527 |
"cmpwi %0,0\n\t"
|
528 |
"beq- $-8"
|
529 |
: "=r" (retval));
|
530 |
#else
|
531 |
/* http://ozlabs.org/pipermail/linuxppc-dev/1999-October/003889.html */
|
532 |
unsigned long junk; |
533 |
__asm__ __volatile__ ("mfspr %1,269\n\t" /* mftbu */ |
534 |
"mfspr %L0,268\n\t" /* mftb */ |
535 |
"mfspr %0,269\n\t" /* mftbu */ |
536 |
"cmpw %0,%1\n\t"
|
537 |
"bne $-16"
|
538 |
: "=r" (retval), "=r" (junk)); |
539 |
#endif
|
540 |
return retval;
|
541 |
} |
542 |
|
543 |
#elif defined(__i386__)
|
544 |
|
545 |
static inline int64_t cpu_get_real_ticks(void) |
546 |
{ |
547 |
int64_t val; |
548 |
asm volatile ("rdtsc" : "=A" (val)); |
549 |
return val;
|
550 |
} |
551 |
|
552 |
#elif defined(__x86_64__)
|
553 |
|
554 |
static inline int64_t cpu_get_real_ticks(void) |
555 |
{ |
556 |
uint32_t low,high; |
557 |
int64_t val; |
558 |
asm volatile("rdtsc" : "=a" (low), "=d" (high)); |
559 |
val = high; |
560 |
val <<= 32;
|
561 |
val |= low; |
562 |
return val;
|
563 |
} |
564 |
|
565 |
#elif defined(__hppa__)
|
566 |
|
567 |
static inline int64_t cpu_get_real_ticks(void) |
568 |
{ |
569 |
int val;
|
570 |
asm volatile ("mfctl %%cr16, %0" : "=r"(val)); |
571 |
return val;
|
572 |
} |
573 |
|
574 |
#elif defined(__ia64)
|
575 |
|
576 |
static inline int64_t cpu_get_real_ticks(void) |
577 |
{ |
578 |
int64_t val; |
579 |
asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); |
580 |
return val;
|
581 |
} |
582 |
|
583 |
#elif defined(__s390__)
|
584 |
|
585 |
static inline int64_t cpu_get_real_ticks(void) |
586 |
{ |
587 |
int64_t val; |
588 |
asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); |
589 |
return val;
|
590 |
} |
591 |
|
592 |
#elif defined(__sparc__)
|
593 |
|
594 |
static inline int64_t cpu_get_real_ticks (void) |
595 |
{ |
596 |
#if defined(_LP64)
|
597 |
uint64_t rval; |
598 |
asm volatile("rd %%tick,%0" : "=r"(rval)); |
599 |
return rval;
|
600 |
#else
|
601 |
/* We need an %o or %g register for this. For recent enough gcc
|
602 |
there is an "h" constraint for that. Don't bother with that. */
|
603 |
union {
|
604 |
uint64_t i64; |
605 |
struct {
|
606 |
uint32_t high; |
607 |
uint32_t low; |
608 |
} i32; |
609 |
} rval; |
610 |
asm volatile("rd %%tick,%%g1; srlx %%g1,32,%0; mov %%g1,%1" |
611 |
: "=r"(rval.i32.high), "=r"(rval.i32.low) : : "g1"); |
612 |
return rval.i64;
|
613 |
#endif
|
614 |
} |
615 |
|
616 |
#elif defined(__mips__) && \
|
617 |
((defined(__mips_isa_rev) && __mips_isa_rev >= 2) || defined(__linux__))
|
618 |
/*
|
619 |
* binutils wants to use rdhwr only on mips32r2
|
620 |
* but as linux kernel emulate it, it's fine
|
621 |
* to use it.
|
622 |
*
|
623 |
*/
|
624 |
#define MIPS_RDHWR(rd, value) { \
|
625 |
__asm__ __volatile__ (".set push\n\t" \
|
626 |
".set mips32r2\n\t" \
|
627 |
"rdhwr %0, "rd"\n\t" \ |
628 |
".set pop" \
|
629 |
: "=r" (value)); \
|
630 |
} |
631 |
|
632 |
static inline int64_t cpu_get_real_ticks(void) |
633 |
{ |
634 |
/* On kernels >= 2.6.25 rdhwr <reg>, $2 and $3 are emulated */
|
635 |
uint32_t count; |
636 |
static uint32_t cyc_per_count = 0; |
637 |
|
638 |
if (!cyc_per_count) {
|
639 |
MIPS_RDHWR("$3", cyc_per_count);
|
640 |
} |
641 |
|
642 |
MIPS_RDHWR("$2", count);
|
643 |
return (int64_t)(count * cyc_per_count);
|
644 |
} |
645 |
|
646 |
#elif defined(__alpha__)
|
647 |
|
648 |
static inline int64_t cpu_get_real_ticks(void) |
649 |
{ |
650 |
uint64_t cc; |
651 |
uint32_t cur, ofs; |
652 |
|
653 |
asm volatile("rpcc %0" : "=r"(cc)); |
654 |
cur = cc; |
655 |
ofs = cc >> 32;
|
656 |
return cur - ofs;
|
657 |
} |
658 |
|
659 |
#else
|
660 |
/* The host CPU doesn't have an easily accessible cycle counter.
|
661 |
Just return a monotonically increasing value. This will be
|
662 |
totally wrong, but hopefully better than nothing. */
|
663 |
static inline int64_t cpu_get_real_ticks (void) |
664 |
{ |
665 |
static int64_t ticks = 0; |
666 |
return ticks++;
|
667 |
} |
668 |
#endif
|
669 |
|
670 |
#ifdef CONFIG_PROFILER
|
671 |
static inline int64_t profile_getclock(void) |
672 |
{ |
673 |
return cpu_get_real_ticks();
|
674 |
} |
675 |
|
676 |
extern int64_t qemu_time, qemu_time_start;
|
677 |
extern int64_t tlb_flush_time;
|
678 |
extern int64_t dev_time;
|
679 |
#endif
|
680 |
|
681 |
#endif
|