this->namepool_.print_stats("section name pool");
this->sympool_.print_stats("output symbol name pool");
this->dynpool_.print_stats("dynamic name pool");
+
+ for (Section_list::const_iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ (*p)->print_merge_stats();
}
// Write_sections_task methods.
if (len % entsize != 0)
return false;
+ this->input_count_ += len / entsize;
+
for (section_size_type i = 0; i < len; i += entsize, p += entsize)
{
// Add the constant to the section contents. If we find that it
memcpy(buffer, this->p_, this->len_);
}
+// Print merge stats to stderr.
+
+void
+Output_merge_data::do_print_merge_stats(const char* section_name)
+{
+ fprintf(stderr,
+ _("%s: %s merged constants size: %lu; input: %zu; output: %zu\n"),
+ program_name, section_name,
+ static_cast<unsigned long>(this->entsize()),
+ this->input_count_, this->hashtable_.size());
+}
+
// Class Output_merge_string.
// Add an input section to a merged string section.
return false;
}
+ size_t count = 0;
+
// The index I is in bytes, not characters.
section_size_type i = 0;
while (i < len)
p = pl + 1;
i += bytelen_with_null;
+ ++count;
}
+ this->input_count_ += count;
+
return true;
}
this->stringpool_.write_to_buffer(buffer, this->data_size());
}
+// Return the name of the types of string to use with
+// do_print_merge_stats.
+
+template<typename Char_type>
+const char*
+Output_merge_string<Char_type>::string_name()
+{
+ gold_unreachable();
+ return NULL;
+}
+
+template<>
+const char*
+Output_merge_string<char>::string_name()
+{
+ return "strings";
+}
+
+template<>
+const char*
+Output_merge_string<uint16_t>::string_name()
+{
+ return "16-bit strings";
+}
+
+template<>
+const char*
+Output_merge_string<uint32_t>::string_name()
+{
+ return "32-bit strings";
+}
+
+// Print merge stats to stderr.
+
+template<typename Char_type>
+void
+Output_merge_string<Char_type>::do_print_merge_stats(const char* section_name)
+{
+ char buf[200];
+ snprintf(buf, sizeof buf, "%s merged %s", section_name, this->string_name());
+ fprintf(stderr, _("%s: %s input: %zu\n"),
+ program_name, buf, this->input_count_);
+ this->stringpool_.print_stats(buf);
+}
+
// Instantiate the templates we need.
template
public:
Output_merge_data(uint64_t entsize, uint64_t addralign)
: Output_merge_base(entsize, addralign), p_(NULL), len_(0), alc_(0),
+ input_count_(0),
hashtable_(128, Merge_data_hash(this), Merge_data_eq(this))
{ }
+ protected:
// Add an input section.
bool
do_add_input_section(Relobj* object, unsigned int shndx);
void
do_write_to_buffer(unsigned char*);
+ // Print merge stats to stderr.
+ void
+ do_print_merge_stats(const char* section_name);
+
private:
// We build a hash table of the fixed-size constants. Each constant
// is stored as a pointer into the section data we are accumulating.
section_size_type len_;
// The size of the allocated buffer.
section_size_type alc_;
+ // The number of entries seen in input files.
+ size_t input_count_;
// The hash table.
Merge_data_hashtable hashtable_;
};
public:
Output_merge_string(uint64_t addralign)
: Output_merge_base(sizeof(Char_type), addralign), stringpool_(),
- merged_strings_()
+ merged_strings_(), input_count_(0)
{
gold_assert(addralign <= sizeof(Char_type));
this->stringpool_.set_no_zero_null();
void
do_write_to_buffer(unsigned char*);
+ // Print merge stats to stderr.
+ void
+ do_print_merge_stats(const char* section_name);
+
// Writes the stringpool to a buffer.
void
stringpool_to_buffer(unsigned char* buffer, section_size_type buffer_size)
{ this->stringpool_.clear(); }
private:
+ // The name of the string type, for stats.
+ const char*
+ string_name();
+
// As we see input sections, we build a mapping from object, section
// index and offset to strings.
struct Merged_string
// Map from a location in an input object to an entry in the
// Stringpool.
Merged_strings merged_strings_;
+ // The number of entries seen in input files.
+ size_t input_count_;
};
} // End namespace gold.
}
}
+// Print stats for merge sections to stderr.
+
+void
+Output_section::print_merge_stats()
+{
+ Input_section_list::iterator p;
+ for (p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ p->print_merge_stats(this->name_);
+}
+
// Output segment methods.
Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
write_to_buffer(unsigned char* buffer)
{ this->do_write_to_buffer(buffer); }
+ // Print merge stats to stderr. This should only be called for
+ // SHF_MERGE sections.
+ void
+ print_merge_stats(const char* section_name)
+ { this->do_print_merge_stats(section_name); }
+
protected:
// The child class must implement do_write.
do_write_to_buffer(unsigned char*)
{ gold_unreachable(); }
+ // Print merge statistics.
+ virtual void
+ do_print_merge_stats(const char*)
+ { gold_unreachable(); }
+
// Return the required alignment.
uint64_t
do_addralign() const
write_header(const Layout*, const Stringpool*,
elfcpp::Shdr_write<size, big_endian>*) const;
+ // Print merge statistics to stderr.
+ void
+ print_merge_stats();
+
protected:
// Return the section index in the output file.
unsigned int
void
write_to_buffer(unsigned char*);
+ // Print statistics about merge sections to stderr.
+ void
+ print_merge_stats(const char* section_name)
+ {
+ if (this->shndx_ == MERGE_DATA_SECTION_CODE
+ || this->shndx_ == MERGE_STRING_SECTION_CODE)
+ this->u2_.posd->print_merge_stats(section_name);
+ }
+
private:
// Code values which appear in shndx_. If the value is not one of
// these codes, it is the input section index in the object file.