• Dmitry Vyukov's avatar
    kasan: eliminate long stalls during quarantine reduction · 64abdcb2
    Dmitry Vyukov authored
    Currently we dedicate 1/32 of RAM for quarantine and then reduce it by
    1/4 of total quarantine size.  This can be a significant amount of
    memory.  For example, with 4GB of RAM total quarantine size is 128MB and
    it is reduced by 32MB at a time.  With 128GB of RAM total quarantine
    size is 4GB and it is reduced by 1GB.  This leads to several problems:
    
     - freeing 1GB can take tens of seconds, causes rcu stall warnings and
       just introduces unexpected long delays at random places
     - if kmalloc() is called under a mutex, other threads stall on that
       mutex while a thread reduces quarantine
     - threads wait on quarantine_lock while one thread grabs a large batch
       of objects to evict
     - we walk the uncached list of object to free twice which makes all of
       the above worse
     - when a thread frees objects, they are already not accounted against
       global_quarantine.bytes; as the result we can have quarantine_size
       bytes in quarantine + unbounded amount of memory in large batches in
       threads that are in process of freeing
    
    Reduce size of quarantine in smaller batches to reduce the delays.  The
    only reason to reduce it in batches is amortization of overheads, the
    new batch size of 1MB should be well enough to amortize spinlock
    lock/unlock and few function calls.
    
    Plus organize quarantine as a FIFO array of batches.  This allows to not
    walk the list in quarantine_reduce() under quarantine_lock, which in
    turn reduces contention and is just faster.
    
    This improves performance of heavy load (syzkaller fuzzing) by ~20% with
    4 CPUs and 32GB of RAM.  Also this eliminates frequent (every 5 sec)
    drops of CPU consumption from ~400% to ~100% (one thread reduces
    quarantine while others are waiting on a mutex).
    
    Some reference numbers:
    1. Machine with 4 CPUs and 4GB of memory. Quarantine size 128MB.
       Currently we free 32MB at at time.
       With new code we free 1MB at a time (1024 batches, ~128 are used).
    2. Machine with 32 CPUs and 128GB of memory. Quarantine size 4GB.
       Currently we free 1GB at at time.
       With new code we free 8MB at a time (1024 batches, ~512 are used).
    3. Machine with 4096 CPUs and 1TB of memory. Quarantine size 32GB.
       Currently we free 8GB at at time.
       With new code we free 4MB at a time (16K batches, ~8K are used).
    
    Link: http://lkml.kernel.org/r/1478756952-18695-1-git-send-email-dvyukov@google.comSigned-off-by: default avatarDmitry Vyukov <dvyukov@google.com>
    Cc: Eric Dumazet <edumazet@google.com>
    Cc: Greg Thelen <gthelen@google.com>
    Cc: Alexander Potapenko <glider@google.com>
    Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
    Cc: Andrey Konovalov <andreyknvl@google.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    64abdcb2
quarantine.c 7.18 KB