This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

[PATCH 1/2] gcc parts of timer refactoring


In r223092 (aka dd4d567f4b6b498242097c41d63666bdae320ac1) I moved the
state of timevar.c from being global data into a "class timer" with
a global instance "g_timer".

This followup patch generalizes the timing within toplev so that an
external "timer" instance can (optionally) be passed in; this is used
in patch 2 to add an API to libgccjit for client code: gcc_jit_timer.

The gcc_jit_timer API allows client code to create arbitrary new timing
items (beyond the hardcoded list in timevar.def), giving them names,
so that client code can time whatever things are relevant to it; this
patch adds the support necessary to timevar.[ch] for this.

The patch also generalizes timevar.h's auto_timevar to avoid it
depending on the "g_timer" global (which is only set during the
lifetime of "toplev".  We can use this to add TV_JIT_ACQUIRING_MUTEX,
and thus measure wallclock time spent waiting for the JIT mutex.

Generalize timevar.c to add support for timing jit client code, by:

 * adding support for timing client items with arbitrary
   client-supplied names (e.g. "compiling code", "running code" etc).

 * supporting having a "timer" instance created externally and passed
   in to toplev, allowing clients to control where toplev's timing
   information is accumulated

 * add a couple of jit-specific timevars

This goes with the next patch; I've split them up for ease of review.

OK for trunk?

gcc/ChangeLog:
	* main.c (main): Pass in NULL for toplev's external_timer.
	* timevar.c: Include coretypes.h, hash-map.h, vec.h.
	(class timer::named_items): New.
	(timer::named_items::named_items): New.
	(timer::named_items::~named_items): New.
	(timer::named_items::push): New.
	(timer::named_items::pop): New.
	(timer::named_items::print): New.
	(timer::timer): Initialize field "m_jit_client_items".
	(timer::~timer): New.
	(timer::push): Move bulk of implementation to...
	(timer::push_internal): ...here.  New function.
	(timer::pop): Move bulk of implementation to...
	(timer::pop_internal): ...here.  New function.
	(timer::push_client_item): New.
	(timer::pop_client_item): New.
	(timer::print_row): New function, taken from timer::print.
	(timer::print): Print "GCC items" header if we also have client
	items.  Move row-printing to timer::print_row.  Print any client
	items.
	(timer::get_topmost_item_name): New method.
	* timevar.def (TV_JIT_ACQUIRING_MUTEX): New.
	(TV_JIT_CLIENT_CODE): New.
	* timevar.h (timer::push_client_item): New declaration.
	(timer::pop_client_item): New declaration.
	(timer::get_topmost_item_name): New method.
	(timer::push_internal): New declaration.
	(timer::pop_internal): New declaration.
	(timer::print_row): New declaration.
	(timer::named_items): New declaration.
	(timer::m_jit_client_items): New field.
	(timer): Add friend class named_items.
	(auto_timevar::auto_timevar): Add timer param.
	(auto_timevar::~auto_timevar): Use field "m_timer".
	(auto_timevar::m_timer): New field.
	* toplev.c (initialize_rtl): Add g_timer as param when
	constructing auto_timevar instance.
	(toplev::toplev): Add "external_timer" param, and use it to
	initialize the "g_timer" global if non-NULL.
	(toplev::~toplev): If this created "g_timer", delete it.
	* toplev.h (toplev::toplev): Replace "use_TV_TOTAL" bool param
	with "external_timer" timer *.
---
 gcc/main.c      |   2 +-
 gcc/timevar.c   | 247 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 gcc/timevar.def |   2 +
 gcc/timevar.h   |  35 +++++++-
 gcc/toplev.c    |  18 +++--
 gcc/toplev.h    |   4 +-
 6 files changed, 261 insertions(+), 47 deletions(-)

diff --git a/gcc/main.c b/gcc/main.c
index 79baf0d..bbd8b67 100644
--- a/gcc/main.c
+++ b/gcc/main.c
@@ -33,7 +33,7 @@ int main (int argc, char **argv);
 int
 main (int argc, char **argv)
 {
-  toplev toplev (true, /* use_TV_TOTAL */
+  toplev toplev (NULL, /* external_timer */
 		 true /* init_signals */);
 
   return toplev.main (argc, argv);
diff --git a/gcc/timevar.c b/gcc/timevar.c
index 76ad22a..eebb1dc 100644
--- a/gcc/timevar.c
+++ b/gcc/timevar.c
@@ -20,7 +20,10 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
 #include "timevar.h"
+#include "hash-map.h"
+#include "vec.h"
 
 #ifndef HAVE_CLOCK_T
 typedef int clock_t;
@@ -120,6 +123,93 @@ static void timevar_accumulate (struct timevar_time_def *,
 				struct timevar_time_def *,
 				struct timevar_time_def *);
 
+/* The implementation of timing events for jit client code, allowing
+   arbitrary named items to appear on the timing stack.  */
+
+class timer::named_items
+{
+ public:
+  named_items (timer *t);
+  ~named_items ();
+
+  void push (const char *item_name);
+  void pop ();
+  void print (FILE *fp, const timevar_time_def *total);
+
+ private:
+  /* Which timer instance does this relate to?  */
+  timer *m_timer;
+
+  /* Dictionary, mapping from item names to timevar_def.
+     Note that currently we merely store/compare the raw string
+     pointers provided by client code; we don't take a copy,
+     or use strcmp.  */
+  hash_map <const char *, timer::timevar_def> m_hash_map;
+
+  /* The order in which items were originally inserted.  */
+  auto_vec <const char *> m_names;
+};
+
+/* The constructor for class timer::named_items.  */
+
+timer::named_items::named_items (timer *t)
+: m_timer (t),
+  m_hash_map (),
+  m_names ()
+{
+}
+
+/* The destructor for class timer::named_items.  */
+
+timer::named_items::~named_items ()
+{
+}
+
+/* Push the named item onto the timer stack.  */
+
+void
+timer::named_items::push (const char *item_name)
+{
+  gcc_assert (item_name);
+
+  bool existed;
+  timer::timevar_def *def = &m_hash_map.get_or_insert (item_name, &existed);
+  if (!existed)
+    {
+      def->elapsed.user = 0;
+      def->elapsed.sys = 0;
+      def->elapsed.wall = 0;
+      def->name = item_name;
+      def->standalone = 0;
+      m_names.safe_push (item_name);
+    }
+  m_timer->push_internal (def);
+}
+
+/* Pop the top item from the timer stack.  */
+
+void
+timer::named_items::pop ()
+{
+  m_timer->pop_internal ();
+}
+
+/* Print the given client item.  Helper function for timer::print.  */
+
+void
+timer::named_items::print (FILE *fp, const timevar_time_def *total)
+{
+  unsigned int i;
+  const char *item_name;
+  fprintf (fp, "Client items:\n");
+  FOR_EACH_VEC_ELT (m_names, i, item_name)
+    {
+      timer::timevar_def *def = m_hash_map.get (item_name);
+      gcc_assert (def);
+      m_timer->print_row (fp, total, def);
+    }
+}
+
 /* Fill the current times into TIME.  The definition of this function
    also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and
    HAVE_WALL_TIME macros.  */
@@ -169,7 +259,8 @@ timevar_accumulate (struct timevar_time_def *timer,
 timer::timer () :
   m_stack (NULL),
   m_unused_stack_instances (NULL),
-  m_start_time ()
+  m_start_time (),
+  m_jit_client_items (NULL)
 {
   /* Zero all elapsed times.  */
   memset (m_timevars, 0, sizeof (m_timevars));
@@ -190,6 +281,26 @@ timer::timer () :
 #endif
 }
 
+/* Class timer's destructor.  */
+
+timer::~timer ()
+{
+  timevar_stack_def *iter, *next;
+
+  for (iter = m_stack; iter; iter=next)
+    {
+      next = iter->next;
+      free (iter);
+    }
+  for (iter = m_unused_stack_instances; iter; iter=next)
+    {
+      next = iter->next;
+      free (iter);
+    }
+
+  delete m_jit_client_items;
+}
+
 /* Initialize timing variables.  */
 
 void
@@ -212,9 +323,20 @@ void
 timer::push (timevar_id_t timevar)
 {
   struct timevar_def *tv = &m_timevars[timevar];
+  push_internal (tv);
+}
+
+/* Push TV onto the timing stack, either one of the builtin ones
+   for a timevar_id_t, or one provided by client code to libgccjit.  */
+
+void
+timer::push_internal (struct timevar_def *tv)
+{
   struct timevar_stack_def *context;
   struct timevar_time_def now;
 
+  gcc_assert (tv);
+
   /* Mark this timing variable as used.  */
   tv->used = 1;
 
@@ -258,11 +380,20 @@ timer::push (timevar_id_t timevar)
 void
 timer::pop (timevar_id_t timevar)
 {
+  gcc_assert (&m_timevars[timevar] == m_stack->timevar);
+
+  pop_internal ();
+}
+
+/* Pop the topmost item from the stack, either one of the builtin ones
+   for a timevar_id_t, or one provided by client code to libgccjit.  */
+
+void
+timer::pop_internal ()
+{
   struct timevar_time_def now;
   struct timevar_stack_def *popped = m_stack;
 
-  gcc_assert (&m_timevars[timevar] == m_stack->timevar);
-
   /* What time is it?  */
   get_time (&now);
 
@@ -410,6 +541,28 @@ timer::cond_stop (timevar_id_t timevar)
   timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
 }
 
+/* Push the named item onto the timing stack.  */
+
+void
+timer::push_client_item (const char *item_name)
+{
+  gcc_assert (item_name);
+
+  /* Lazily create the named_items instance.  */
+  if (!m_jit_client_items)
+    m_jit_client_items = new named_items (this);
+
+  m_jit_client_items->push (item_name);
+}
+
+/* Pop the top-most client item from the timing stack.  */
+
+void
+timer::pop_client_item ()
+{
+  gcc_assert (m_jit_client_items);
+  m_jit_client_items->pop ();
+}
 
 /* Validate that phase times are consistent.  */
 
@@ -462,6 +615,46 @@ timer::validate_phases (FILE *fp) const
     }
 }
 
+/* Helper function for timer::print.  */
+
+void
+timer::print_row (FILE *fp,
+		  const timevar_time_def *total,
+		  const timevar_def *tv)
+{
+  /* The timing variable name.  */
+  fprintf (fp, " %-24s:", tv->name);
+
+#ifdef HAVE_USER_TIME
+  /* Print user-mode time for this process.  */
+  fprintf (fp, "%7.2f (%2.0f%%) usr",
+	   tv->elapsed.user,
+	   (total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100);
+#endif /* HAVE_USER_TIME */
+
+#ifdef HAVE_SYS_TIME
+  /* Print system-mode time for this process.  */
+  fprintf (fp, "%7.2f (%2.0f%%) sys",
+	   tv->elapsed.sys,
+	   (total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100);
+#endif /* HAVE_SYS_TIME */
+
+#ifdef HAVE_WALL_TIME
+  /* Print wall clock time elapsed.  */
+  fprintf (fp, "%7.2f (%2.0f%%) wall",
+	   tv->elapsed.wall,
+	   (total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100);
+#endif /* HAVE_WALL_TIME */
+
+  /* Print the amount of ggc memory allocated.  */
+  fprintf (fp, "%8u kB (%2.0f%%) ggc",
+	   (unsigned) (tv->elapsed.ggc_mem >> 10),
+	   (total->ggc_mem == 0
+	    ? 0
+	    : (float) tv->elapsed.ggc_mem / total->ggc_mem) * 100);
+
+  putc ('\n', fp);
+}
 
 /* Summarize timing variables to FP.  The timing variable TV_TOTAL has
    a special meaning -- it's considered to be the total elapsed time,
@@ -494,6 +687,8 @@ timer::print (FILE *fp)
   m_start_time = now;
 
   fputs ("\nExecution times (seconds)\n", fp);
+  if (m_jit_client_items)
+    fputs ("GCC items:\n", fp);
   for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id)
     {
       const timevar_def *tv = &m_timevars[(timevar_id_t) id];
@@ -516,39 +711,10 @@ timer::print (FILE *fp)
 	  && tv->elapsed.ggc_mem < GGC_MEM_BOUND)
 	continue;
 
-      /* The timing variable name.  */
-      fprintf (fp, " %-24s:", tv->name);
-
-#ifdef HAVE_USER_TIME
-      /* Print user-mode time for this process.  */
-      fprintf (fp, "%7.2f (%2.0f%%) usr",
-	       tv->elapsed.user,
-	       (total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100);
-#endif /* HAVE_USER_TIME */
-
-#ifdef HAVE_SYS_TIME
-      /* Print system-mode time for this process.  */
-      fprintf (fp, "%7.2f (%2.0f%%) sys",
-	       tv->elapsed.sys,
-	       (total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100);
-#endif /* HAVE_SYS_TIME */
-
-#ifdef HAVE_WALL_TIME
-      /* Print wall clock time elapsed.  */
-      fprintf (fp, "%7.2f (%2.0f%%) wall",
-	       tv->elapsed.wall,
-	       (total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100);
-#endif /* HAVE_WALL_TIME */
-
-      /* Print the amount of ggc memory allocated.  */
-      fprintf (fp, "%8u kB (%2.0f%%) ggc",
-	       (unsigned) (tv->elapsed.ggc_mem >> 10),
-	       (total->ggc_mem == 0
-		? 0
-		: (float) tv->elapsed.ggc_mem / total->ggc_mem) * 100);
-
-      putc ('\n', fp);
+      print_row (fp, total, tv);
     }
+  if (m_jit_client_items)
+    m_jit_client_items->print (fp, total);
 
   /* Print total time.  */
   fputs (" TOTAL                 :", fp);
@@ -578,6 +744,17 @@ timer::print (FILE *fp)
   validate_phases (fp);
 }
 
+/* Get the name of the topmost item.  For use by jit for validating
+   inputs to gcc_jit_timer_pop.  */
+const char *
+timer::get_topmost_item_name () const
+{
+  if (m_stack)
+    return m_stack->timevar->name;
+  else
+    return NULL;
+}
+
 /* Prints a message to stderr stating that time elapsed in STR is
    TOTAL (given in microseconds).  */
 
diff --git a/gcc/timevar.def b/gcc/timevar.def
index aee36e6..ac41075 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -296,3 +296,5 @@ DEFTIMEVAR (TV_JIT_REPLAY	     , "replay of JIT client activity")
 DEFTIMEVAR (TV_ASSEMBLE	     , "assemble JIT code")
 DEFTIMEVAR (TV_LINK		     , "link JIT code")
 DEFTIMEVAR (TV_LOAD		     , "load JIT result")
+DEFTIMEVAR (TV_JIT_ACQUIRING_MUTEX   , "acquiring JIT mutex")
+DEFTIMEVAR (TV_JIT_CLIENT_CODE   , "JIT client code")
diff --git a/gcc/timevar.h b/gcc/timevar.h
index 71a814a..85c7610 100644
--- a/gcc/timevar.h
+++ b/gcc/timevar.h
@@ -115,12 +115,24 @@ class timer
   bool cond_start (timevar_id_t tv);
   void cond_stop (timevar_id_t tv);
 
+  void push_client_item (const char *item_name);
+  void pop_client_item ();
+
   void print (FILE *fp);
 
+  const char *get_topmost_item_name () const;
+
  private:
   /* Private member functions.  */
   void validate_phases (FILE *fp) const;
 
+  struct timevar_def;
+  void push_internal (struct timevar_def *tv);
+  void pop_internal ();
+  static void print_row (FILE *fp,
+			 const timevar_time_def *total,
+			 const timevar_def *tv);
+
  private:
 
   /* Private type: a timing variable.  */
@@ -157,6 +169,12 @@ class timer
     struct timevar_stack_def *next;
   };
 
+  /* A class for managing a collection of named timing items, for use
+     e.g. by libgccjit for timing client code.  This class is declared
+     inside timevar.c to avoid everything using timevar.h
+     from needing vec and hash_map.  */
+  class named_items;
+
  private:
 
   /* Data members (all private).  */
@@ -176,6 +194,11 @@ class timer
      pushed.  Time elapsed since then is attributed to the topmost
      element.  */
   timevar_time_def m_start_time;
+
+  /* If non-NULL, for use when timing libgccjit's client code.  */
+  named_items *m_jit_client_items;
+
+  friend class named_items;
 };
 
 /* Provided for backward compatibility.  */
@@ -198,15 +221,18 @@ timevar_pop (timevar_id_t tv)
 class auto_timevar
 {
  public:
-  auto_timevar (timevar_id_t tv)
-    : m_tv (tv)
+  auto_timevar (timer *t, timevar_id_t tv)
+    : m_timer (t),
+      m_tv (tv)
   {
-    timevar_push (m_tv);
+    if (m_timer)
+      m_timer->push (m_tv);
   }
 
   ~auto_timevar ()
   {
-    timevar_pop (m_tv);
+    if (m_timer)
+      m_timer->pop (m_tv);
   }
 
  private:
@@ -214,6 +240,7 @@ class auto_timevar
   // Private to disallow copies.
   auto_timevar (const auto_timevar &);
 
+  timer *m_timer;
   timevar_id_t m_tv;
 };
 
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 1bacb68..0b0c7f1 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1781,7 +1781,7 @@ static int rtl_initialized;
 void
 initialize_rtl (void)
 {
-  auto_timevar tv (TV_INITIALIZE_RTL);
+  auto_timevar tv (g_timer, TV_INITIALIZE_RTL);
 
   /* Initialization done just once per compilation, but delayed
      till code generation.  */
@@ -2054,23 +2054,29 @@ do_compile ()
     }
 }
 
-toplev::toplev (bool use_TV_TOTAL, bool init_signals)
-  : m_use_TV_TOTAL (use_TV_TOTAL),
+toplev::toplev (timer *external_timer,
+		bool init_signals)
+  : m_use_TV_TOTAL (external_timer == NULL),
     m_init_signals (init_signals)
 {
-  if (!m_use_TV_TOTAL)
-    start_timevars ();
+  if (external_timer)
+    g_timer = external_timer;
 }
 
 toplev::~toplev ()
 {
-  if (g_timer)
+  if (g_timer && m_use_TV_TOTAL)
     {
       g_timer->stop (TV_TOTAL);
       g_timer->print (stderr);
+      delete g_timer;
+      g_timer = NULL;
     }
 }
 
+/* Potentially call timevar_init (which will create g_timevars if it
+   doesn't already exist).  */
+
 void
 toplev::start_timevars ()
 {
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 3bddcbb..21d9a75 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -24,11 +24,13 @@ along with GCC; see the file COPYING3.  If not see
 extern struct cl_decoded_option *save_decoded_options;
 extern unsigned int save_decoded_options_count;
 
+class timer;
+
 /* Invoking the compiler.  */
 class toplev
 {
 public:
-  toplev (bool use_TV_TOTAL,
+  toplev (timer *external_timer,
 	  bool init_signals);
   ~toplev ();
 
-- 
1.8.5.3


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