• Sergey Senozhatsky's avatar
    printk: introduce suppress_message_printing() · cf775444
    Sergey Senozhatsky authored
    Messages' levels and console log level are inspected when the actual
    printing occurs, which may provoke console_unlock() and
    console_cont_flush() to waste CPU cycles on every message that has
    loglevel above the current console_loglevel.
    
    Schematically, console_unlock() does the following:
    
    console_unlock()
    {
            ...
            for (;;) {
                    ...
                    raw_spin_lock_irqsave(&logbuf_lock, flags);
    skip:
                    msg = log_from_idx(console_idx);
    
                    if (msg->flags & LOG_NOCONS) {
                            ...
                            goto skip;
                    }
    
                    level = msg->level;
                    len += msg_print_text();                        >> sprintfs
                                                                       memcpy,
                                                                       etc.
    
                    if (nr_ext_console_drivers) {
                            ext_len = msg_print_ext_header();       >> scnprintf
                            ext_len += msg_print_ext_body();        >> scnprintfs
                                                                       etc.
                    }
                    ...
                    raw_spin_unlock(&logbuf_lock);
    
                    call_console_drivers(level, ext_text, ext_len, text, len)
                    {
                            if (level >= console_loglevel &&        >> drop the message
                                            !ignore_loglevel)
                                    return;
    
                            console->write(...);
                    }
    
                    local_irq_restore(flags);
            }
            ...
    }
    
    The thing here is this deferred `level >= console_loglevel' check.  We
    are wasting CPU cycles on sprintfs/memcpy/etc.  preparing the messages
    that we will eventually drop.
    
    This can be huge when we register a new CON_PRINTBUFFER console, for
    instance.  For every such a console register_console() resets the
    
            console_seq, console_idx, console_prev
    
    and sets a `exclusive console' pointer to replay the log buffer to that
    just-registered console.  And there can be a lot of messages to replay,
    in the worst case most of which can be dropped after console_loglevel
    test.
    
    We know messages' levels long before we call msg_print_text() and
    friends, so we can just move console_loglevel check out of
    call_console_drivers() and format a new message only if we are sure that
    it won't be dropped.
    
    The patch factors out loglevel check into suppress_message_printing()
    function and tests message->level and console_loglevel before formatting
    functions in console_unlock() and console_cont_flush() are getting
    executed.  This improves things not only for exclusive CON_PRINTBUFFER
    consoles, but for every console_unlock() that attempts to print a
    message of level above the console_loglevel.
    
    Link: http://lkml.kernel.org/r/20160627135012.8229-1-sergey.senozhatsky@gmail.comSigned-off-by: default avatarSergey Senozhatsky <sergey.senozhatsky@gmail.com>
    Reviewed-by: default avatarPetr Mladek <pmladek@suse.com>
    Cc: Tejun Heo <tj@kernel.org>
    Cc: Jan Kara <jack@suse.cz>
    Cc: Calvin Owens <calvinowens@fb.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    cf775444
printk.c 81.8 KB