• Andrew Morton's avatar
    [PATCH] prepare_to_wait/finish_wait sleep/wakeup API · 3da08d6c
    Andrew Morton authored
    This is worth a whopping 2% on spwecweb on an 8-way.  Which is faintly
    surprising because __wake_up and other wait/wakeup functions are not
    apparent in the specweb profiles which I've seen.
    
    
    The main objective of this is to reduce the CPU cost of the wait/wakeup
    operation.  When a task is woken up, its waitqueue is removed from the
    waitqueue_head by the waker (ie: immediately), rather than by the woken
    process.
    
    This means that a subsequent wakeup does not need to revisit the
    just-woken task.  It also means that the just-woken task does not need
    to take the waitqueue_head's lock, which may well reside in another
    CPU's cache.
    
    I have no decent measurements on the effect of this change - possibly a
    20-30% drop in __wake_up cost in Badari's 40-dds-to-40-disks test (it
    was the most expensive function), but it's inconclusive.  And no
    quantitative testing of which I am aware has been performed by
    networking people.
    
    The API is very simple to use (Linus thought it up):
    
    my_func(waitqueue_head_t *wqh)
    {
    	DEFINE_WAIT(wait);
    
    	prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
    	if (!some_test)
    		schedule();
    	finish_wait(wqh, &wait);
    }
    
    or:
    
    	DEFINE_WAIT(wait);
    
    	while (!some_test_1) {
    		prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
    		if (!some_test_2)
    			schedule();
    		...
    	}
    	finish_wait(wqh, &wait);
    
    You need to bear in mind that once prepare_to_wait has been performed,
    your task could be removed from the waitqueue_head and placed into
    TASK_RUNNING at any time.  You don't know whether or not you're still
    on the waitqueue_head.
    
    Running prepare_to_wait() when you're already on the waitqueue_head is
    fine - it will do the right thing.
    
    Running finish_wait() when you're actually not on the waitqueue_head is
    fine.
    
    Running finish_wait() when you've _never_ been on the waitqueue_head is
    fine, as ling as the DEFINE_WAIT() macro was used to initialise the
    waitqueue.
    
    You don't need to fiddle with current->state.  prepare_to_wait() and
    finish_wait() will do that.  finish_wait() will always return in state
    TASK_RUNNING.
    
    There are plenty of usage examples in vm-wakeups.patch and
    tcp-wakeups.patch.
    3da08d6c
fork.c 24.5 KB