mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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>

  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®