• Qu Wenruo's avatar
    btrfs: backref: Fix soft lockup in __merge_refs function · d8422ba3
    Qu Wenruo authored
    When over 1000 file extents refers to one extent, find_parent_nodes()
    will be obviously slow, due to the O(n^2)~O(n^3) loops inside
    __merge_refs().
    
    The following ftrace shows the cubic growth of execution time:
    
    256 refs
     5) + 91.768 us   |  __add_keyed_refs.isra.12 [btrfs]();
     5)   1.447 us    |  __add_missing_keys.isra.13 [btrfs]();
     5) ! 114.544 us  |  __merge_refs [btrfs]();
     5) ! 136.399 us  |  __merge_refs [btrfs]();
    
    512 refs
     6) ! 279.859 us  |  __add_keyed_refs.isra.12 [btrfs]();
     6)   3.164 us    |  __add_missing_keys.isra.13 [btrfs]();
     6) ! 442.498 us  |  __merge_refs [btrfs]();
     6) # 2091.073 us |  __merge_refs [btrfs]();
    
    and 1024 refs
     7) ! 368.683 us  |  __add_keyed_refs.isra.12 [btrfs]();
     7)   4.810 us    |  __add_missing_keys.isra.13 [btrfs]();
     7) # 2043.428 us |  __merge_refs [btrfs]();
     7) * 18964.23 us |  __merge_refs [btrfs]();
    
    And sort them into the following char:
    (Unit: us)
    ------------------------------------------------------------------------
     Trace function        | 256 ref        | 512 refs      | 1024 refs    |
    ------------------------------------------------------------------------
     __add_keyed_refs      | 91             | 249           | 368          |
     __add_missing_keys    | 1              | 3             | 4            |
     __merge_refs 1st call | 114            | 442           | 2043         |
     __merge_refs 2nd call | 136            | 2091          | 18964        |
    ------------------------------------------------------------------------
    
    We can see the that __add_keyed_refs() grows almost in linear behavior.
    And __add_missing_keys() in this case doesn't change much or takes much
    time.
    
    While for the 1st __merge_refs() it's square growth
    for the 2nd __merge_refs() call it's cubic growth.
    
    It's no doubt that merge_refs() will take a long long time to execute if
    the number of refs continues its grows.
    
    So add a cond_resced() into the loop of __merge_refs().
    
    Although this will solve the problem of soft lockup, we need to use the
    new rb_tree based structure introduced by Lu Fengqi to really solve the
    long execution time.
    Signed-off-by: default avatarQu Wenruo <quwenruo@cn.fujitsu.com>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarChris Mason <clm@fb.com>
    d8422ba3
backref.c 51.9 KB