Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/alpha Improve time keeping and host CPU usage when ...



details:   https://anonhg.NetBSD.org/src/rev/37eb1dc4c9b1
branches:  trunk
changeset: 944446:37eb1dc4c9b1
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Tue Sep 29 01:33:00 2020 +0000

description:
Improve time keeping and host CPU usage when running in Qemu:
- clockattach(): Allow multiple calls when running in Qemu. Anything
  after this first one is ignored, but this gives us a change to use
  a clock source provided by the VM directly, rather than relying on
  a more expensive hardware emulation.
- Add cpu_initclocks_secondary(), to handle clock setup on secondary
  CPUs, if needed.
- Allow us to use the WTINT PALcode call in cpu_idle() to idle in a lower
  power state (Qemu's PALcode supports this).
- Use the Qemu per-cpu set-alarm-rel call as the hardclock interrupt
  source.  In Qemu environments, reduce hz to 50 (rather than the
  default 1024) to give the clock a snowball's chance when running on
  a host system with hz=100.  XXX We have to manually re-calculate
  tick and tickadj.  There should be MI code to do this for us.  Also
  in Qemu environments, let hardclock() drive the sched clock by setting
  schedhz=0.

diffstat:

 sys/arch/alpha/alpha/clock.c |  24 ++++++++++--
 sys/arch/alpha/alpha/cpu.c   |  27 +++++++++++++-
 sys/arch/alpha/alpha/qemu.c  |  81 ++++++++++++++++++++++++++++++++++++++++++-
 sys/arch/alpha/include/cpu.h |   8 +++-
 4 files changed, 130 insertions(+), 10 deletions(-)

diffs (253 lines):

diff -r 6460cf63670c -r 37eb1dc4c9b1 sys/arch/alpha/alpha/clock.c
--- a/sys/arch/alpha/alpha/clock.c      Tue Sep 29 01:20:59 2020 +0000
+++ b/sys/arch/alpha/alpha/clock.c      Tue Sep 29 01:33:00 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: clock.c,v 1.44 2020/09/27 23:17:36 thorpej Exp $ */
+/* $NetBSD: clock.c,v 1.45 2020/09/29 01:33:00 thorpej Exp $ */
 
 /*
  * Copyright (c) 1988 University of Utah.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.44 2020/09/27 23:17:36 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.45 2020/09/29 01:33:00 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -64,10 +64,16 @@
 {
 
        /*
-        * Just bookkeeping.
+        * Just bookkeeping.  We only allow one system clock.  If
+        * we're running on real hardware, enforce this.  If we're
+        * running under Qemu, anything after the first one.
         */
-       if (clock_init != NULL)
+       if (clock_init != NULL) {
+               if (alpha_is_qemu) {
+                       return;
+               }
                panic("clockattach: multiple clocks");
+       }
        clock_init = fns;
        clockdev = dev;
 }
@@ -114,6 +120,16 @@
 }
 
 /*
+ * Some platforms might have other per-cpu clock initialization.  This
+ * is handled here.
+ */
+void
+cpu_initclocks_secondary(void)
+{
+       (*clock_init)(clockdev);
+}
+
+/*
  * We assume newhz is either stathz or profhz, and that neither will
  * change after being set up above.  Could recalculate intervals here
  * but that would be a drag.
diff -r 6460cf63670c -r 37eb1dc4c9b1 sys/arch/alpha/alpha/cpu.c
--- a/sys/arch/alpha/alpha/cpu.c        Tue Sep 29 01:20:59 2020 +0000
+++ b/sys/arch/alpha/alpha/cpu.c        Tue Sep 29 01:33:00 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.c,v 1.100 2020/09/04 01:56:29 thorpej Exp $ */
+/* $NetBSD: cpu.c,v 1.101 2020/09/29 01:33:00 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
 
 #include <sys/cdefs.h>                 /* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.100 2020/09/04 01:56:29 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.101 2020/09/29 01:33:00 thorpej Exp $");
 
 #include "opt_ddb.h"
 #include "opt_multiprocessor.h"
@@ -100,6 +100,27 @@
 void   cpu_boot_secondary(struct cpu_info *);
 #endif /* MULTIPROCESSOR */
 
+static void
+cpu_idle_default(void)
+{
+       /*
+        * Default is to do nothing.  Platform code can overwrite
+        * as needed.
+        */
+}
+
+void
+cpu_idle_wtint(void)
+{
+       /*
+        * Some PALcode versions implement the WTINT call to idle
+        * in a low power mode.
+        */
+       alpha_pal_wtint(0);
+}
+
+void   (*cpu_idle_fn)(void) __read_mostly = cpu_idle_default;
+
 /*
  * The Implementation Version and the Architecture Mask must be
  * consistent across all CPUs in the system, so we set it for the
@@ -582,6 +603,8 @@
        alpha_pal_imb();
 
        cc_calibrate_cpu(ci);
+
+       cpu_initclocks_secondary();
 }
 
 int
diff -r 6460cf63670c -r 37eb1dc4c9b1 sys/arch/alpha/alpha/qemu.c
--- a/sys/arch/alpha/alpha/qemu.c       Tue Sep 29 01:20:59 2020 +0000
+++ b/sys/arch/alpha/alpha/qemu.c       Tue Sep 29 01:33:00 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: qemu.c,v 1.1 2020/09/27 23:59:37 thorpej Exp $ */
+/* $NetBSD: qemu.c,v 1.2 2020/09/29 01:33:00 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -38,12 +38,16 @@
 #include <sys/device.h>
 #include <sys/time.h>
 #include <sys/timetc.h>
+#include <sys/kernel.h>
 #include <sys/cpu.h>
 
 #include <machine/autoconf.h>
+#include <machine/cpuconf.h>
 #include <machine/rpb.h>
 #include <machine/alpha.h>
 
+#include <alpha/alpha/clockvar.h>
+
 extern struct cfdriver qemu_cd;
 
 struct qemu_softc {
@@ -57,7 +61,7 @@
 {
        register unsigned long v0 __asm("$0");
        register unsigned long a0 __asm("$16") = 7;     /* Qemu get-time */
-       
+
        __asm volatile ("call_pal %2"
                : "=r"(v0), "+r"(a0)
                : "i"(PAL_cserve)
@@ -66,6 +70,69 @@
        return (u_int)v0;
 }
 
+static inline void
+qemu_set_alarm_relative(unsigned long nsec)
+{
+       register unsigned long a0 __asm("$16") = 5;     /* Qemu set-alarm-rel */
+       register unsigned long a1 __asm("$17") = nsec;
+
+       __asm volatile ("call_pal %2"
+               : "+r"(a0), "+r"(a1)
+               : "i"(PAL_cserve)
+               : "$0", "$18", "$19", "$20", "$21");
+}
+
+static unsigned long qemu_nsec_per_tick __read_mostly;
+
+static void
+qemu_hardclock(struct clockframe * const framep)
+{
+       if (__predict_false(qemu_nsec_per_tick == 0)) {
+               /* Spurious; qemu_clock_init() hasn't been called yet. */
+               return;
+       }
+
+       /* Schedule the next tick before we process the current one. */
+       qemu_set_alarm_relative(qemu_nsec_per_tick);
+
+       hardclock(framep);
+}
+
+static void
+qemu_clock_init(void * const v __unused)
+{
+       /* First-time initialization... */
+       if (qemu_nsec_per_tick == 0) {
+               KASSERT(CPU_IS_PRIMARY(curcpu()));
+               qemu_nsec_per_tick = 1000000000UL / hz;
+
+               /*
+                * Override the clockintr routine; the Qemu alarm is
+                * one-shot, so we have to restart it for the next one.
+                */
+               platform.clockintr = qemu_hardclock;
+
+               /*
+                * hz=1024 is a little bananas for an emulated
+                * virtual machine.  Reset to something more
+                * reasonable, and recalculate everything based
+                * on it.
+                */
+               hz = 50;
+               tick = 1000000 / hz;
+               tickadj = (240000 / (60 * hz)) ? (240000 / (60 * hz)) : 1;
+               schedhz = 0;
+
+               printf("Using the Qemu CPU alarm for %d Hz hardclock.\n", hz);
+       }
+
+       /*
+        * Note: We need to do this on each CPU, as the Qemu
+        * alarm is implemented as a per-CPU register.
+        */
+       qemu_set_alarm_relative(qemu_nsec_per_tick);
+}
+
 static int
 qemu_match(device_t parent, cfdata_t cfdata, void *aux)
 {
@@ -98,6 +165,16 @@
        tc->tc_frequency = 1000000000UL;        /* nanosecond granularity */
        tc->tc_priv = sc;
        tc_init(tc);
+
+       /*
+        * Use the Qemu alarm as the system clock.
+        */
+       clockattach(qemu_clock_init, sc);
+
+       /*
+        * Qemu's PALcode implements WTINT; use it to save host cycles.
+        */
+       cpu_idle_fn = cpu_idle_wtint;
 }
 
 CFATTACH_DECL_NEW(qemu, sizeof(struct qemu_softc),
diff -r 6460cf63670c -r 37eb1dc4c9b1 sys/arch/alpha/include/cpu.h
--- a/sys/arch/alpha/include/cpu.h      Tue Sep 29 01:20:59 2020 +0000
+++ b/sys/arch/alpha/include/cpu.h      Tue Sep 29 01:33:00 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.h,v 1.97 2020/09/25 03:40:11 thorpej Exp $ */
+/* $NetBSD: cpu.h,v 1.98 2020/09/29 01:33:00 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -242,7 +242,11 @@
 void * cpu_uarea_alloc(bool);
 bool   cpu_uarea_free(void *);
 
-#define        cpu_idle()      /* nothing */
+void   cpu_idle_wtint(void);
+extern void (*cpu_idle_fn)(void);
+#define        cpu_idle()      (*cpu_idle_fn)()
+
+void   cpu_initclocks_secondary(void);
 
 #endif /* _KERNEL */
 #endif /* _ALPHA_CPU_H_ */



Home | Main Index | Thread Index | Old Index