All of lore.kernel.org
 help / color / mirror / Atom feed
From: "George Spelvin" <linux@horizon.com>
To: linux@horizon.com, mingo@kernel.org
Cc: adrian.hunter@intel.com, ak@linux.intel.com, hpa@zytor.com,
	linux-kernel@vger.kernel.org, luto@amacapital.net,
	tglx@linutronix.de, torvalds@linux-foundation.org
Subject: Re: [PATCH RFC] x86, tsc: Allow for high latency in quick_pit_calibrate()
Date: 5 Jun 2015 16:17:39 -0400	[thread overview]
Message-ID: <20150605201739.20651.qmail@ns.horizon.com> (raw)
In-Reply-To: <20150605083107.GA29843@gmail.com>

> I'll run your code as well, to make sure it's not something bad in my code.

Here's a modified version that uses less stack space (no need to store
all 64 bits of a timestamp), and captures a window around an RTC periodic
flag edge to explore WTF is going on there.

commit 769eba0b589141edca3541cfb1e30e01b806e5cb
Author: George Spelvin <linux@horizon.com>
Date:   Thu Jun 4 22:04:19 2015 -0400

    x86, tsc: Add test code.

diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index a00f35be..00ff0359 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -22,6 +22,8 @@
 #include <asm/nmi.h>
 #include <asm/x86_init.h>
 
+#include <asm/mc146818rtc.h>
+
 unsigned int __read_mostly cpu_khz;	/* TSC clocks / usec, not used here */
 EXPORT_SYMBOL(cpu_khz);
 
@@ -533,15 +535,15 @@ static inline int pit_verify_msb(unsigned char val)
 
 static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *deltap)
 {
-	int count;
-	u64 tsc = 0, prev_tsc = 0;
+	int count = 0;
+	u64 prev_tsc, tsc = 0;
 
-	for (count = 0; count < 50000; count++) {
-		if (!pit_verify_msb(val))
-			break;
+	do {
+		if (++count > 50000)
+			return 0;
 		prev_tsc = tsc;
 		tsc = get_cycles();
-	}
+	} while (pit_verify_msb(val));
 	*deltap = get_cycles() - prev_tsc;
 	*tscp = tsc;
 
@@ -552,6 +554,177 @@ static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *de
 	return count > 5;
 }
 
+/* Similar, but only a single read.  And returns the number of reads. */
+static inline unsigned
+pit_expect_msb1(unsigned char val, unsigned *tscp, unsigned *deltap)
+{
+	int count = 0;
+	unsigned prev_tsc, tsc = 0;
+
+	do {
+		if (++count > 50000)
+			return 0;
+		prev_tsc = tsc;
+		tsc = (unsigned)get_cycles();
+	} while (inb(0x42) == val);
+	*deltap = (unsigned)get_cycles() - prev_tsc;
+	*tscp = tsc;
+
+	return count;
+}
+
+static inline unsigned
+rtc_wait_bit(unsigned *tscp, unsigned *deltap)
+{
+	int count = 0;
+	unsigned prev_tsc, tsc = 0;
+
+	do {
+		if (++count > 5000)
+			return 0;
+		prev_tsc = tsc;
+		tsc = (unsigned)get_cycles();
+	} while (~inb(RTC_PORT(1)) & RTC_PF);	/* Wait for bit 6 to be set */
+	*deltap = (unsigned)get_cycles() - prev_tsc;
+	*tscp = tsc;
+
+	/*
+	 * We require _some_ success, but the quality control
+	 * will be based on the error terms on the TSC values.
+	 */
+	return count;
+}
+
+#define SAMPLES 64
+
+static void noinline_for_stack
+pit_test(void)
+{
+	unsigned tsc[SAMPLES+1];	/* How long since rpevious edge */
+	unsigned range[SAMPLES+1];	/* Range of uncertainty */
+	unsigned iter[SAMPLES];	/*& Number of iterations for capture */
+	int i, j;
+	unsigned char saved_a, saved_b;
+	unsigned long flags;
+	extern spinlock_t rtc_lock;
+
+	outb(0xb0, 0x43);
+
+	/* Start at 0xffff */
+	outb(0xff, 0x42);
+	outb(0xff, 0x42);
+
+	pit_verify_msb(0);
+
+	/*
+	 * Among the evil non-portable hacks this code does, it exploits
+	 * the fact that x86 is little-endian and allows unaligned stores
+	 * to store 64-bit values into an array of 32-bit values, where
+	 * each one overwrites the high half of the one before.
+	 */
+	if (pit_expect_msb(0xff, (u64 *)tsc, (unsigned long *)range)) {
+		for (i = 1; i < SAMPLES; i++) {
+			if (!pit_expect_msb(0xff - i, (u64 *)(tsc+i), (unsigned long *)(range+i)))
+				break;
+			if (!pit_verify_msb(0xfe - i))
+				break;
+		}
+		printk("** 2-byte PIT timing\n");
+		for (j = 1; j < i; j++)
+			printk("PIT edge delta %7u, range %6u\n",
+				tsc[j] - tsc[j-1], range[j]);
+	}
+
+	/* Try again, with one-byte reads */
+	outb(0xa0, 0x43);
+	outb(0xff, 0x42);	/* Start at 0xff00 */
+
+	/* Wait until we reach 0xfe (should be very fast) */
+	pit_verify_msb(0);
+	for (i = 0; i < 1000; i++)
+		if (inb(0x42) == 0xfe)
+			break;
+
+	if (i < 1000) {
+		for (i = 0; i < SAMPLES; i++) {
+			iter[i] = pit_expect_msb1(0xfe - i, tsc+i, range+i);
+			if (iter[i] <= 5)
+				break;
+			if (inb(0x42) != 0xfd - i)
+				break;
+		}
+		printk("** 1-byte PIT timing\n");
+		for (j = 1; j < i; j++)
+			printk("PIT edge delta %7u, range %6u, iter %u\n",
+				tsc[j] - tsc[j-1], range[j], iter[j]);
+	}
+
+	/* Once more, with the RTC */
+	spin_lock_irqsave(&rtc_lock, flags);
+
+	lock_cmos_prefix(RTC_REG_C);
+/* This is skanky stuff that requries rewritten RTC locking to do properly */
+	outb(RTC_REG_B, RTC_PORT(0));
+	saved_b = inb(RTC_PORT(1));
+	outb(saved_b & 7, RTC_PORT(1));	/* Clear interrupt enables */
+
+	outb(RTC_REG_A, RTC_PORT(0));
+	saved_a = inb(RTC_PORT(1));
+	outb((saved_a & 0xf0) | 3, RTC_PORT(1));	/* Set 8 kHz rate */
+/* End of skanky stuff */
+
+	outb(RTC_REG_C, RTC_PORT(0));
+	inb(RTC_PORT(1));	/* Clear any pending */
+
+	for (i = 0; i < SAMPLES; i++) {
+		iter[i] = rtc_wait_bit(tsc+i, range+i);
+		if (iter[i] <= 3)
+			break;
+		if (inb(RTC_PORT(1)) & RTC_PF)
+			break;
+	}
+
+	lock_cmos_suffix(RTC_REG_C);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
+	printk("** RTC timing\n");
+	for (j = 1; j < i; j++) {
+		printk("RTC edge delta %7u, range %6u, iter %u\n",
+			tsc[j] - tsc[j-1],  range[j], iter[j]);
+	}
+
+	/* Collect different statistics: per-read timing */
+	spin_lock_irqsave(&rtc_lock, flags);
+	lock_cmos_prefix(RTC_REG_C);
+	outb(RTC_REG_C, RTC_PORT(0));
+	inb(RTC_PORT(1));	/* Clear any pending */
+
+	/* Capture a series of timestamps straddling a bit change */
+	j = 10000;
+	for (i = 0; i < j; i++) {
+		tsc[i % (unsigned)SAMPLES] = (unsigned)get_cycles();
+		if (inb(RTC_PORT(1)) & RTC_PF && i >= SAMPLES/2 && j < 10000)
+			j = i + SAMPLES/2;
+	}
+
+	/* Restore the RTC state */
+	outb(RTC_REG_A, RTC_PORT(0));
+	outb(saved_a, RTC_PORT(1));
+	outb(RTC_REG_B, RTC_PORT(0));
+	outb(saved_b, RTC_PORT(1));
+
+	lock_cmos_suffix(RTC_REG_C);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
+	printk("** RTC timing details\n");
+	for (j = 1; j < SAMPLES; j++) {
+		unsigned k = i + j - SAMPLES;
+		printk("RTC sample %3d: %7u%s\n", k,
+			tsc[k % SAMPLES] - tsc[(k-1) % SAMPLES],
+			j == SAMPLES/2 ? " *" : "");
+	}
+}
+
 /*
  * How many MSB values do we want to see? We aim for
  * a maximum error rate of 500ppm (in practice the
@@ -570,6 +743,8 @@ static unsigned long quick_pit_calibrate(void)
 	/* Set the Gate high, disable speaker */
 	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
 
+pit_test();
+
 	/*
 	 * Counter 2, mode 0 (one-shot), binary count
 	 *

  reply	other threads:[~2015-06-05 20:17 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-03  6:27 [PATCH RFC] x86, tsc: Allow for high latency in quick_pit_calibrate() George Spelvin
2015-06-03 18:29 ` George Spelvin
2015-06-03 18:48   ` H. Peter Anvin
2015-06-03 19:07     ` George Spelvin
2015-06-04 16:38       ` George Spelvin
2015-06-04 16:52         ` Linus Torvalds
2015-06-04 17:54           ` George Spelvin
2015-06-04 18:07             ` Linus Torvalds
2015-06-05  5:52           ` George Spelvin
2015-06-05  6:16             ` Ingo Molnar
2015-06-05  5:58         ` Ingo Molnar
2015-06-05  8:24           ` George Spelvin
2015-06-05  8:31             ` Ingo Molnar
2015-06-05 20:17               ` George Spelvin [this message]
2015-06-06 21:50                 ` George Spelvin
2015-06-09  6:54                   ` [RFC PATCH] Make quick_pit_calibrate more robust George Spelvin
2015-06-09  9:13                     ` Adrian Hunter
2015-06-09  9:54                       ` George Spelvin
2015-06-10  7:08                       ` Discussion: quick_pit_calibrate is slow George Spelvin
2015-06-10  7:30                         ` Ingo Molnar
2015-06-10  8:47                           ` George Spelvin
2015-06-10  9:25                             ` Ingo Molnar
2015-06-10 15:43                               ` George Spelvin
2015-06-10 15:56                                 ` Arjan van de Ven
2015-06-10 16:27                                   ` George Spelvin
2015-06-10 18:38                                     ` George Spelvin
2015-06-10 19:30                                       ` Arjan van de Ven
2015-06-10 22:19                                         ` George Spelvin
2015-06-10  8:13                         ` Adrian Hunter
2015-06-10  8:55                           ` George Spelvin
2015-06-10  9:12                           ` Ingo Molnar
2015-06-10 16:11                             ` George Spelvin
2015-06-10  7:32                       ` Discussion: quick_pit_calibrate isn't quick George Spelvin
  -- strict thread matches above, loose matches on Subject: below --
2015-05-21  7:55 [PATCH RFC] x86, tsc: Allow for high latency in quick_pit_calibrate() Adrian Hunter
2015-06-01  7:57 ` Adrian Hunter
2015-06-02 13:58   ` Thomas Gleixner
2015-06-02 19:33 ` Thomas Gleixner
2015-06-02 19:41   ` Andy Lutomirski
2015-06-02 19:43     ` Andi Kleen
2015-06-02 19:58       ` Thomas Gleixner
2015-06-02 20:03         ` Andy Lutomirski
2015-06-02 20:20           ` Andi Kleen
2015-06-02 21:03             ` Thomas Gleixner
2015-06-02 23:38               ` Andi Kleen
2015-06-03  0:21                 ` Andy Lutomirski
2015-06-03  0:39                   ` Andi Kleen
2015-06-03  0:58                     ` Andy Lutomirski
2015-06-03  3:30                       ` Andi Kleen
2015-06-03  8:13                         ` Adrian Hunter
2015-06-03 13:45                           ` Linus Torvalds
2015-06-04 11:28                             ` Adrian Hunter
2015-06-03 16:23                           ` Thomas Gleixner
2015-06-22 11:21                             ` Adrian Hunter
2015-06-22 13:14                               ` Thomas Gleixner
2015-07-06  6:48                                 ` Adrian Hunter
2015-07-06  7:42                                   ` Thomas Gleixner
2015-06-22 14:12                               ` George Spelvin
2015-06-03  4:20   ` Linus Torvalds
2015-06-03  6:20     ` Ingo Molnar
2015-06-03 13:43       ` Linus Torvalds
2015-06-03 16:47         ` Thomas Gleixner
2015-06-03 17:04           ` Linus Torvalds
2015-06-03 17:50             ` H. Peter Anvin
2015-06-04 12:32               ` Ingo Molnar
2015-06-03 17:06           ` Ingo Molnar

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=20150605201739.20651.qmail@ns.horizon.com \
    --to=linux@horizon.com \
    --cc=adrian.hunter@intel.com \
    --cc=ak@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@amacapital.net \
    --cc=mingo@kernel.org \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.