This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gold][patch] Add more timing information


The attached patch adds an utility class Timer which uses some ideas
from gcc's timevar.c. The patch also uses Timer to report user, system
and wall time of each task and of the full run.

Things to note:
*) Timer uses "times" or get_run_time. Not as portable as timevar.c but not a
regression since gold used only get_run_time before.
*) The resolution of times is not very good, but getting better wall time would
require a second syscall.

2009-12-16  Rafael Avila de Espindola  <espindola@google.com>

	* Makefile.am (CCFILES): Add timer.cc.
	(HFILES): Add timer.h.
	* configure.ac: Check for sysconf and times.
	* main.cc: include timer.h.
	(main): Use Timer instead of get_run_time.
	* timer.cc: New.
	* timer.h: New.
	* workqueue.cc: include timer.h.
	(Workqueue::find_and_run_task):
	Report user, sys and wall time.
	* Makefile.in: Regenerate.
	* config.in: Regenerate.
	* configure: Regenerate.

Cheers,
-- 
Rafael Ãvila de EspÃndola
diff --git a/gold/Makefile.am b/gold/Makefile.am
index 6afca17..9c9ed1a 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -78,6 +78,7 @@ CCFILES = \
 	symtab.cc \
 	target.cc \
 	target-select.cc \
+	timer.cc \
 	version.cc \
 	workqueue.cc \
 	workqueue-threads.cc
@@ -124,6 +125,7 @@ HFILES = \
 	target.h \
 	target-reloc.h \
 	target-select.h \
+	timer.h \
 	tls.h \
 	token.h \
 	workqueue.h \
diff --git a/gold/configure.ac b/gold/configure.ac
index 2f9cc43..f279b45 100644
--- a/gold/configure.ac
+++ b/gold/configure.ac
@@ -338,7 +338,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_HEADERS(byteswap.h)
-AC_CHECK_FUNCS(mallinfo posix_fallocate readv)
+AC_CHECK_FUNCS(mallinfo posix_fallocate readv sysconf times)
 AC_CHECK_DECLS([basename, ffs, asprintf, vasprintf, snprintf, vsnprintf, strverscmp, strndup, memmem])
 
 # Use of ::std::tr1::unordered_map::rehash causes undefined symbols
diff --git a/gold/main.cc b/gold/main.cc
index 66e8b24..c9d0d79 100644
--- a/gold/main.cc
+++ b/gold/main.cc
@@ -46,6 +46,7 @@
 #include "gc.h"
 #include "icf.h"
 #include "incremental.h"
+#include "timer.h"
 
 using namespace gold;
 
@@ -161,9 +162,9 @@ main(int argc, char** argv)
   Command_line command_line;
   command_line.process(argc - 1, const_cast<const char**>(argv + 1));
 
-  long start_time = 0;
+  Timer timer;
   if (command_line.options().stats())
-    start_time = get_run_time();
+    timer.start();
 
   // Store some options in the globally accessible parameters.
   set_parameters_options(&command_line.options());
@@ -247,9 +248,15 @@ main(int argc, char** argv)
 
   if (command_line.options().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);
+      Timer::TimeStats elapsed = timer.get_elapsed_time();
+      fprintf(stderr,
+             _("%s: total run time: " \
+               "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)\n"),
+              program_name,
+              elapsed.user / 1000, (elapsed.user % 1000) * 1000,
+              elapsed.sys / 1000, (elapsed.user % 1000) * 1000,
+              elapsed.wall / 1000, (elapsed.wall % 1000) * 1000);
+
 #ifdef HAVE_MALLINFO
       struct mallinfo m = mallinfo();
       fprintf(stderr, _("%s: total space allocated by malloc: %d bytes\n"),
diff --git a/gold/timer.cc b/gold/timer.cc
new file mode 100644
index 0000000..041517d
--- /dev/null
+++ b/gold/timer.cc
@@ -0,0 +1,109 @@
+// timer.cc -- helper class for time accounting
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Rafael Avila de Espindola <espindola@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// After processing the command line, everything the linker does is
+// driven from a work queue.  This permits us to parallelize the
+// linker where possible.
+
+#include "gold.h"
+
+#include <sys/times.h>
+
+#include "libiberty.h"
+
+#include "timer.h"
+
+namespace gold
+{
+
+// Class Timer
+
+Timer::Timer()
+{
+  this->start_time_.wall = 0;
+  this->start_time_.user = 0;
+  this->start_time_.sys = 0;
+}
+
+// Start couting the time.
+void
+Timer::start ()
+{
+  this->get_time(&this->start_time_);
+}
+
+#if HAVE_SYSCONF && defined _SC_CLK_TCK
+# define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */
+#else
+# ifdef CLK_TCK
+#  define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */
+# else
+#  ifdef HZ
+#   define TICKS_PER_SECOND HZ  /* traditional UNIX */
+#  else
+#   define TICKS_PER_SECOND 100 /* often the correct value */
+#  endif
+# endif
+#endif
+
+// sysconf can be slow, so we only call it once.
+static long ticks_per_sec;
+class Timer_init
+{
+ public:
+  Timer_init()
+  {
+    ticks_per_sec = TICKS_PER_SECOND;
+  }
+};
+Timer_init timer_init;
+
+// Write the current time infortamion.
+void
+Timer::get_time (TimeStats *now)
+{
+#ifdef HAVE_TIMES
+  tms t;
+  now->wall = (times(&t)  * 1000) / ticks_per_sec;
+  now->user = (t.tms_utime * 1000) / ticks_per_sec;
+  now->sys  = (t.tms_stime * 1000) / ticks_per_sec;
+#else
+  now->wall = get_run_time() / 1000;
+  now->user = 0;
+  now->sys = 0;
+#endif
+}
+
+// Return the stats since start was called.
+Timer::TimeStats
+Timer::get_elapsed_time ()
+{
+  TimeStats now;
+  this->get_time(&now);
+  TimeStats delta;
+  delta.wall = now.wall - this->start_time_.wall;
+  delta.user = now.user - this->start_time_.user;
+  delta.sys = now.sys - this->start_time_.sys;
+  return delta;
+}
+
+}
diff --git a/gold/timer.h b/gold/timer.h
new file mode 100644
index 0000000..32fff27
--- /dev/null
+++ b/gold/timer.h
@@ -0,0 +1,71 @@
+// timer.h -- helper class for time accounting   -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Written by Rafael Avila de Espindola <espindola@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// After processing the command line, everything the linker does is
+// driven from a work queue.  This permits us to parallelize the
+// linker where possible.
+
+#ifndef GOLD_TIMER_H
+#define GOLD_TIMER_H
+
+namespace gold
+{
+
+class Timer
+{
+ public:
+  // Used to report time statistics. All fields are in milliseconds.
+  struct TimeStats
+  {
+    /* User time in this process.  */
+    long user;
+
+    /* System time in this process.  */
+    long sys;
+
+    /* Wall clock time.  */
+    long wall;
+  };
+
+  // Return the stats since start was called.
+  TimeStats
+  get_elapsed_time ();
+
+  // Start couting the time.
+  void
+  start();
+
+  Timer();
+
+ private:
+  // This class cannot be copied.
+  Timer(const Timer&);
+  Timer& operator=(const Timer&);
+
+  // Write the current time infortamion.
+  static void
+  get_time (TimeStats *now);
+  TimeStats start_time_;
+};
+
+}
+#endif
diff --git a/gold/workqueue.cc b/gold/workqueue.cc
index 18c3900..c713dca 100644
--- a/gold/workqueue.cc
+++ b/gold/workqueue.cc
@@ -24,6 +24,7 @@
 
 #include "debug.h"
 #include "options.h"
+#include "timer.h"
 #include "workqueue.h"
 #include "workqueue-internal.h"
 
@@ -311,10 +312,24 @@ Workqueue::find_and_run_task(int thread_number)
       gold_debug(DEBUG_TASK, "%3d running   task %s", thread_number,
 		 t->name().c_str());
 
+      Timer timer;
+      if (is_debugging_enabled(DEBUG_TASK))
+        timer.start();
+
       t->run(this);
 
-      gold_debug(DEBUG_TASK, "%3d completed task %s", thread_number,
-		 t->name().c_str());
+      if (is_debugging_enabled(DEBUG_TASK))
+        {
+          Timer::TimeStats elapsed = timer.get_elapsed_time();
+
+          gold_debug(DEBUG_TASK,
+                     "%3d completed task %s "
+                     "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)",
+                     thread_number,  t->name().c_str(),
+                     elapsed.user / 1000, (elapsed.user % 1000) * 1000,
+                     elapsed.sys / 1000, (elapsed.user % 1000) * 1000,
+                     elapsed.wall / 1000, (elapsed.wall % 1000) * 1000);
+        }
 
       Task* next;
       {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]