Commit 1dce7c3c2244a6f149e7afd7b1d84963ed57b7fd

Authored by bellard
1 parent effedbc9

new clock logic: cpu ticks and virtual clocks are no longer proportional - added…

… timestamps on the stdio console


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2049 c046a42c-6fe2-441c-8c8c-71466251a162
... ... @@ -58,10 +58,19 @@ static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
58 58 }
59 59  
60 60 /* TSC handling */
61   -
62 61 uint64_t cpu_get_tsc(CPUX86State *env)
63 62 {
64   - return qemu_get_clock(vm_clock);
  63 + /* Note: when using kqemu, it is more logical to return the host TSC
  64 + because kqemu does not trap the RDTSC instruction for
  65 + performance reasons */
  66 +#if USE_KQEMU
  67 + if (env->kqemu_enabled) {
  68 + return cpu_get_real_ticks();
  69 + } else
  70 +#endif
  71 + {
  72 + return cpu_get_ticks();
  73 + }
65 74 }
66 75  
67 76 /* IRQ handling */
... ...
linux-user/main.c
... ... @@ -107,29 +107,7 @@ int cpu_get_pic_interrupt(CPUState *env)
107 107  
108 108 /* timers for rdtsc */
109 109  
110   -#if defined(__i386__)
111   -
112   -int64_t cpu_get_real_ticks(void)
113   -{
114   - int64_t val;
115   - asm volatile ("rdtsc" : "=A" (val));
116   - return val;
117   -}
118   -
119   -#elif defined(__x86_64__)
120   -
121   -int64_t cpu_get_real_ticks(void)
122   -{
123   - uint32_t low,high;
124   - int64_t val;
125   - asm volatile("rdtsc" : "=a" (low), "=d" (high));
126   - val = high;
127   - val <<= 32;
128   - val |= low;
129   - return val;
130   -}
131   -
132   -#else
  110 +#if 0
133 111  
134 112 static uint64_t emu_time;
135 113  
... ...
... ... @@ -482,114 +482,103 @@ int kbd_mouse_is_absolute(void)
482 482 return qemu_put_mouse_event_absolute;
483 483 }
484 484  
485   -/***********************************************************/
486   -/* timers */
487   -
488   -#if defined(__powerpc__)
489   -
490   -static inline uint32_t get_tbl(void)
  485 +/* compute with 96 bit intermediate result: (a*b)/c */
  486 +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
491 487 {
492   - uint32_t tbl;
493   - asm volatile("mftb %0" : "=r" (tbl));
494   - return tbl;
495   -}
  488 + union {
  489 + uint64_t ll;
  490 + struct {
  491 +#ifdef WORDS_BIGENDIAN
  492 + uint32_t high, low;
  493 +#else
  494 + uint32_t low, high;
  495 +#endif
  496 + } l;
  497 + } u, res;
  498 + uint64_t rl, rh;
496 499  
497   -static inline uint32_t get_tbu(void)
498   -{
499   - uint32_t tbl;
500   - asm volatile("mftbu %0" : "=r" (tbl));
501   - return tbl;
  500 + u.ll = a;
  501 + rl = (uint64_t)u.l.low * (uint64_t)b;
  502 + rh = (uint64_t)u.l.high * (uint64_t)b;
  503 + rh += (rl >> 32);
  504 + res.l.high = rh / c;
  505 + res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
  506 + return res.ll;
502 507 }
503 508  
504   -int64_t cpu_get_real_ticks(void)
505   -{
506   - uint32_t l, h, h1;
507   - /* NOTE: we test if wrapping has occurred */
508   - do {
509   - h = get_tbu();
510   - l = get_tbl();
511   - h1 = get_tbu();
512   - } while (h != h1);
513   - return ((int64_t)h << 32) | l;
514   -}
  509 +/***********************************************************/
  510 +/* real time host monotonic timer */
515 511  
516   -#elif defined(__i386__)
  512 +#define QEMU_TIMER_BASE 1000000000LL
517 513  
518   -int64_t cpu_get_real_ticks(void)
519   -{
520   -#ifdef _WIN32
521   - LARGE_INTEGER ti;
522   - QueryPerformanceCounter(&ti);
523   - return ti.QuadPart;
524   -#else
525   - int64_t val;
526   - asm volatile ("rdtsc" : "=A" (val));
527   - return val;
528   -#endif
529   -}
  514 +#ifdef WIN32
530 515  
531   -#elif defined(__x86_64__)
  516 +static int64_t clock_freq;
532 517  
533   -int64_t cpu_get_real_ticks(void)
  518 +static void init_get_clock(void)
534 519 {
535   - uint32_t low,high;
536   - int64_t val;
537   - asm volatile("rdtsc" : "=a" (low), "=d" (high));
538   - val = high;
539   - val <<= 32;
540   - val |= low;
541   - return val;
  520 + ret = QueryPerformanceFrequency(&freq);
  521 + if (ret == 0) {
  522 + fprintf(stderr, "Could not calibrate ticks\n");
  523 + exit(1);
  524 + }
  525 + clock_freq = freq.QuadPart;
542 526 }
543 527  
544   -#elif defined(__ia64)
545   -
546   -int64_t cpu_get_real_ticks(void)
  528 +static int64_t get_clock(void)
547 529 {
548   - int64_t val;
549   - asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
550   - return val;
  530 + LARGE_INTEGER ti;
  531 + QueryPerformanceCounter(&ti);
  532 + return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq);
551 533 }
552 534  
553   -#elif defined(__s390__)
  535 +#else
554 536  
555   -int64_t cpu_get_real_ticks(void)
  537 +static int use_rt_clock;
  538 +
  539 +static void init_get_clock(void)
556 540 {
557   - int64_t val;
558   - asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
559   - return val;
  541 + use_rt_clock = 0;
  542 +#if defined(__linux__)
  543 + {
  544 + struct timespec ts;
  545 + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
  546 + use_rt_clock = 1;
  547 + }
  548 + }
  549 +#endif
560 550 }
561 551  
562   -#elif defined(__sparc__) && defined(HOST_SOLARIS)
563   -
564   -uint64_t cpu_get_real_ticks (void)
  552 +static int64_t get_clock(void)
565 553 {
566   -#if defined(_LP64)
567   - uint64_t rval;
568   - asm volatile("rd %%tick,%0" : "=r"(rval));
569   - return rval;
570   -#else
571   - union {
572   - uint64_t i64;
573   - struct {
574   - uint32_t high;
575   - uint32_t low;
576   - } i32;
577   - } rval;
578   - asm volatile("rd %%tick,%1; srlx %1,32,%0"
579   - : "=r"(rval.i32.high), "=r"(rval.i32.low));
580   - return rval.i64;
  554 +#if defined(__linux__)
  555 + if (use_rt_clock) {
  556 + struct timespec ts;
  557 + clock_gettime(CLOCK_MONOTONIC, &ts);
  558 + return ts.tv_sec * 1000000000LL + ts.tv_nsec;
  559 + } else
581 560 #endif
  561 + {
  562 + /* XXX: using gettimeofday leads to problems if the date
  563 + changes, so it should be avoided. */
  564 + struct timeval tv;
  565 + gettimeofday(&tv, NULL);
  566 + return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
  567 + }
582 568 }
583 569  
584   -#else
585   -#error unsupported CPU
586 570 #endif
587 571  
  572 +/***********************************************************/
  573 +/* guest cycle counter */
  574 +
588 575 static int64_t cpu_ticks_prev;
589 576 static int64_t cpu_ticks_offset;
  577 +static int64_t cpu_clock_offset;
590 578 static int cpu_ticks_enabled;
591 579  
592   -static inline int64_t cpu_get_ticks(void)
  580 +/* return the host CPU cycle counter and handle stop/restart */
  581 +int64_t cpu_get_ticks(void)
593 582 {
594 583 if (!cpu_ticks_enabled) {
595 584 return cpu_ticks_offset;
... ... @@ -606,11 +595,24 @@ static inline int64_t cpu_get_ticks(void)
606 595 }
607 596 }
608 597  
  598 +/* return the host CPU monotonic timer and handle stop/restart */
  599 +static int64_t cpu_get_clock(void)
  600 +{
  601 + int64_t ti;
  602 + if (!cpu_ticks_enabled) {
  603 + return cpu_clock_offset;
  604 + } else {
  605 + ti = get_clock();
  606 + return ti + cpu_clock_offset;
  607 + }
  608 +}
  609 +
609 610 /* enable cpu_get_ticks() */
610 611 void cpu_enable_ticks(void)
611 612 {
612 613 if (!cpu_ticks_enabled) {
613 614 cpu_ticks_offset -= cpu_get_real_ticks();
  615 + cpu_clock_offset -= get_clock();
614 616 cpu_ticks_enabled = 1;
615 617 }
616 618 }
... ... @@ -621,69 +623,14 @@ void cpu_disable_ticks(void)
621 623 {
622 624 if (cpu_ticks_enabled) {
623 625 cpu_ticks_offset = cpu_get_ticks();
  626 + cpu_clock_offset = cpu_get_clock();
624 627 cpu_ticks_enabled = 0;
625 628 }
626 629 }
627 630  
628   -#ifdef _WIN32
629   -void cpu_calibrate_ticks(void)
630   -{
631   - LARGE_INTEGER freq;
632   - int ret;
633   -
634   - ret = QueryPerformanceFrequency(&freq);
635   - if (ret == 0) {
636   - fprintf(stderr, "Could not calibrate ticks\n");
637   - exit(1);
638   - }
639   - ticks_per_sec = freq.QuadPart;
640   -}
641   -
642   -#else
643   -static int64_t get_clock(void)
644   -{
645   - struct timeval tv;
646   - gettimeofday(&tv, NULL);
647   - return tv.tv_sec * 1000000LL + tv.tv_usec;
648   -}
649   -
650   -void cpu_calibrate_ticks(void)
651   -{
652   - int64_t usec, ticks;
653   -
654   - usec = get_clock();
655   - ticks = cpu_get_real_ticks();
656   - usleep(50 * 1000);
657   - usec = get_clock() - usec;
658   - ticks = cpu_get_real_ticks() - ticks;
659   - ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec;
660   -}
661   -#endif /* !_WIN32 */
662   -
663   -/* compute with 96 bit intermediate result: (a*b)/c */
664   -uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
665   -{
666   - union {
667   - uint64_t ll;
668   - struct {
669   -#ifdef WORDS_BIGENDIAN
670   - uint32_t high, low;
671   -#else
672   - uint32_t low, high;
673   -#endif
674   - } l;
675   - } u, res;
676   - uint64_t rl, rh;
677   -
678   - u.ll = a;
679   - rl = (uint64_t)u.l.low * (uint64_t)b;
680   - rh = (uint64_t)u.l.high * (uint64_t)b;
681   - rh += (rl >> 32);
682   - res.l.high = rh / c;
683   - res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
684   - return res.ll;
685   -}
686   -
  631 +/***********************************************************/
  632 +/* timers */
  633 +
687 634 #define QEMU_TIMER_REALTIME 0
688 635 #define QEMU_TIMER_VIRTUAL 1
689 636  
... ... @@ -822,28 +769,21 @@ int64_t qemu_get_clock(QEMUClock *clock)
822 769 {
823 770 switch(clock->type) {
824 771 case QEMU_TIMER_REALTIME:
825   -#ifdef _WIN32
826   - return GetTickCount();
827   -#else
828   - {
829   - struct tms tp;
830   -
831   - /* Note that using gettimeofday() is not a good solution
832   - for timers because its value change when the date is
833   - modified. */
834   - if (timer_freq == 100) {
835   - return times(&tp) * 10;
836   - } else {
837   - return ((int64_t)times(&tp) * 1000) / timer_freq;
838   - }
839   - }
840   -#endif
  772 + return get_clock() / 1000000;
841 773 default:
842 774 case QEMU_TIMER_VIRTUAL:
843   - return cpu_get_ticks();
  775 + return cpu_get_clock();
844 776 }
845 777 }
846 778  
  779 +static void init_timers(void)
  780 +{
  781 + init_get_clock();
  782 + ticks_per_sec = QEMU_TIMER_BASE;
  783 + rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
  784 + vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
  785 +}
  786 +
847 787 /* save a timer */
848 788 void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
849 789 {
... ... @@ -985,11 +925,8 @@ static int start_rtc_timer(void)
985 925  
986 926 #endif /* !defined(_WIN32) */
987 927  
988   -static void init_timers(void)
  928 +static void init_timer_alarm(void)
989 929 {
990   - rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
991   - vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
992   -
993 930 #ifdef _WIN32
994 931 {
995 932 int count=0;
... ... @@ -1354,7 +1291,9 @@ CharDriverState *qemu_chr_open_pipe(const char *filename)
1354 1291  
1355 1292 static int term_got_escape, client_index;
1356 1293 static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
1357   -int term_fifo_size;
  1294 +static int term_fifo_size;
  1295 +static int term_timestamps;
  1296 +static int64_t term_timestamps_start;
1358 1297  
1359 1298 void term_print_help(void)
1360 1299 {
... ... @@ -1363,6 +1302,7 @@ void term_print_help(void)
1363 1302 "C-a x exit emulator\n"
1364 1303 "C-a s save disk data back to file (if -snapshot)\n"
1365 1304 "C-a b send break (magic sysrq)\n"
  1305 + "C-a t toggle console timestamps\n"
1366 1306 "C-a c switch between console and monitor\n"
1367 1307 "C-a C-a send C-a\n"
1368 1308 );
... ... @@ -1409,6 +1349,10 @@ static void stdio_received_byte(int ch)
1409 1349 goto send_char;
1410 1350 }
1411 1351 break;
  1352 + case 't':
  1353 + term_timestamps = !term_timestamps;
  1354 + term_timestamps_start = -1;
  1355 + break;
1412 1356 case TERM_ESCAPE:
1413 1357 goto send_char;
1414 1358 }
... ... @@ -1466,6 +1410,39 @@ static void stdio_read(void *opaque)
1466 1410 stdio_received_byte(buf[0]);
1467 1411 }
1468 1412  
  1413 +static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
  1414 +{
  1415 + FDCharDriver *s = chr->opaque;
  1416 + if (!term_timestamps) {
  1417 + return unix_write(s->fd_out, buf, len);
  1418 + } else {
  1419 + int i;
  1420 + char buf1[64];
  1421 +
  1422 + for(i = 0; i < len; i++) {
  1423 + unix_write(s->fd_out, buf + i, 1);
  1424 + if (buf[i] == '\n') {
  1425 + int64_t ti;
  1426 + int secs;
  1427 +
  1428 + ti = get_clock();
  1429 + if (term_timestamps_start == -1)
  1430 + term_timestamps_start = ti;
  1431 + ti -= term_timestamps_start;
  1432 + secs = ti / 1000000000;
  1433 + snprintf(buf1, sizeof(buf1),
  1434 + "[%02d:%02d:%02d.%03d] ",
  1435 + secs / 3600,
  1436 + (secs / 60) % 60,
  1437 + secs % 60,
  1438 + (int)((ti / 1000000) % 1000));
  1439 + unix_write(s->fd_out, buf1, strlen(buf1));
  1440 + }
  1441 + }
  1442 + return len;
  1443 + }
  1444 +}
  1445 +
1469 1446 /* init terminal so that we can grab keys */
1470 1447 static struct termios oldtty;
1471 1448 static int old_fd0_flags;
... ... @@ -1511,6 +1488,7 @@ CharDriverState *qemu_chr_open_stdio(void)
1511 1488 if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
1512 1489 return NULL;
1513 1490 chr = qemu_chr_open_fd(0, 1);
  1491 + chr->chr_write = stdio_write;
1514 1492 if (stdio_nb_clients == 0)
1515 1493 qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL);
1516 1494 client_index = stdio_nb_clients;
... ... @@ -5638,6 +5616,7 @@ int main(int argc, char **argv)
5638 5616 SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
5639 5617 #endif
5640 5618 init_timers();
  5619 + init_timer_alarm();
5641 5620  
5642 5621 register_machines();
5643 5622 machine = first_machine;
... ... @@ -6128,7 +6107,6 @@ int main(int argc, char **argv)
6128 6107 register_savevm("ram", 0, 1, ram_save, ram_load, NULL);
6129 6108  
6130 6109 init_ioports();
6131   - cpu_calibrate_ticks();
6132 6110  
6133 6111 /* terminal init */
6134 6112 if (nographic) {
... ...
... ... @@ -390,6 +390,7 @@ int qemu_timer_pending(QEMUTimer *ts);
390 390 extern int64_t ticks_per_sec;
391 391 extern int pit_min_timer_count;
392 392  
  393 +int64_t cpu_get_ticks(void);
393 394 void cpu_enable_ticks(void);
394 395 void cpu_disable_ticks(void);
395 396  
... ...