Commit 1b9407d7 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Add del_single_shot_timer()

From: Geoff Gustafson <geoff@linux.jf.intel.com>,
      "Chen, Kenneth W" <kenneth.w.chen@intel.com>,
      Ingo Molnar <mingo@elte.hu>,
      me.

The big-SMP guys are seeing high CPU load due to del_timer_sync()'s
inefficiencies.  The callers are fs/aio.c and schedule_timeout().

We note that neither of these callers' timer handlers actually re-add the
timer - they are single-shot.

So we don't need all that complexity in del_timer_sync() - we can just run
del_timer() and if that worked we know the timer is dead.

Add del_single_shot_timer(), export it to modules and use it in AIO and
schedule_timeout().


(these numbers are for an earlier patch, but they'll be close)

Before:             32p     4p
     Warm cache   29,000    505
     Cold cache   37,800   1220

After:              32p     4p
     Warm cache       95     88
     Cold cache    1,800    140

[Measurements are CPU cycles spent in a call to del_timer_sync, the average
of 1000 calls. 32p is 16-node NUMA, 4p is SMP.]

(I cleaned up a few things and added some commentary)
parent 496dc9b4
......@@ -793,7 +793,7 @@ static inline void set_timeout(long start_jiffies, struct timeout *to,
static inline void clear_timeout(struct timeout *to)
{
del_timer_sync(&to->timer);
del_singleshot_timer_sync(&to->timer);
}
static int read_events(struct kioctx *ctx,
......
......@@ -87,9 +87,11 @@ static inline void add_timer(struct timer_list * timer)
}
#ifdef CONFIG_SMP
extern int del_timer_sync(struct timer_list * timer);
extern int del_timer_sync(struct timer_list *timer);
extern int del_singleshot_timer_sync(struct timer_list *timer);
#else
# define del_timer_sync(t) del_timer(t)
# define del_singleshot_timer_sync(t) del_timer(t)
#endif
extern void init_timers(void);
......
......@@ -317,10 +317,16 @@ EXPORT_SYMBOL(del_timer);
*
* Synchronization rules: callers must prevent restarting of the timer,
* otherwise this function is meaningless. It must not be called from
* interrupt contexts. Upon exit the timer is not queued and the handler
* is not running on any CPU.
* interrupt contexts. The caller must not hold locks which would prevent
* completion of the timer's handler. Upon exit the timer is not queued and
* the handler is not running on any CPU.
*
* The function returns whether it has deactivated a pending timer or not.
*
* del_timer_sync() is slow and complicated because it copes with timer
* handlers which re-arm the timer (periodic timers). If the timer handler
* is known to not do this (a single shot timer) then use
* del_singleshot_timer_sync() instead.
*/
int del_timer_sync(struct timer_list *timer)
{
......@@ -348,8 +354,36 @@ int del_timer_sync(struct timer_list *timer)
return ret;
}
EXPORT_SYMBOL(del_timer_sync);
/***
* del_singleshot_timer_sync - deactivate a non-recursive timer
* @timer: the timer to be deactivated
*
* This function is an optimization of del_timer_sync for the case where the
* caller can guarantee the timer does not reschedule itself in its timer
* function.
*
* Synchronization rules: callers must prevent restarting of the timer,
* otherwise this function is meaningless. It must not be called from
* interrupt contexts. The caller must not hold locks which wold prevent
* completion of the timer's handler. Upon exit the timer is not queued and
* the handler is not running on any CPU.
*
* The function returns whether it has deactivated a pending timer or not.
*/
int del_singleshot_timer_sync(struct timer_list *timer)
{
int ret = del_timer(timer);
if (!ret) {
ret = del_timer_sync(timer);
BUG_ON(ret);
}
return ret;
}
EXPORT_SYMBOL(del_singleshot_timer_sync);
#endif
static int cascade(tvec_base_t *base, tvec_t *tv, int index)
......@@ -1109,7 +1143,7 @@ fastcall signed long __sched schedule_timeout(signed long timeout)
add_timer(&timer);
schedule();
del_timer_sync(&timer);
del_singleshot_timer_sync(&timer);
timeout = expire - jiffies;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment