cpufreq Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Dominik Brodowski <linux@dominikbrodowski.de>
To: cpufreq@www.linux.org.uk, johnstul@us.ibm.com
Subject: give the TSC a fair chance [Was: [PATCHES] cpufreq_get(), cpufreq->get()]
Date: Mon, 12 Apr 2004 14:04:22 +0200	[thread overview]
Message-ID: <20040412120422.GA7337@dominikbrodowski.de> (raw)
In-Reply-To: <20040411215912.GA8160@dominikbrodowski.de>

Dear John, 

Based on a patchset I submitted to the cpufreq list yesterday [description
and patches: http://www.brodo.de/patches/2004-04-11/00-announcement ]
I'd like to discuss the following patch:

If many lost ticks are detected, a call to "cpufreq_get()" for each online
CPU is scheduled as "work" for the "event" thread. This needs to be delayed
as cpufreq_get() may sleep. Inside cpufreq_get(), the cpufreq core tries to
determine the actual (hardware) CPU frequency, and if it differs from the
state the CPU was last set to, it will adjust to this inconsistency by
calling cpufreq notifiers. This means that the relevant frequency-affected
"constants" in timer_tsc.c will be updated, and no more lost ticks should
occur.

I've just verified that this patch does what it intends to, removing and
inserting the AC plug caused these messages in dmesg:
Warning: CPU frequency out of sync: cpufreq and timing core thinks of 1400000, is 600000 kHz.
Warning: CPU frequency out of sync: cpufreq and timing core thinks of 600000, is 1400000 kHz.

Please note that this patchset only will function on SMP as the cpufreq
workqueue interface was designed so well: even though the "kevent" thread
runs normally on one CPU, the actual work can be moved to other CPUs by
set_cpus_allowed(); one kevent "worker" can schedule additional work.

However, this patch has one slight chance for a bug: if lost_count reaches
50, a call to handle_cpufreq_delayed_work is scheduled, but does not execute
until lost_count reaches 50 again [e.g. when no lost ticks are
detected at the next call, but on the next 50 consecutive calls...]. As
keventd runs at -10 priority I doubt this will happen under normal
circumstances, though.

diff -ruN linux-original/arch/i386/kernel/timers/timer_tsc.c linux/arch/i386/kernel/timers/timer_tsc.c
--- linux-original/arch/i386/kernel/timers/timer_tsc.c	2004-04-12 13:38:59.541593040 +0200
+++ linux/arch/i386/kernel/timers/timer_tsc.c	2004-04-12 10:54:15.000000000 +0200
@@ -27,6 +27,8 @@
 struct timer_opts timer_tsc;
 #endif
 
+static inline void cpufreq_delayed_get(void);
+
 int tsc_disable __initdata = 0;
 
 extern spinlock_t i8253_lock;
@@ -241,6 +243,9 @@
 
 			clock_fallback();
 		}
+		/* ... but give it a fair chance to compensate for BIOS cpu frequency transitions */
+		if (lost_count == 50)
+			cpufreq_delayed_get();
 	} else
 		lost_count = 0;
 	/* update the monotonic base value */
@@ -324,6 +329,29 @@
 
 
 #ifdef CONFIG_CPU_FREQ
+#include <linux/workqueue.h>
+
+static unsigned int cpufreq_init = 0;
+static struct work_struct cpufreq_delayed_get_work;
+
+static void handle_cpufreq_delayed_get(void *v)
+{
+	unsigned int cpu;
+	for_each_online_cpu(cpu) {
+		cpufreq_get(cpu);
+	}
+}
+
+/* if we notice lost ticks, schedule a call to cpufreq_get() as it tries
+ * to verify the CPU frequency the timing core thinks the CPU is running
+ * at is still correct.
+ */
+static inline void cpufreq_delayed_get(void) 
+{
+	if (cpufreq_init)
+		schedule_work(&cpufreq_delayed_get_work);
+}
+
 /* If the CPU frequency is scaled, TSC-based delays will need a different
  * loops_per_jiffy value to function properly. An exception to this
  * are modern Intel Pentium 4 processors, where the TSC runs at a constant
@@ -383,6 +411,8 @@
 
 static int __init cpufreq_tsc(void)
 {
+	INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL);
+	cpufreq_init = 1;
 	/* P4 and above CPU TSC freq doesn't change when CPU frequency changes*/
 	if ((boot_cpu_data.x86 >= 15) && (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL))
 		variable_tsc = 0;
@@ -391,6 +421,8 @@
 }
 core_initcall(cpufreq_tsc);
 
+#else /* CONFIG_CPU_FREQ */
+static inline void cpufreq_delayed_get(void) { return; }
 #endif 

  parent reply	other threads:[~2004-04-12 12:04 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-04-11 21:59 [PATCHES] cpufreq_get(), cpufreq->get() Dominik Brodowski
2004-04-11 22:00 ` patch-02 [Re: [PATCHES] cpufreq_get(), cpufreq->get()] Dominik Brodowski
2004-04-11 22:00 ` patch-04 " Dominik Brodowski
2004-04-11 22:00 ` patch-05 " Dominik Brodowski
2004-04-11 22:01 ` patch-06 " Dominik Brodowski
2004-04-12 12:04 ` Dominik Brodowski [this message]
2004-04-14 18:24   ` give the TSC a fair chance [Was: " john stultz
2004-04-14 18:54     ` Dominik Brodowski
2004-04-14 20:03       ` john stultz
2004-04-14 20:57         ` Dominik Brodowski
2004-04-14 21:24           ` john stultz
2004-04-19 15:32             ` Dominik Brodowski
2004-04-14 10:52 ` [PATCHES] cpufreq_get(), cpufreq->get() Dave Jones

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=20040412120422.GA7337@dominikbrodowski.de \
    --to=linux@dominikbrodowski.de \
    --cc=cpufreq@www.linux.org.uk \
    --cc=johnstul@us.ibm.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