Add --stats option to print runtime and memory usage statistics.
This commit is contained in:
parent
6ca8706da5
commit
e44fcf3bcf
10 changed files with 205 additions and 3 deletions
|
@ -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
|
||||
|
||||
|
|
102
gold/configure
vendored
102
gold/configure
vendored
|
@ -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(); };
|
||||
|
|
|
@ -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([
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
25
gold/main.cc
25
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);
|
||||
}
|
||||
|
|
|
@ -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_()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue