From: Andi Kleen <ak@suse.de>
To: jeremy@goop.org, zach@vmware.com, dhecht@vmware.com,
johnstul@us.ibm.com, patches@x86-64.org,
linux-kernel@vger.kernel.org
Subject: [PATCH] [17/34] x86: PARAVIRT: Add a sched_clock paravirt_op
Date: Mon, 30 Apr 2007 17:49:49 +0200 (CEST) [thread overview]
Message-ID: <20070430154949.C640A151CA@wotan.suse.de> (raw)
In-Reply-To: <20070430549.617098000@suse.de>
From: Jeremy Fitzhardinge <jeremy@goop.org>
The tsc-based get_scheduled_cycles interface is not a good match for
Xen's runstate accounting, which reports everything in nanoseconds.
This patch replaces this interface with a sched_clock interface, which
matches both Xen and VMI's requirements.
In order to do this, we:
1. replace get_scheduled_cycles with sched_clock
2. hoist cycles_2_ns into a common header
3. update vmi accordingly
One thing to note: because sched_clock is implemented as a weak
function in kernel/sched.c, we must define a real function in order to
override this weak binding. This means the usual paravirt_ops
technique of using an inline function won't work in this case.
[ This is against Andi's patch queue. It fixes the x86-64 build problem. ]
Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Cc: Zachary Amsden <zach@vmware.com>
Cc: Dan Hecht <dhecht@vmware.com>
Cc: john stultz <johnstul@us.ibm.com>
---
arch/i386/kernel/paravirt.c | 2 -
arch/i386/kernel/sched-clock.c | 43 ++++++++++++++---------------------
arch/i386/kernel/vmi.c | 2 -
arch/i386/kernel/vmiclock.c | 4 +--
include/asm-i386/paravirt.h | 7 ++++-
include/asm-i386/sched-clock.h | 49 +++++++++++++++++++++++++++++++++++++++++
include/asm-i386/timer.h | 2 -
include/asm-i386/vmi_time.h | 2 -
include/asm-x86_64/timer.h | 2 -
9 files changed, 78 insertions(+), 35 deletions(-)
===================================================================
Index: linux/arch/i386/kernel/paravirt.c
===================================================================
--- linux.orig/arch/i386/kernel/paravirt.c
+++ linux/arch/i386/kernel/paravirt.c
@@ -268,7 +268,7 @@ struct paravirt_ops paravirt_ops = {
.write_msr = native_write_msr_safe,
.read_tsc = native_read_tsc,
.read_pmc = native_read_pmc,
- .get_scheduled_cycles = native_read_tsc,
+ .sched_clock = native_sched_clock,
.get_cpu_khz = native_calculate_cpu_khz,
.load_tr_desc = native_load_tr_desc,
.set_ldt = native_set_ldt,
Index: linux/arch/i386/kernel/sched-clock.c
===================================================================
--- linux.orig/arch/i386/kernel/sched-clock.c
+++ linux/arch/i386/kernel/sched-clock.c
@@ -35,30 +35,9 @@
* -johnstul@us.ibm.com "math is hard, lets go shopping!"
*/
-#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
-
-struct sc_data {
- unsigned cyc2ns_scale;
- unsigned unstable;
- unsigned long long sync_base; /* TSC or jiffies at syncpoint*/
- unsigned long long ns_base; /* nanoseconds at sync point */
- unsigned long long last_val; /* Last returned value */
-};
-
-static DEFINE_PER_CPU(struct sc_data, sc_data) =
+DEFINE_PER_CPU(struct sc_data, sc_data) =
{ .unstable = 1, .sync_base = INITIAL_JIFFIES };
-static inline u64 cycles_2_ns(struct sc_data *sc, u64 cyc)
-{
- u64 ns;
-
- cyc -= sc->sync_base;
- ns = (cyc * sc->cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
- ns += sc->ns_base;
-
- return ns;
-}
-
/*
* Scheduler clock - returns current time in nanosec units.
* All data is local to the CPU.
@@ -79,7 +58,7 @@ static inline u64 cycles_2_ns(struct sc_
* per CPU. This state is protected against parallel state changes
* with interrupts off.
*/
-unsigned long long sched_clock(void)
+unsigned long long native_sched_clock(void)
{
unsigned long long r;
struct sc_data *sc = &get_cpu_var(sc_data);
@@ -98,8 +77,8 @@ unsigned long long sched_clock(void)
sc->last_val = r;
local_irq_restore(flags);
} else {
- get_scheduled_cycles(r);
- r = cycles_2_ns(sc, r);
+ rdtscll(r);
+ r = cycles_2_ns(r);
sc->last_val = r;
}
@@ -108,6 +87,18 @@ unsigned long long sched_clock(void)
return r;
}
+/* We need to define a real function for sched_clock, to override the
+ weak default version */
+#ifdef CONFIG_PARAVIRT
+unsigned long long sched_clock(void)
+{
+ return paravirt_sched_clock();
+}
+#else
+unsigned long long sched_clock(void)
+ __attribute__((alias("native_sched_clock")));
+#endif
+
/* Resync with new CPU frequency */
static void resync_sc_freq(struct sc_data *sc, unsigned int newfreq)
{
@@ -124,7 +115,7 @@ static void resync_sc_freq(struct sc_dat
because sched_clock callers should be able to tolerate small
errors. */
sc->ns_base = ktime_to_ns(ktime_get());
- get_scheduled_cycles(sc->sync_base);
+ rdtscll(sc->sync_base);
sc->cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR) / newfreq;
}
Index: linux/arch/i386/kernel/vmi.c
===================================================================
--- linux.orig/arch/i386/kernel/vmi.c
+++ linux/arch/i386/kernel/vmi.c
@@ -890,7 +890,7 @@ static inline int __init activate_vmi(vo
paravirt_ops.setup_boot_clock = vmi_time_bsp_init;
paravirt_ops.setup_secondary_clock = vmi_time_ap_init;
#endif
- paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles;
+ paravirt_ops.sched_clock = vmi_sched_clock;
paravirt_ops.get_cpu_khz = vmi_cpu_khz;
/* We have true wallclock functions; disable CMOS clock sync */
Index: linux/arch/i386/kernel/vmiclock.c
===================================================================
--- linux.orig/arch/i386/kernel/vmiclock.c
+++ linux/arch/i386/kernel/vmiclock.c
@@ -65,9 +65,9 @@ int vmi_set_wallclock(unsigned long now)
}
/* paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles */
-unsigned long long vmi_get_sched_cycles(void)
+unsigned long long vmi_sched_clock(void)
{
- return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE);
+ return cycles_2_ns(vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE));
}
/* paravirt_ops.get_cpu_khz = vmi_cpu_khz */
Index: linux/include/asm-i386/paravirt.h
===================================================================
--- linux.orig/include/asm-i386/paravirt.h
+++ linux/include/asm-i386/paravirt.h
@@ -116,7 +116,7 @@ struct paravirt_ops
u64 (*read_tsc)(void);
u64 (*read_pmc)(void);
- u64 (*get_scheduled_cycles)(void);
+ unsigned long long (*sched_clock)(void);
unsigned long (*get_cpu_khz)(void);
/* Segment descriptor handling */
@@ -573,7 +573,10 @@ static inline u64 paravirt_read_tsc(void
#define rdtscll(val) (val = paravirt_read_tsc())
-#define get_scheduled_cycles(val) (val = paravirt_ops.get_scheduled_cycles())
+static inline unsigned long long paravirt_sched_clock(void)
+{
+ return PVOP_CALL0(unsigned long long, sched_clock);
+}
#define calculate_cpu_khz() (paravirt_ops.get_cpu_khz())
#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
Index: linux/include/asm-i386/sched-clock.h
===================================================================
--- /dev/null
+++ linux/include/asm-i386/sched-clock.h
@@ -0,0 +1,49 @@
+#ifndef _ASM_SCHED_CLOCK_H
+#define _ASM_SCHED_CLOCK_H
+
+/* Accellerators for sched_clock()
+ * convert from cycles(64bits) => nanoseconds (64bits)
+ * basic equation:
+ * ns = cycles / (freq / ns_per_sec)
+ * ns = cycles * (ns_per_sec / freq)
+ * ns = cycles * (10^9 / (cpu_khz * 10^3))
+ * ns = cycles * (10^6 / cpu_khz)
+ *
+ * Then we use scaling math (suggested by george@mvista.com) to get:
+ * ns = cycles * (10^6 * SC / cpu_khz) / SC
+ * ns = cycles * cyc2ns_scale / SC
+ *
+ * And since SC is a constant power of two, we can convert the div
+ * into a shift.
+ *
+ * We can use khz divisor instead of mhz to keep a better percision, since
+ * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
+ * (mathieu.desnoyers@polymtl.ca)
+ *
+ * -johnstul@us.ibm.com "math is hard, lets go shopping!"
+ */
+struct sc_data {
+ unsigned cyc2ns_scale;
+ unsigned unstable;
+ unsigned long long sync_base; /* TSC or jiffies at syncpoint*/
+ unsigned long long ns_base; /* nanoseconds at sync point */
+ unsigned long long last_val; /* Last returned value */
+};
+
+DECLARE_PER_CPU(struct sc_data, sc_data);
+
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline unsigned long long cycles_2_ns(unsigned long long cyc)
+{
+ const struct sc_data *sc = &__get_cpu_var(sc_data);
+ unsigned long long ns;
+
+ cyc -= sc->sync_base;
+ ns = (cyc * sc->cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+ ns += sc->ns_base;
+
+ return ns;
+}
+
+#endif /* _ASM_SCHED_CLOCK_H */
Index: linux/include/asm-i386/timer.h
===================================================================
--- linux.orig/include/asm-i386/timer.h
+++ linux/include/asm-i386/timer.h
@@ -2,6 +2,7 @@
#define _ASMi386_TIMER_H
#include <linux/init.h>
#include <linux/pm.h>
+#include <asm/sched-clock.h>
#define TICK_SIZE (tick_nsec / 1000)
@@ -15,7 +16,6 @@ extern int no_sync_cmos_clock;
extern int recalibrate_cpu_khz(void);
#ifndef CONFIG_PARAVIRT
-#define get_scheduled_cycles(val) rdtscll(val)
#define calculate_cpu_khz() native_calculate_cpu_khz()
#endif
Index: linux/include/asm-i386/vmi_time.h
===================================================================
--- linux.orig/include/asm-i386/vmi_time.h
+++ linux/include/asm-i386/vmi_time.h
@@ -49,7 +49,7 @@ extern struct vmi_timer_ops {
extern void __init vmi_time_init(void);
extern unsigned long vmi_get_wallclock(void);
extern int vmi_set_wallclock(unsigned long now);
-extern unsigned long long vmi_get_sched_cycles(void);
+extern unsigned long long vmi_sched_clock(void);
extern unsigned long vmi_cpu_khz(void);
#ifdef CONFIG_X86_LOCAL_APIC
Index: linux/include/asm-x86_64/timer.h
===================================================================
--- linux.orig/include/asm-x86_64/timer.h
+++ linux/include/asm-x86_64/timer.h
@@ -1 +1 @@
-#define get_scheduled_cycles(x) rdtscll(x)
+#include <asm-i386/sched-clock.h>
next prev parent reply other threads:[~2007-04-30 15:53 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-30 15:49 [PATCH] [0/34] x86 candidate patches for review VI: MTRR, APIC, more paravirt, misc Andi Kleen
2007-04-30 15:49 ` [PATCH] [1/34] x86_64: Move mtrr prototypes from proto.h to mtrr.h Andi Kleen
2007-04-30 15:49 ` [PATCH] [2/34] x86: Adds mtrr_save_fixed_ranges() for use in two later patches Andi Kleen
2007-04-30 15:49 ` [PATCH] [3/34] x86: Save the MTRRs of the BSP before booting an AP Andi Kleen
2007-04-30 15:49 ` [PATCH] [4/34] x86: Save and restore the fixed-range MTRRs of the BSP when suspending Andi Kleen
2007-04-30 15:49 ` [PATCH] [5/34] i386: Enable support for fixed-range IORRs to keep RdMem & WrMem in sync Andi Kleen
2007-04-30 15:49 ` [PATCH] [6/34] i386: safe_apic_wait_icr_idle - i386 Andi Kleen
2007-04-30 15:49 ` [PATCH] [7/34] x86_64: safe_apic_wait_icr_idle - x86_64 Andi Kleen
2007-04-30 15:49 ` [PATCH] [8/34] i386: use safe_apic_wait_icr_idle - i386 Andi Kleen
2007-04-30 15:49 ` [PATCH] [9/34] x86_64: use safe_apic_wait_icr_idle in smpboot.c - x86_64 Andi Kleen
2007-04-30 15:49 ` [PATCH] [10/34] i386: use safe_apic_wait_icr_idle in smpboot.c Andi Kleen
2007-04-30 15:49 ` [PATCH] [11/34] x86_64: use safe_apic_wait_icr_idle in smpboot.c - x86_64 Andi Kleen
2007-04-30 15:49 ` [PATCH] [12/34] i386: __send_IPI_dest_field - i386 Andi Kleen
2007-04-30 15:49 ` [PATCH] [13/34] x86_64: __send_IPI_dest_field - x86_64 Andi Kleen
2007-04-30 15:49 ` [PATCH] [14/34] i386: Use safe_apic_wait_icr_idle in safe_apic_wait_icr_idle - i386 Andi Kleen
2007-04-30 15:49 ` [PATCH] [15/34] x86_64: Use safe_apic_wait_icr_idle in __send_IPI_dest_field - x86_64 Andi Kleen
2007-04-30 15:49 ` [PATCH] [16/34] i386: fix mtrr sections Andi Kleen
2007-05-02 17:08 ` Bernhard Kaindl
2007-05-03 11:16 ` Bernhard Kaindl
2007-05-03 11:19 ` Andi Kleen
2007-05-03 15:12 ` Randy Dunlap
2007-04-30 15:49 ` Andi Kleen [this message]
2007-04-30 15:49 ` [PATCH] [18/34] i386: PARAVIRT: fix startup_ipi_hook config dependency Andi Kleen
2007-04-30 15:49 ` [PATCH] [19/34] x86_64: move __vgetcpu_mode & __jiffies to the vsyscall_2 zone Andi Kleen
2007-04-30 15:49 ` [PATCH] [20/34] i386: avoid checking for cpu gone when CONFIG_HOTPLUG_CPU not defined Andi Kleen
2007-04-30 15:49 ` [PATCH] [21/34] i386: replace spin_lock_irqsave with spin_lock Andi Kleen
2007-04-30 15:49 ` [PATCH] [22/34] i386: clean up flush_tlb_others fn Andi Kleen
2007-04-30 15:49 ` [PATCH] [23/34] i386: check capability Andi Kleen
2007-04-30 15:49 ` [PATCH] [24/34] x86_64: Auto compute __NR_syscall_max at compile time Andi Kleen
2007-04-30 15:49 ` [PATCH] [25/34] x86_64: skip cache_free_alien() on non NUMA Andi Kleen
2007-04-30 15:49 ` [PATCH] [26/34] i386: remove xtime_lock'ing around cpufreq notifier Andi Kleen
2007-04-30 15:50 ` [PATCH] [27/34] i386: pte clear optimization Andi Kleen
2007-04-30 15:50 ` [PATCH] [28/34] i386: pte xchg optimization Andi Kleen
2007-05-02 10:52 ` [patches] " Jan Beulich
2007-05-02 11:05 ` Andi Kleen
2007-05-02 19:19 ` Zachary Amsden
2007-04-30 15:50 ` [PATCH] [29/34] i386: pte simplify ops Andi Kleen
2007-04-30 15:50 ` [PATCH] [30/34] i386: convert the monitor thread to use the kthread API Andi Kleen
2007-04-30 16:55 ` James Bottomley
2007-04-30 17:56 ` Andi Kleen
2007-04-30 15:50 ` [PATCH] [31/34] i386: convert to " Andi Kleen
2007-04-30 15:50 ` [PATCH] [32/34] x86_64: unexport cpu_llc_id Andi Kleen
2007-04-30 15:50 ` [PATCH] [34/34] x86_64: ignore vgacon if hardware not present Andi Kleen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070430154949.C640A151CA@wotan.suse.de \
--to=ak@suse.de \
--cc=dhecht@vmware.com \
--cc=jeremy@goop.org \
--cc=johnstul@us.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=patches@x86-64.org \
--cc=zach@vmware.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®