summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-10-12 05:51:25 +0000
committerIan Lance Taylor <iant@google.com>2007-10-12 05:51:25 +0000
commite44fcf3bcf912ddf4ce94f9c3f71c253d473d692 (patch)
tree3f5de3fdbbc7b5ba332f8d2123f017c2e8437ce6
parent6ca8706da5d2154ee86544024f708fda30efba26 (diff)
downloadbinutils-gdb-e44fcf3bcf912ddf4ce94f9c3f71c253d473d692.tar.gz
Add --stats option to print runtime and memory usage statistics.
-rw-r--r--gold/config.in3
-rwxr-xr-xgold/configure102
-rw-r--r--gold/configure.ac1
-rw-r--r--gold/fileread.cc30
-rw-r--r--gold/fileread.h23
-rw-r--r--gold/layout.cc4
-rw-r--r--gold/layout.h7
-rw-r--r--gold/main.cc25
-rw-r--r--gold/options.cc3
-rw-r--r--gold/options.h10
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 <inttypes.h> 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 <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> 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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#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<int i> 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<unsigned char*>(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<const unsigned char*>(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 <malloc.h>
+#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<long long>(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
@@ -252,6 +257,10 @@ class General_options
{ 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_;
};