LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 1/2] Add round_jiffies_up and related routines
@ 2008-11-04 16:15 Alan Stern
  2008-11-05  3:33 ` Tejun Heo
  0 siblings, 1 reply; 6+ messages in thread
From: Alan Stern @ 2008-11-04 16:15 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Tejun Heo, Kernel development list

This patch (as1158) adds round_jiffies_up() and friends.  These
routines work like the analogous round_jiffies() functions, except
that they will never round down.

The new routines will be useful for timeouts where we don't care
exactly when the timer expires, provided it doesn't expire too soon.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>

---

Jens:

This doesn't have anything to do with the block layer.  But the second
patch in this series does, and it uses round_jiffies_up().  Therefore I
thought it would be appropriate to submit this through you.

Alan Stern


Index: usb-2.6/include/linux/timer.h
===================================================================
--- usb-2.6.orig/include/linux/timer.h
+++ usb-2.6/include/linux/timer.h
@@ -186,4 +186,9 @@ unsigned long __round_jiffies_relative(u
 unsigned long round_jiffies(unsigned long j);
 unsigned long round_jiffies_relative(unsigned long j);
 
+unsigned long __round_jiffies_up(unsigned long j, int cpu);
+unsigned long __round_jiffies_up_relative(unsigned long j, int cpu);
+unsigned long round_jiffies_up(unsigned long j);
+unsigned long round_jiffies_up_relative(unsigned long j);
+
 #endif
Index: usb-2.6/kernel/timer.c
===================================================================
--- usb-2.6.orig/kernel/timer.c
+++ usb-2.6/kernel/timer.c
@@ -112,27 +112,8 @@ timer_set_base(struct timer_list *timer,
 				      tbase_get_deferrable(timer->base));
 }
 
-/**
- * __round_jiffies - function to round jiffies to a full second
- * @j: the time in (absolute) jiffies that should be rounded
- * @cpu: the processor number on which the timeout will happen
- *
- * __round_jiffies() rounds an absolute time in the future (in jiffies)
- * up or down to (approximately) full seconds. This is useful for timers
- * for which the exact time they fire does not matter too much, as long as
- * they fire approximately every X seconds.
- *
- * By rounding these timers to whole seconds, all such timers will fire
- * at the same time, rather than at various times spread out. The goal
- * of this is to have the CPU wake up less, which saves power.
- *
- * The exact rounding is skewed for each processor to avoid all
- * processors firing at the exact same time, which could lead
- * to lock contention or spurious cache line bouncing.
- *
- * The return value is the rounded version of the @j parameter.
- */
-unsigned long __round_jiffies(unsigned long j, int cpu)
+static unsigned long round_jiffies_common(unsigned long j, int cpu,
+		bool force_up)
 {
 	int rem;
 	unsigned long original = j;
@@ -154,8 +135,9 @@ unsigned long __round_jiffies(unsigned l
 	 * due to delays of the timer irq, long irq off times etc etc) then
 	 * we should round down to the whole second, not up. Use 1/4th second
 	 * as cutoff for this rounding as an extreme upper bound for this.
+	 * But never round down if @force_up is set.
 	 */
-	if (rem < HZ/4) /* round down */
+	if (rem < HZ/4 && !force_up) /* round down */
 		j = j - rem;
 	else /* round up */
 		j = j - rem + HZ;
@@ -167,6 +149,31 @@ unsigned long __round_jiffies(unsigned l
 		return original;
 	return j;
 }
+
+/**
+ * __round_jiffies - function to round jiffies to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ * @cpu: the processor number on which the timeout will happen
+ *
+ * __round_jiffies() rounds an absolute time in the future (in jiffies)
+ * up or down to (approximately) full seconds. This is useful for timers
+ * for which the exact time they fire does not matter too much, as long as
+ * they fire approximately every X seconds.
+ *
+ * By rounding these timers to whole seconds, all such timers will fire
+ * at the same time, rather than at various times spread out. The goal
+ * of this is to have the CPU wake up less, which saves power.
+ *
+ * The exact rounding is skewed for each processor to avoid all
+ * processors firing at the exact same time, which could lead
+ * to lock contention or spurious cache line bouncing.
+ *
+ * The return value is the rounded version of the @j parameter.
+ */
+unsigned long __round_jiffies(unsigned long j, int cpu)
+{
+	return round_jiffies_common(j, cpu, false);
+}
 EXPORT_SYMBOL_GPL(__round_jiffies);
 
 /**
@@ -191,13 +198,10 @@ EXPORT_SYMBOL_GPL(__round_jiffies);
  */
 unsigned long __round_jiffies_relative(unsigned long j, int cpu)
 {
-	/*
-	 * In theory the following code can skip a jiffy in case jiffies
-	 * increments right between the addition and the later subtraction.
-	 * However since the entire point of this function is to use approximate
-	 * timeouts, it's entirely ok to not handle that.
-	 */
-	return  __round_jiffies(j + jiffies, cpu) - jiffies;
+	unsigned long j0 = jiffies;
+
+	barrier();	/* Prevent the compiler from aliasing j0 and jiffies */
+	return round_jiffies_common(j + j0, cpu, false) - j0;
 }
 EXPORT_SYMBOL_GPL(__round_jiffies_relative);
 
@@ -218,7 +222,7 @@ EXPORT_SYMBOL_GPL(__round_jiffies_relati
  */
 unsigned long round_jiffies(unsigned long j)
 {
-	return __round_jiffies(j, raw_smp_processor_id());
+	return round_jiffies_common(j, raw_smp_processor_id(), false);
 }
 EXPORT_SYMBOL_GPL(round_jiffies);
 
@@ -243,6 +247,71 @@ unsigned long round_jiffies_relative(uns
 }
 EXPORT_SYMBOL_GPL(round_jiffies_relative);
 
+/**
+ * __round_jiffies_up - function to round jiffies up to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ * @cpu: the processor number on which the timeout will happen
+ *
+ * This is the same as __round_jiffies() except that it will never
+ * round down.  This is useful for timeouts for which the exact time
+ * of firing does not matter too much, as long as they don't fire too
+ * early.
+ */
+unsigned long __round_jiffies_up(unsigned long j, int cpu)
+{
+	return round_jiffies_common(j, cpu, true);
+}
+EXPORT_SYMBOL_GPL(__round_jiffies_up);
+
+/**
+ * __round_jiffies_up_relative - function to round jiffies up to a full second
+ * @j: the time in (relative) jiffies that should be rounded
+ * @cpu: the processor number on which the timeout will happen
+ *
+ * This is the same as __round_jiffies_relative() except that it will never
+ * round down.  This is useful for timeouts for which the exact time
+ * of firing does not matter too much, as long as they don't fire too
+ * early.
+ */
+unsigned long __round_jiffies_up_relative(unsigned long j, int cpu)
+{
+	unsigned long j0 = jiffies;
+
+	barrier();	/* Prevent the compiler from aliasing j0 and jiffies */
+	return round_jiffies_common(j + j0, cpu, true) - j0;
+}
+EXPORT_SYMBOL_GPL(__round_jiffies_up_relative);
+
+/**
+ * round_jiffies_up - function to round jiffies up to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ *
+ * This is the same as round_jiffies() except that it will never
+ * round down.  This is useful for timeouts for which the exact time
+ * of firing does not matter too much, as long as they don't fire too
+ * early.
+ */
+unsigned long round_jiffies_up(unsigned long j)
+{
+	return round_jiffies_common(j, raw_smp_processor_id(), true);
+}
+EXPORT_SYMBOL_GPL(round_jiffies_up);
+
+/**
+ * round_jiffies_up_relative - function to round jiffies up to a full second
+ * @j: the time in (relative) jiffies that should be rounded
+ *
+ * This is the same as round_jiffies_relative() except that it will never
+ * round down.  This is useful for timeouts for which the exact time
+ * of firing does not matter too much, as long as they don't fire too
+ * early.
+ */
+unsigned long round_jiffies_up_relative(unsigned long j)
+{
+	return __round_jiffies_up_relative(j, raw_smp_processor_id());
+}
+EXPORT_SYMBOL_GPL(round_jiffies_up_relative);
+
 
 static inline void set_running_timer(struct tvec_base *base,
 					struct timer_list *timer)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] Add round_jiffies_up and related routines
  2008-11-04 16:15 [PATCH 1/2] Add round_jiffies_up and related routines Alan Stern
@ 2008-11-05  3:33 ` Tejun Heo
  2008-11-05 16:20   ` Alan Stern
  0 siblings, 1 reply; 6+ messages in thread
From: Tejun Heo @ 2008-11-05  3:33 UTC (permalink / raw)
  To: Alan Stern; +Cc: Jens Axboe, Kernel development list

Alan Stern wrote:
> This patch (as1158) adds round_jiffies_up() and friends.  These
> routines work like the analogous round_jiffies() functions, except
> that they will never round down.
> 
> The new routines will be useful for timeouts where we don't care
> exactly when the timer expires, provided it doesn't expire too soon.
> 
> Signed-off-by: Alan Stern <stern@rowland.harvard.edu>

Heh... I have exactly the same patches but mines were named
round_up_jiffies().

> +	unsigned long j0 = jiffies;
> +
> +	barrier();	/* Prevent the compiler from aliasing j0 and jiffies */
> +	return round_jiffies_common(j + j0, cpu, false) - j0;

jiffies is volatile.  No need for explicit barrier, but this part is
necessary for correct operation as if jiffies go up by two the
calculation will wrap and the returned value will be very large.  I
think this fix deserves a separate patch and proper explanation.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] Add round_jiffies_up and related routines
  2008-11-05  3:33 ` Tejun Heo
@ 2008-11-05 16:20   ` Alan Stern
  2008-11-05 19:11     ` Jens Axboe
  0 siblings, 1 reply; 6+ messages in thread
From: Alan Stern @ 2008-11-05 16:20 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Jens Axboe, Kernel development list

On Wed, 5 Nov 2008, Tejun Heo wrote:

> Alan Stern wrote:
> > This patch (as1158) adds round_jiffies_up() and friends.  These
> > routines work like the analogous round_jiffies() functions, except
> > that they will never round down.
> > 
> > The new routines will be useful for timeouts where we don't care
> > exactly when the timer expires, provided it doesn't expire too soon.
> > 
> > Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
> 
> Heh... I have exactly the same patches but mines were named
> round_up_jiffies().

To an American, "round_up_jiffies" sounds like something a cowboy might 
do.  :-)

I haven't bothered to look throughout the kernel to see where 
round_jiffies_up() could be used.  Have you done this?

> > +	unsigned long j0 = jiffies;
> > +
> > +	barrier();	/* Prevent the compiler from aliasing j0 and jiffies */
> > +	return round_jiffies_common(j + j0, cpu, false) - j0;
> 
> jiffies is volatile.  No need for explicit barrier,

I didn't realize that.  Good, it makes things easier.

> but this part is
> necessary for correct operation as if jiffies go up by two the
> calculation will wrap and the returned value will be very large.  I
> think this fix deserves a separate patch and proper explanation.

How about if I remove the barrier() call?  Should this new code still
go in a separate patch?

Alan Stern


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] Add round_jiffies_up and related routines
  2008-11-05 16:20   ` Alan Stern
@ 2008-11-05 19:11     ` Jens Axboe
  2008-11-05 21:18       ` [PATCH 1/2 ver 2] " Alan Stern
  0 siblings, 1 reply; 6+ messages in thread
From: Jens Axboe @ 2008-11-05 19:11 UTC (permalink / raw)
  To: Alan Stern; +Cc: Tejun Heo, Kernel development list

On Wed, Nov 05 2008, Alan Stern wrote:
> On Wed, 5 Nov 2008, Tejun Heo wrote:
> 
> > Alan Stern wrote:
> > > This patch (as1158) adds round_jiffies_up() and friends.  These
> > > routines work like the analogous round_jiffies() functions, except
> > > that they will never round down.
> > > 
> > > The new routines will be useful for timeouts where we don't care
> > > exactly when the timer expires, provided it doesn't expire too soon.
> > > 
> > > Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
> > 
> > Heh... I have exactly the same patches but mines were named
> > round_up_jiffies().
> 
> To an American, "round_up_jiffies" sounds like something a cowboy might 
> do.  :-)
> 
> I haven't bothered to look throughout the kernel to see where 
> round_jiffies_up() could be used.  Have you done this?

Heh, I do agree :-)

> > > +	unsigned long j0 = jiffies;
> > > +
> > > +	barrier();	/* Prevent the compiler from aliasing j0 and jiffies */
> > > +	return round_jiffies_common(j + j0, cpu, false) - j0;
> > 
> > jiffies is volatile.  No need for explicit barrier,
> 
> I didn't realize that.  Good, it makes things easier.
> 
> > but this part is
> > necessary for correct operation as if jiffies go up by two the
> > calculation will wrap and the returned value will be very large.  I
> > think this fix deserves a separate patch and proper explanation.
> 
> How about if I remove the barrier() call?  Should this new code still
> go in a separate patch?

I think it's fine as-is without the barrier. Can you resend it as such,
makes it easier to merge up (plus, it does need a new signed-off-by).

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2 ver 2] Add round_jiffies_up and related routines
  2008-11-05 19:11     ` Jens Axboe
@ 2008-11-05 21:18       ` Alan Stern
  2008-11-06  7:42         ` Jens Axboe
  0 siblings, 1 reply; 6+ messages in thread
From: Alan Stern @ 2008-11-05 21:18 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Tejun Heo, Kernel development list

This patch (as1158b) adds round_jiffies_up() and friends.  These
routines work like the analogous round_jiffies() functions, except
that they will never round down.

The new routines will be useful for timeouts where we don't care
exactly when the timer expires, provided it doesn't expire too soon.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>

---

No barriers this time.


Index: usb-2.6/include/linux/timer.h
===================================================================
--- usb-2.6.orig/include/linux/timer.h
+++ usb-2.6/include/linux/timer.h
@@ -186,4 +186,9 @@ unsigned long __round_jiffies_relative(u
 unsigned long round_jiffies(unsigned long j);
 unsigned long round_jiffies_relative(unsigned long j);
 
+unsigned long __round_jiffies_up(unsigned long j, int cpu);
+unsigned long __round_jiffies_up_relative(unsigned long j, int cpu);
+unsigned long round_jiffies_up(unsigned long j);
+unsigned long round_jiffies_up_relative(unsigned long j);
+
 #endif
Index: usb-2.6/kernel/timer.c
===================================================================
--- usb-2.6.orig/kernel/timer.c
+++ usb-2.6/kernel/timer.c
@@ -112,27 +112,8 @@ timer_set_base(struct timer_list *timer,
 				      tbase_get_deferrable(timer->base));
 }
 
-/**
- * __round_jiffies - function to round jiffies to a full second
- * @j: the time in (absolute) jiffies that should be rounded
- * @cpu: the processor number on which the timeout will happen
- *
- * __round_jiffies() rounds an absolute time in the future (in jiffies)
- * up or down to (approximately) full seconds. This is useful for timers
- * for which the exact time they fire does not matter too much, as long as
- * they fire approximately every X seconds.
- *
- * By rounding these timers to whole seconds, all such timers will fire
- * at the same time, rather than at various times spread out. The goal
- * of this is to have the CPU wake up less, which saves power.
- *
- * The exact rounding is skewed for each processor to avoid all
- * processors firing at the exact same time, which could lead
- * to lock contention or spurious cache line bouncing.
- *
- * The return value is the rounded version of the @j parameter.
- */
-unsigned long __round_jiffies(unsigned long j, int cpu)
+static unsigned long round_jiffies_common(unsigned long j, int cpu,
+		bool force_up)
 {
 	int rem;
 	unsigned long original = j;
@@ -154,8 +135,9 @@ unsigned long __round_jiffies(unsigned l
 	 * due to delays of the timer irq, long irq off times etc etc) then
 	 * we should round down to the whole second, not up. Use 1/4th second
 	 * as cutoff for this rounding as an extreme upper bound for this.
+	 * But never round down if @force_up is set.
 	 */
-	if (rem < HZ/4) /* round down */
+	if (rem < HZ/4 && !force_up) /* round down */
 		j = j - rem;
 	else /* round up */
 		j = j - rem + HZ;
@@ -167,6 +149,31 @@ unsigned long __round_jiffies(unsigned l
 		return original;
 	return j;
 }
+
+/**
+ * __round_jiffies - function to round jiffies to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ * @cpu: the processor number on which the timeout will happen
+ *
+ * __round_jiffies() rounds an absolute time in the future (in jiffies)
+ * up or down to (approximately) full seconds. This is useful for timers
+ * for which the exact time they fire does not matter too much, as long as
+ * they fire approximately every X seconds.
+ *
+ * By rounding these timers to whole seconds, all such timers will fire
+ * at the same time, rather than at various times spread out. The goal
+ * of this is to have the CPU wake up less, which saves power.
+ *
+ * The exact rounding is skewed for each processor to avoid all
+ * processors firing at the exact same time, which could lead
+ * to lock contention or spurious cache line bouncing.
+ *
+ * The return value is the rounded version of the @j parameter.
+ */
+unsigned long __round_jiffies(unsigned long j, int cpu)
+{
+	return round_jiffies_common(j, cpu, false);
+}
 EXPORT_SYMBOL_GPL(__round_jiffies);
 
 /**
@@ -191,13 +198,10 @@ EXPORT_SYMBOL_GPL(__round_jiffies);
  */
 unsigned long __round_jiffies_relative(unsigned long j, int cpu)
 {
-	/*
-	 * In theory the following code can skip a jiffy in case jiffies
-	 * increments right between the addition and the later subtraction.
-	 * However since the entire point of this function is to use approximate
-	 * timeouts, it's entirely ok to not handle that.
-	 */
-	return  __round_jiffies(j + jiffies, cpu) - jiffies;
+	unsigned long j0 = jiffies;
+
+	/* Use j0 because jiffies might change while we run */
+	return round_jiffies_common(j + j0, cpu, false) - j0;
 }
 EXPORT_SYMBOL_GPL(__round_jiffies_relative);
 
@@ -218,7 +222,7 @@ EXPORT_SYMBOL_GPL(__round_jiffies_relati
  */
 unsigned long round_jiffies(unsigned long j)
 {
-	return __round_jiffies(j, raw_smp_processor_id());
+	return round_jiffies_common(j, raw_smp_processor_id(), false);
 }
 EXPORT_SYMBOL_GPL(round_jiffies);
 
@@ -243,6 +247,71 @@ unsigned long round_jiffies_relative(uns
 }
 EXPORT_SYMBOL_GPL(round_jiffies_relative);
 
+/**
+ * __round_jiffies_up - function to round jiffies up to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ * @cpu: the processor number on which the timeout will happen
+ *
+ * This is the same as __round_jiffies() except that it will never
+ * round down.  This is useful for timeouts for which the exact time
+ * of firing does not matter too much, as long as they don't fire too
+ * early.
+ */
+unsigned long __round_jiffies_up(unsigned long j, int cpu)
+{
+	return round_jiffies_common(j, cpu, true);
+}
+EXPORT_SYMBOL_GPL(__round_jiffies_up);
+
+/**
+ * __round_jiffies_up_relative - function to round jiffies up to a full second
+ * @j: the time in (relative) jiffies that should be rounded
+ * @cpu: the processor number on which the timeout will happen
+ *
+ * This is the same as __round_jiffies_relative() except that it will never
+ * round down.  This is useful for timeouts for which the exact time
+ * of firing does not matter too much, as long as they don't fire too
+ * early.
+ */
+unsigned long __round_jiffies_up_relative(unsigned long j, int cpu)
+{
+	unsigned long j0 = jiffies;
+
+	/* Use j0 because jiffies might change while we run */
+	return round_jiffies_common(j + j0, cpu, true) - j0;
+}
+EXPORT_SYMBOL_GPL(__round_jiffies_up_relative);
+
+/**
+ * round_jiffies_up - function to round jiffies up to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ *
+ * This is the same as round_jiffies() except that it will never
+ * round down.  This is useful for timeouts for which the exact time
+ * of firing does not matter too much, as long as they don't fire too
+ * early.
+ */
+unsigned long round_jiffies_up(unsigned long j)
+{
+	return round_jiffies_common(j, raw_smp_processor_id(), true);
+}
+EXPORT_SYMBOL_GPL(round_jiffies_up);
+
+/**
+ * round_jiffies_up_relative - function to round jiffies up to a full second
+ * @j: the time in (relative) jiffies that should be rounded
+ *
+ * This is the same as round_jiffies_relative() except that it will never
+ * round down.  This is useful for timeouts for which the exact time
+ * of firing does not matter too much, as long as they don't fire too
+ * early.
+ */
+unsigned long round_jiffies_up_relative(unsigned long j)
+{
+	return __round_jiffies_up_relative(j, raw_smp_processor_id());
+}
+EXPORT_SYMBOL_GPL(round_jiffies_up_relative);
+
 
 static inline void set_running_timer(struct tvec_base *base,
 					struct timer_list *timer)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2 ver 2] Add round_jiffies_up and related routines
  2008-11-05 21:18       ` [PATCH 1/2 ver 2] " Alan Stern
@ 2008-11-06  7:42         ` Jens Axboe
  0 siblings, 0 replies; 6+ messages in thread
From: Jens Axboe @ 2008-11-06  7:42 UTC (permalink / raw)
  To: Alan Stern; +Cc: Tejun Heo, Kernel development list

On Wed, Nov 05 2008, Alan Stern wrote:
> This patch (as1158b) adds round_jiffies_up() and friends.  These
> routines work like the analogous round_jiffies() functions, except
> that they will never round down.
> 
> The new routines will be useful for timeouts where we don't care
> exactly when the timer expires, provided it doesn't expire too soon.

Thanks Alan, applied 1-2 for 2.6.28.

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2008-11-06  7:44 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-11-04 16:15 [PATCH 1/2] Add round_jiffies_up and related routines Alan Stern
2008-11-05  3:33 ` Tejun Heo
2008-11-05 16:20   ` Alan Stern
2008-11-05 19:11     ` Jens Axboe
2008-11-05 21:18       ` [PATCH 1/2 ver 2] " Alan Stern
2008-11-06  7:42         ` Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).