From Craig Silverstein: size hash tables to avoid resizing.
authorIan Lance Taylor <iant@google.com>
Fri, 14 Dec 2007 05:24:17 +0000 (05:24 +0000)
committerIan Lance Taylor <iant@google.com>
Fri, 14 Dec 2007 05:24:17 +0000 (05:24 +0000)
gold/layout.cc
gold/main.cc
gold/object.h
gold/stringpool.cc
gold/stringpool.h
gold/symtab.cc
gold/symtab.h

index 26585fa88c8ea86d55785eb7af9b0030c0e19b8a..1cea1a6429466fbb655e9f29331e0b6207f9ae40 100644 (file)
@@ -1154,6 +1154,25 @@ Layout::set_section_indexes(unsigned int shndx)
 void
 Layout::count_local_symbols(const Input_objects* input_objects)
 {
+  // First, figure out an upper bound on the number of symbols we'll
+  // be inserting into each pool.  This helps us create the pools with
+  // the right size, to avoid unnecessary hashtable resizing.
+  unsigned int symbol_count = 0;
+  for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+       p != input_objects->relobj_end();
+       ++p)
+    symbol_count += (*p)->local_symbol_count();
+
+  // Go from "upper bound" to "estimate."  We overcount for two
+  // reasons: we double-count symbols that occur in more than one
+  // object file, and we count symbols that are dropped from the
+  // output.  Add it all together and assume we overcount by 100%.
+  symbol_count /= 2;
+
+  // We assume all symbols will go into both the sympool and dynpool.
+  this->sympool_.reserve(symbol_count);
+  this->dynpool_.reserve(symbol_count);
+
   for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
        p != input_objects->relobj_end();
        ++p)
index 921d14808d98c5d1c338f9aee9ffd79957e5b655..c7c2d95dbfe71e2afc3acdbc8b0612608c077627 100644 (file)
@@ -75,8 +75,11 @@ main(int argc, char** argv)
   // The list of input objects.
   Input_objects input_objects;
 
-  // The symbol table.
-  Symbol_table symtab;
+  // The symbol table.  We're going to guess here how many symbols
+  // we're going to see based on the number of input files.  Even when
+  // this is off, it means at worse we don't quite optimize hashtable
+  // resizing as well as we could have (perhap using more memory).
+  Symbol_table symtab(command_line.number_of_input_files() * 1024);
 
   // The layout object.
   Layout layout(command_line.options());
index 5faa9115acbdd358b5998c276cf163aa9fb9a403..a98e75665d21bef518138fe4787c0c1b4fdefcc4 100644 (file)
@@ -429,6 +429,11 @@ class Relobj : public Object
              Layout* layout, Read_relocs_data* rd)
   { return this->do_scan_relocs(options, symtab, layout, rd); }
 
+  // The number of local symbols in the input symbol table.
+  virtual unsigned int
+  local_symbol_count() const
+  { return this->do_local_symbol_count(); }
+
   // Initial local symbol processing: count the number of local symbols
   // in the output symbol table and dynamic symbol table; add local symbol
   // names to *POOL and *DYNPOOL.
@@ -538,6 +543,10 @@ class Relobj : public Object
   do_scan_relocs(const General_options&, Symbol_table*, Layout*,
                 Read_relocs_data*) = 0;
 
+  // Return the number of local symbols--implemented by child class.
+  virtual unsigned int
+  do_local_symbol_count() const = 0;
+
   // Count local symbols--implemented by child class.
   virtual void
   do_count_local_symbols(Stringpool_template<char>*,
@@ -791,11 +800,6 @@ class Sized_relobj : public Relobj
   void
   setup(const typename elfcpp::Ehdr<size, big_endian>&);
 
-  // Return the number of local symbols.
-  unsigned int
-  local_symbol_count() const
-  { return this->local_symbol_count_; }
-
   // If SYM is the index of a global symbol in the object file's
   // symbol table, return the Symbol object.  Otherwise, return NULL.
   Symbol*
@@ -964,10 +968,16 @@ class Sized_relobj : public Relobj
   get_symbol_location_info(unsigned int shndx, off_t offset,
                           Symbol_location_info* info);
 
+ protected:
   // Read the symbols.
   void
   do_read_symbols(Read_symbols_data*);
 
+  // Return the number of local symbols.
+  unsigned int
+  do_local_symbol_count() const
+  { return this->local_symbol_count_; }
+
   // Lay out the input sections.
   void
   do_layout(Symbol_table*, Layout*, Read_symbols_data*);
index 0ac1dcb24c9835e0b4a435296092bc2abdd88e0a..7bf83656e7ef775d402c09f92f5fa078a5b2f147 100644 (file)
@@ -58,6 +58,30 @@ Stringpool_template<Stringpool_char>::~Stringpool_template()
   this->clear();
 }
 
+// Resize the internal hashtable with the expectation we'll get n new
+// elements.  Note that the hashtable constructor takes a "number of
+// buckets you'd like," rather than "number of elements you'd like,"
+// but that's the best we can do.
+
+template<typename Stringpool_char>
+void
+Stringpool_template<Stringpool_char>::reserve(unsigned int n)
+{
+#if defined(HAVE_TR1_UNORDERED_MAP)
+  // rehash() implementation is broken in gcc 4.0.3's stl
+  //this->string_set_.rehash(this->string_set_.size() + n);
+  //return;
+#elif defined(HAVE_EXT_HASH_MAP)
+  this->string_set_.resize(this->string_set_.size() + n);
+  return;
+#endif
+
+  // This is the generic "reserve" code, if no #ifdef above triggers.
+  String_set_type new_string_set(this->string_set_.size() + n);
+  new_string_set.insert(this->string_set_.begin(), this->string_set_.end());
+  this->string_set_.swap(new_string_set);
+}
+
 // Return the length of a string of arbitrary character type.
 
 template<typename Stringpool_char>
@@ -212,7 +236,11 @@ Stringpool_template<Stringpool_char>::add_string(const Stringpool_char* s,
   ++this->next_index_;
 
   if (pkey != NULL)
-    *pkey = psd->index * key_mult;
+    {
+      *pkey = psd->index * key_mult;
+      // Ensure there was no overflow.
+      gold_assert(*pkey / key_mult == psd->index);
+    }
 
   if (front)
     this->strings_.push_front(psd);
index 929b4d1bc1fcf0e79cc0c02ef95e590a099f2e63..93e1ec8392572e2e3fa4d006591f587a9a98d4af 100644 (file)
@@ -88,6 +88,12 @@ class Stringpool_template
   void
   clear();
 
+  // Hint to the stringpool class that you intend to insert n additional
+  // elements.  The stringpool class can use this info however it likes;
+  // in practice it will resize its internal hashtables to make room.
+  void
+  reserve(unsigned int n);
+
   // Indicate that we should not reserve offset 0 to hold the empty
   // string when converting the stringpool to a string table.  This
   // should not be called for a proper ELF SHT_STRTAB section.
index 9187f326aca067b5f40be8a993fb06820ff8de25..770628cac8cc97b4120a7e04384f1f72d41ae140 100644 (file)
@@ -295,10 +295,11 @@ Symbol::final_value_is_known() const
 
 // Class Symbol_table.
 
-Symbol_table::Symbol_table()
-  : saw_undefined_(0), offset_(0), table_(), namepool_(),
+Symbol_table::Symbol_table(unsigned int count)
+  : saw_undefined_(0), offset_(0), table_(count), namepool_(),
     forwarders_(), commons_(), warnings_()
 {
+  namepool_.reserve(count);
 }
 
 Symbol_table::~Symbol_table()
index a4f11068dc75620d680dc5be3ddffb91c3c8a6f0..cb3be9b37ee667492cf4b908abfdc6d161bae2b6 100644 (file)
@@ -955,7 +955,10 @@ class Warnings
 class Symbol_table
 {
  public:
-  Symbol_table();
+  // COUNT is an estimate of how many symbosl will be inserted in the
+  // symbol table.  It's ok to put 0 if you don't know; a correct
+  // guess will just save some CPU by reducing hashtable resizes.
+  Symbol_table(unsigned int count);
 
   ~Symbol_table();
 
This page took 0.032203 seconds and 4 git commands to generate.