From e44fcf3bcf912ddf4ce94f9c3f71c253d473d692 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 12 Oct 2007 05:51:25 +0000 Subject: [PATCH] Add --stats option to print runtime and memory usage statistics. --- gold/config.in | 3 ++ gold/configure | 102 ++++++++++++++++++++++++++++++++++++++++++++++ gold/configure.ac | 1 + gold/fileread.cc | 30 +++++++++++++- gold/fileread.h | 23 ++++++++++- gold/layout.cc | 4 +- gold/layout.h | 7 ++++ gold/main.cc | 25 ++++++++++++ gold/options.cc | 3 ++ gold/options.h | 10 +++++ 10 files changed, 205 insertions(+), 3 deletions(-) diff --git a/gold/config.in b/gold/config.in index 46d67e5746f..9d1eba2e4b9 100644 --- a/gold/config.in +++ b/gold/config.in @@ -13,6 +13,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `mallinfo' function. */ +#undef HAVE_MALLINFO + /* Whether the C++ compiler can call a template member with no arguments */ #undef HAVE_MEMBER_TEMPLATE_SPECIFICATIONS diff --git a/gold/configure b/gold/configure index 305fe72e699..d1270485699 100755 --- a/gold/configure +++ b/gold/configure @@ -5443,6 +5443,108 @@ fi done +for ac_func in mallinfo +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + cat >conftest.$ac_ext <<_ACEOF class c { public: template void fn(); }; diff --git a/gold/configure.ac b/gold/configure.ac index 0e0bc7ef0d7..eb4416a9456 100644 --- a/gold/configure.ac +++ b/gold/configure.ac @@ -171,6 +171,7 @@ AC_LANG_PUSH(C++) AC_CHECK_HEADERS(tr1/unordered_set tr1/unordered_map) AC_CHECK_HEADERS(ext/hash_map ext/hash_set) +AC_CHECK_FUNCS(mallinfo) dnl Test whether the compiler can specify a member templates to call. AC_COMPILE_IFELSE([ diff --git a/gold/fileread.cc b/gold/fileread.cc index 88ac12611a2..97773d23a7d 100644 --- a/gold/fileread.cc +++ b/gold/fileread.cc @@ -48,6 +48,8 @@ File_read::View::~View() if (::munmap(const_cast(this->data_), this->size_) != 0) fprintf(stderr, _("%s: munmap failed: %s\n"), program_name, strerror(errno)); + + File_read::current_mapped_bytes -= this->size_; } } @@ -72,6 +74,11 @@ File_read::View::is_locked() // Class File_read. +// The File_read static variables. +unsigned long long File_read::total_mapped_bytes; +unsigned long long File_read::current_mapped_bytes; +unsigned long long File_read::maximum_mapped_bytes; + // The File_read class is designed to support file descriptor caching, // but this is not currently implemented. @@ -146,7 +153,15 @@ File_read::unlock() gold_assert(this->lock_count_ > 0); --this->lock_count_; if (this->lock_count_ == 0) - this->clear_views(false); + { + File_read::total_mapped_bytes += this->mapped_bytes_; + File_read::current_mapped_bytes += this->mapped_bytes_; + this->mapped_bytes_ = 0; + if (File_read::current_mapped_bytes > File_read::maximum_mapped_bytes) + File_read::maximum_mapped_bytes = File_read::current_mapped_bytes; + + this->clear_views(false); + } } bool @@ -289,6 +304,8 @@ File_read::find_or_make_view(off_t start, off_t size, bool cache) gold_exit(false); } + this->mapped_bytes_ += psize; + const unsigned char* pbytes = static_cast(p); v = new File_read::View(poff, psize, pbytes, cache, true); } @@ -355,6 +372,17 @@ File_read::clear_views(bool destroying) } } +// Print statistical information to stderr. This is used for --stats. + +void +File_read::print_stats() +{ + fprintf(stderr, _("%s: total bytes mapped for read: %llu\n"), + program_name, File_read::total_mapped_bytes); + fprintf(stderr, _("%s: maximum bytes mapped for read at one time: %llu\n"), + program_name, File_read::maximum_mapped_bytes); +} + // Class File_view. File_view::~File_view() diff --git a/gold/fileread.h b/gold/fileread.h index 349a2b52173..cf4b3ab98ae 100644 --- a/gold/fileread.h +++ b/gold/fileread.h @@ -46,7 +46,7 @@ class File_read public: File_read() : name_(), descriptor_(-1), size_(0), lock_count_(0), views_(), - saved_views_(), contents_(NULL) + saved_views_(), contents_(NULL), mapped_bytes_(0) { } ~File_read(); @@ -109,11 +109,27 @@ class File_read File_view* get_lasting_view(off_t start, off_t size, bool cache); + // Dump statistical information to stderr. + static void + print_stats(); + private: // This class may not be copied. File_read(const File_read&); File_read& operator=(const File_read&); + // Total bytes mapped into memory during the link. This variable is + // only accessed from the main thread, when unlocking the object. + static unsigned long long total_mapped_bytes; + + // Current number of bytes mapped into memory during the link. This + // variable is only accessed from the main thread. + static unsigned long long current_mapped_bytes; + + // High water mark of bytes mapped into memory during the link. + // This variable is only accessed from the main thread. + static unsigned long long maximum_mapped_bytes; + // A view into the file. class View { @@ -167,6 +183,7 @@ class File_read bool mapped_; }; + friend class View; friend class File_view; // Find a view into the file. @@ -219,6 +236,10 @@ class File_read Saved_views saved_views_; // Specified file contents. Used only for testing purposes. const unsigned char* contents_; + // Total amount of space mapped into memory. This is only changed + // while the file is locked. When we unlock the file, we transfer + // the total to total_mapped_bytes, and reset this to zero. + size_t mapped_bytes_; }; // A view of file data that persists even when the file is unlocked. diff --git a/gold/layout.cc b/gold/layout.cc index f7e136590a4..5bcdbe1a81c 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -67,7 +67,7 @@ Layout::Layout(const General_options& options) unattached_section_list_(), special_output_list_(), tls_segment_(NULL), symtab_section_(NULL), dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL), - eh_frame_section_(NULL) + eh_frame_section_(NULL), output_file_size_(-1) { // Make space for more than enough segments for a typical file. // This is just for efficiency--it's OK if we wind up needing more. @@ -625,6 +625,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) // Now we know exactly where everything goes in the output file. Output_data::layout_complete(); + this->output_file_size_ = off; + return off; } diff --git a/gold/layout.h b/gold/layout.h index 90cc22bb20c..441be944841 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -137,6 +137,11 @@ class Layout off_t finalize(const Input_objects*, Symbol_table*); + // Return the size of the output file. + off_t + output_file_size() const + { return this->output_file_size_; } + // Return the TLS segment. This will return NULL if there isn't // one. Output_segment* @@ -368,6 +373,8 @@ class Layout Output_data_dynamic* dynamic_data_; // The exception frame section. Output_section* eh_frame_section_; + // The size of the output file. + off_t output_file_size_; }; // This task handles writing out data which is not part of a section diff --git a/gold/main.cc b/gold/main.cc index ccd958d872b..49b50b2ca4c 100644 --- a/gold/main.cc +++ b/gold/main.cc @@ -22,6 +22,11 @@ #include "gold.h" +#ifdef HAVE_MALLINFO +#include +#endif +#include "libiberty.h" + #include "options.h" #include "parameters.h" #include "dirsearch.h" @@ -49,6 +54,11 @@ main(int argc, char** argv) // Handle the command line options. Command_line command_line; command_line.process(argc - 1, argv + 1); + + long start_time = 0; + if (command_line.options().print_stats()) + start_time = get_run_time(); + initialize_parameters(&command_line.options()); // The work queue. @@ -75,5 +85,20 @@ main(int argc, char** argv) // Run the main task processing loop. workqueue.process(); + if (command_line.options().print_stats()) + { + long run_time = get_run_time() - start_time; + fprintf(stderr, _("%s: total run time: %ld.%06ld seconds\n"), + program_name, run_time / 1000000, run_time % 1000000); +#ifdef HAVE_MALLINFO + struct mallinfo m = mallinfo(); + fprintf(stderr, _("%s: total space allocated by malloc: %d bytes\n"), + program_name, m.arena); +#endif + File_read::print_stats(); + fprintf(stderr, _("%s: output file size: %lld bytes\n"), + program_name, static_cast(layout.output_file_size())); + } + gold_exit(true); } diff --git a/gold/options.cc b/gold/options.cc index 89f4ff4418d..89eecf66bb8 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -348,6 +348,8 @@ options::Command_line_options::options[] = NULL, ONE_DASH, &General_options::set_shared), GENERAL_NOARG('\0', "static", N_("Do not link against shared libraries"), NULL, ONE_DASH, &General_options::set_static), + GENERAL_NOARG('\0', "stats", N_("Print resource usage statistics"), + NULL, TWO_DASHES, &General_options::set_stats), GENERAL_ARG('\0', "sysroot", N_("Set target system root directory"), N_("--sysroot DIR"), TWO_DASHES, &General_options::set_sysroot), POSDEP_NOARG('\0', "as-needed", @@ -388,6 +390,7 @@ General_options::General_options() rpath_link_(), is_shared_(false), is_static_(false), + print_stats_(false), sysroot_() { } diff --git a/gold/options.h b/gold/options.h index a11b68cdb00..9848639dff5 100644 --- a/gold/options.h +++ b/gold/options.h @@ -169,6 +169,11 @@ class General_options is_static() const { return this->is_static_; } + // --statis: Print resource usage statistics. + bool + print_stats() const + { return this->print_stats_; } + // --sysroot: The system root of a cross-linker. const std::string& sysroot() const @@ -251,6 +256,10 @@ class General_options set_static() { this->is_static_ = true; } + void + set_stats() + { this->print_stats_ = true; } + void set_sysroot(const char* arg) { this->sysroot_ = arg; } @@ -275,6 +284,7 @@ class General_options Dir_list rpath_link_; bool is_shared_; bool is_static_; + bool print_stats_; std::string sysroot_; }; -- 2.30.2