Optimize the performance of the group_setup function.
authorJens Widell <jl@opera.com>
Fri, 12 Jan 2018 13:16:17 +0000 (13:16 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 12 Jan 2018 13:16:17 +0000 (13:16 +0000)
When processing a section that is a member of a group, the group
that contains it is looked up using a linear search. The resulting
O(n^2) complexity causes significant performance issues when
dealing with object files with very many groups.

By remembering the index of the last found group and restarting
the next search from that index, the search instead becomes O(n)
in common cases.

* elf.c (setup_group): Optimize search for group by remembering
last found group and restarting search at that index.
* elf-bfd.h (struct elf_obj_tdata): Add group_search_offset field.

bfd/ChangeLog
bfd/elf-bfd.h
bfd/elf.c

index 19364c0c779ed07c3722044dfff7600310b502ac..cc54b535f7503902a5e1d31b15cdfbf94ee6308e 100644 (file)
@@ -1,3 +1,9 @@
+2018-01-12  Jens Widell  <jl@opera.com>
+
+       * elf.c (setup_group): Optimize search for group by remembering
+       last found group and restarting search at that index.
+       * elf-bfd.h (struct elf_obj_tdata): Add group_search_offset field.
+
 2018-01-12  Gunther Nikl  <gnikl@users.sourceforge.net>
 
        * aoutx.h (aout_link_check_ar_symbols): Remove default and handle
index 9c9b0c7fac12b32770d598129af11f4b5248a3ed..b580dc2769af462266ffc3d8a69199617fe51f1d 100644 (file)
@@ -1909,6 +1909,10 @@ struct elf_obj_tdata
   Elf_Internal_Shdr **group_sect_ptr;
   int num_group;
 
+  /* Index into group_sect_ptr, updated by setup_group when finding a
+     section's group.  Used to optimize subsequent group searches.  */
+  unsigned int group_search_offset;
+
   unsigned int symtab_section, dynsymtab_section;
   unsigned int dynversym_section, dynverdef_section, dynverref_section;
 
index 1d0eefd053694889812b6390a0c9fbb33a0f2a9c..90aef0913292f1760264c72867b8c872527b4d8f 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -737,10 +737,14 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
 
   if (num_group != (unsigned) -1)
     {
-      unsigned int i;
+      unsigned int search_offset = elf_tdata (abfd)->group_search_offset;
+      unsigned int j;
 
-      for (i = 0; i < num_group; i++)
+      for (j = 0; j < num_group; j++)
        {
+         /* Begin search from previous found group.  */
+         unsigned i = (j + search_offset) % num_group;
+
          Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
          Elf_Internal_Group *idx;
          bfd_size_type n_elt;
@@ -803,7 +807,8 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
                if (shdr->bfd_section != NULL)
                  elf_next_in_group (shdr->bfd_section) = newsect;
 
-               i = num_group - 1;
+               elf_tdata (abfd)->group_search_offset = i;
+               j = num_group - 1;
                break;
              }
        }