• Scott Cheloha's avatar
    drivers/base/memory.c: cache memory blocks in xarray to accelerate lookup · 4fb6eabf
    Scott Cheloha authored
    Searching for a particular memory block by id is an O(n) operation because
    each memory block's underlying device is kept in an unsorted linked list
    on the subsystem bus.
    
    We can cut the lookup cost to O(log n) if we cache each memory block
    in an xarray.  This time complexity improvement is significant on
    systems with many memory blocks.  For example:
    
    1. A 128GB POWER9 VM with 256MB memblocks has 512 blocks.  With this
       change  memory_dev_init() completes ~12ms faster and walk_memory_blocks()
       completes ~12ms faster.
    
    Before:
    [    0.005042] memory_dev_init: adding memory blocks
    [    0.021591] memory_dev_init: added memory blocks
    [    0.022699] walk_memory_blocks: walking memory blocks
    [    0.038730] walk_memory_blocks: walked memory blocks 0-511
    
    After:
    [    0.005057] memory_dev_init: adding memory blocks
    [    0.009415] memory_dev_init: added memory blocks
    [    0.010519] walk_memory_blocks: walking memory blocks
    [    0.014135] walk_memory_blocks: walked memory blocks 0-511
    
    2. A 256GB POWER9 LPAR with 256MB memblocks has 1024 blocks.  With
       this change memory_dev_init() completes ~88ms faster and
       walk_memory_blocks() completes ~87ms faster.
    
    Before:
    [    0.252246] memory_dev_init: adding memory blocks
    [    0.395469] memory_dev_init: added memory blocks
    [    0.409413] walk_memory_blocks: walking memory blocks
    [    0.433028] walk_memory_blocks: walked memory blocks 0-511
    [    0.433094] walk_memory_blocks: walking memory blocks
    [    0.500244] walk_memory_blocks: walked memory blocks 131072-131583
    
    After:
    [    0.245063] memory_dev_init: adding memory blocks
    [    0.299539] memory_dev_init: added memory blocks
    [    0.313609] walk_memory_blocks: walking memory blocks
    [    0.315287] walk_memory_blocks: walked memory blocks 0-511
    [    0.315349] walk_memory_blocks: walking memory blocks
    [    0.316988] walk_memory_blocks: walked memory blocks 131072-131583
    
    3. A 32TB POWER9 LPAR with 256MB memblocks has 131072 blocks.  With
       this change we complete memory_dev_init() ~37 minutes faster and
       walk_memory_blocks() at least ~30 minutes faster.  The exact timing
       for walk_memory_blocks() is  missing, though I observed that the
       soft lockups in walk_memory_blocks() disappeared with the change,
       suggesting that lower bound.
    
    Before:
    [   13.703907] memory_dev_init: adding blocks
    [ 2287.406099] memory_dev_init: added all blocks
    [ 2347.494986] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    [ 2527.625378] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    [ 2707.761977] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    [ 2887.899975] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    [ 3068.028318] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    [ 3248.158764] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    [ 3428.287296] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    [ 3608.425357] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    [ 3788.554572] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    [ 3968.695071] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    [ 4148.823970] [c000000014c5bb60] [c000000000869af4] walk_memory_blocks+0x94/0x160
    
    After:
    [   13.696898] memory_dev_init: adding blocks
    [   15.660035] memory_dev_init: added all blocks
    (the walk_memory_blocks traces disappear)
    
    There should be no significant negative impact for machines with few
    memory blocks.  A sparse xarray has a small footprint and an O(log n)
    lookup is negligibly slower than an O(n) lookup for only the smallest
    number of memory blocks.
    
    1. A 16GB x86 machine with 128MB memblocks has 132 blocks.  With this
       change memory_dev_init() completes ~300us faster and walk_memory_blocks()
       completes no faster or slower.  The improvement is pretty close to noise.
    
    Before:
    [    0.224752] memory_dev_init: adding memory blocks
    [    0.227116] memory_dev_init: added memory blocks
    [    0.227183] walk_memory_blocks: walking memory blocks
    [    0.227183] walk_memory_blocks: walked memory blocks 0-131
    
    After:
    [    0.224911] memory_dev_init: adding memory blocks
    [    0.226935] memory_dev_init: added memory blocks
    [    0.227089] walk_memory_blocks: walking memory blocks
    [    0.227089] walk_memory_blocks: walked memory blocks 0-131
    
    [david@redhat.com: document the locking]
      Link: http://lkml.kernel.org/r/bc21eec6-7251-4c91-2f57-9a0671f8d414@redhat.comSigned-off-by: default avatarScott Cheloha <cheloha@linux.ibm.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Acked-by: default avatarDavid Hildenbrand <david@redhat.com>
    Acked-by: default avatarNathan Lynch <nathanl@linux.ibm.com>
    Acked-by: default avatarMichal Hocko <mhocko@suse.com>
    Cc: Rafael J. Wysocki <rafael@kernel.org>
    Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Cc: Rick Lindsley <ricklind@linux.vnet.ibm.com>
    Cc: Scott Cheloha <cheloha@linux.ibm.com>
    Link: http://lkml.kernel.org/r/20200121231028.13699-1-cheloha@linux.ibm.comSigned-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    4fb6eabf
memory.c 20.3 KB