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 01/16] gcc: Generalization of timevar API; add gcc_jit_timer interface


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

This followup patch generalizes the timing within toplev so that an
external "timer" instance can be passed in, and then exposes this
from libgccjit via an API 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.

It uses this API within jit.dg/test-benchmark.c to accumulate timings,
comparing the different optimization levels.  For example, in one run,
the output indicated:
  ./test-benchmark.c.exe: 100 iterations
    at optlevel 0 took a total of 6.370s (0.064s per iteration)
    at optlevel 1 took a total of 7.050s (0.071s per iteration)
    at optlevel 2 took a total of 7.260s (0.073s per iteration)
    at optlevel 3 took a total of 9.070s (0.091s per iteration)
with detailed timings being emitted for each optlevel.

Further patches in this kit speed this up dramatically, and use the
named items API in other ways.

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.

ABI note: this extends the libgccjit API for the first time since GCC 5;
should there be a SONAME bump?  Is there a better way of managing this
(e.g. via a linker script) to avoid invalidating binaries compiled
against previous versions of the library?

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.
	* 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::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/jit/ChangeLog:
	* docs/topics/contexts.rst (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY):
	We no longer show a profile.
	* docs/topics/index.rst (Topic Reference): Add performance.rst.
	* docs/topics/performance.rst: New file.
	* jit-playback.c (gcc::jit::playback::context::compile): Add timer
	param when constructing the "toplev" instance.
	(gcc::jit::playback::context::acquire_mutex): Add timer param when
	constructing auto_timevar instance.
	(gcc::jit::playback::context::make_fake_args): If we have a timer,
	add "-ftime-report".
	(gcc::jit::playback::context::invoke_driver): Add timer param when
	constructing auto_timevar instance.
	(gcc::jit::playback::context::dlopen_built_dso): Likewise.
	* jit-playback.h (gcc::jit::playback::context::get_timer): New accessor.
	* jit-recording.c: Include timevar.h.
	(gcc::jit::recording::context::context): Initialize field "m_timer".
	* jit-recording.h: Add forward declaration of class timer.
	(gcc::jit::recording::context::set_timer): New method.
	(gcc::jit::recording::context::get_timer): New method.
	(gcc::jit::recording::context::m_timer): New field.
	* libgccjit++.h (gccjit::timer): New class.
	(gccjit::auto_time): New class.
	(gccjit::context::set_timer): New method.
	(gccjit::context::get_timer): New.
	(gccjit::timer::timer): New.
	(gccjit::timer::push): New.
	(gccjit::timer::pop): New.
	(timer::print): New.
	(timer::get_inner_timer): New.
	(timer::release): New.
	(auto_time::auto_time): New.
	(auto_time::~auto_time): New.
	* libgccjit.c: Include timevar.h.
	(struct gcc_jit_timer): New.
	(gcc_jit_timer_new): New function.
	(gcc_jit_timer_release): New function.
	(gcc_jit_context_set_timer): New function.
	(gcc_jit_context_get_timer): New function.
	(gcc_jit_timer_push): New function.
	(gcc_jit_timer_pop): New function.
	(gcc_jit_timer_print): New function.
	* libgccjit.h (LIBGCCJIT_HAS_FEATURE_gcc_jit_timer): New macro.
	(gcc_jit_timer): New typedef.
	(gcc_jit_timer_new): New function.
	(gcc_jit_timer_release): New function.
	(gcc_jit_context_set_timer): New function.
	(gcc_jit_context_get_timer): New function.
	(gcc_jit_timer_push): New function.
	(gcc_jit_timer_pop): New function.
	(gcc_jit_timer_print): New function.
	* libgccjit.map (gcc_jit_timer_new): New function.
	(gcc_jit_timer_release): New function.
	(gcc_jit_context_set_timer): New function.
	(gcc_jit_context_get_timer): New function.
	(gcc_jit_timer_push): New function.
	(gcc_jit_timer_pop): New function.
	(gcc_jit_timer_print): New function.

gcc/testsuite/ChangeLog:
	* jit.dg/test-benchmark.c (test_jit): Add param "timer" and use
	it to push/pop timing items.
	(main): For each optimization level, create a gcc_jit_timer, and
	time all of the iteration within that level cumulatively.
---
 gcc/jit/docs/topics/contexts.rst      |   3 +-
 gcc/jit/docs/topics/index.rst         |   1 +
 gcc/jit/docs/topics/performance.rst   | 208 ++++++++++++++++++++++++++++++
 gcc/jit/jit-playback.c                |  11 +-
 gcc/jit/jit-playback.h                |   2 +
 gcc/jit/jit-recording.c               |   2 +
 gcc/jit/jit-recording.h               |   7 +
 gcc/jit/libgccjit++.h                 | 114 ++++++++++++++++
 gcc/jit/libgccjit.c                   |  90 +++++++++++++
 gcc/jit/libgccjit.h                   |  51 ++++++++
 gcc/jit/libgccjit.map                 |   7 +
 gcc/main.c                            |   2 +-
 gcc/testsuite/jit.dg/test-benchmark.c |  20 ++-
 gcc/timevar.c                         | 236 +++++++++++++++++++++++++++++-----
 gcc/timevar.def                       |   2 +
 gcc/timevar.h                         |  33 ++++-
 gcc/toplev.c                          |  18 ++-
 gcc/toplev.h                          |   4 +-
 18 files changed, 757 insertions(+), 54 deletions(-)
 create mode 100644 gcc/jit/docs/topics/performance.rst

diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst
index b7f281a..afa51a9 100644
--- a/gcc/jit/docs/topics/contexts.rst
+++ b/gcc/jit/docs/topics/contexts.rst
@@ -417,8 +417,7 @@ Boolean options
   .. macro:: GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
 
      If true, :func:`gcc_jit_context_compile` will print information to stderr
-     on the actions it is performing, followed by a profile showing
-     the time taken and memory usage of each phase.
+     on the actions it is performing.
 
   .. macro:: GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
 
diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst
index 4ebb623..b221e40 100644
--- a/gcc/jit/docs/topics/index.rst
+++ b/gcc/jit/docs/topics/index.rst
@@ -28,3 +28,4 @@ Topic Reference
    functions.rst
    locations.rst
    compilation.rst
+   performance.rst
diff --git a/gcc/jit/docs/topics/performance.rst b/gcc/jit/docs/topics/performance.rst
new file mode 100644
index 0000000..b7de28e
--- /dev/null
+++ b/gcc/jit/docs/topics/performance.rst
@@ -0,0 +1,208 @@
+.. Copyright (C) 2015 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This 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, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Performance
+===========
+
+The timing API
+--------------
+
+As of GCC 6, libgccjit exposes a timing API, for printing reports on
+how long was spent in different parts of code.
+
+You can create a :c:type:`gcc_jit_timer` instance, which will
+measure time spent since its creation.  The timer maintains a stack
+of "timer items": as control flow moves through your code, you can push
+and pop named items relating to your code onto the stack, and the timer
+will account the time spent accordingly.
+
+You can also asssociate a timer with a :c:type:`gcc_jit_context`, in
+which case the time spent inside compilation will be subdivided.
+
+For example, the following code uses a timer, recording client items
+"create_code", "compile", and "running code":
+
+.. code-block:: c
+
+  /* Create a timer.  */
+  gcc_jit_timer *timer = gcc_jit_timer_new ();
+  if (!timer)
+    {
+       error ("gcc_jit_timer_new failed");
+       return -1;
+    }
+
+  /* Let's repeatedly compile and run some code, accumulating it
+     all into the timer.  */
+  for (int i = 0; i < num_iterations; i++)
+    {
+      /* Create a context and associate it with the timer.  */
+      gcc_jit_context *ctxt = gcc_jit_context_acquire ();
+      if (!ctxt)
+        {
+          error ("gcc_jit_context_acquire failed");
+          return -1;
+        }
+      gcc_jit_context_set_timer (ctxt, timer);
+
+      /* Populate the context, timing it as client item "create_code".  */
+      gcc_jit_timer_push (timer, "create_code");
+      create_code (ctxt);
+      gcc_jit_timer_pop (timer);
+
+      /* Compile the context, timing it as client item "compile".  */
+      gcc_jit_timer_push (timer, "compile");
+      result = gcc_jit_context_compile (ctxt);
+      gcc_jit_timer_pop (timer);
+
+      /* Run the generated code, timing it as client item "running code".  */
+      gcc_jit_timer_push (timer, "running code");
+      run_the_code (ctxt, result);
+      gcc_jit_timer_pop (timer);
+
+      /* Clean up.  */
+      gcc_jit_context_release (ctxt);
+      gcc_jit_result_release (result);
+  }
+
+  /* Print the accumulated timings.  */
+  gcc_jit_timer_print (timer, stderr);
+  gcc_jit_timer_release (timer);
+
+giving output like this, showing the internal GCC items at the top, then
+client items, then the total::
+
+  Execution times (seconds)
+  GCC items:
+   phase setup             :   0.29 (14%) usr   0.00 ( 0%) sys   0.32 ( 5%) wall   10661 kB (50%) ggc
+   phase parsing           :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     653 kB ( 3%) ggc
+   phase finalize          :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   dump files              :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall       0 kB ( 0%) ggc
+   callgraph construction  :   0.02 ( 1%) usr   0.01 ( 6%) sys   0.01 ( 0%) wall     242 kB ( 1%) ggc
+   callgraph optimization  :   0.03 ( 2%) usr   0.00 ( 0%) sys   0.02 ( 0%) wall     142 kB ( 1%) ggc
+   trivially dead code     :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   df scan insns           :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       9 kB ( 0%) ggc
+   df live regs            :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall       0 kB ( 0%) ggc
+   inline parameters       :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall      82 kB ( 0%) ggc
+   tree CFG cleanup        :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   tree PHI insertion      :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.02 ( 0%) wall      64 kB ( 0%) ggc
+   tree SSA other          :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall      18 kB ( 0%) ggc
+   expand                  :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     398 kB ( 2%) ggc
+   jump                    :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   loop init               :   0.01 ( 0%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall      67 kB ( 0%) ggc
+   integrated RA           :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall    2468 kB (12%) ggc
+   thread pro- & epilogue  :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     162 kB ( 1%) ggc
+   final                   :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     216 kB ( 1%) ggc
+   rest of compilation     :   1.37 (69%) usr   0.00 ( 0%) sys   1.13 (18%) wall    1391 kB ( 6%) ggc
+   assemble JIT code       :   0.01 ( 1%) usr   0.00 ( 0%) sys   4.04 (66%) wall       0 kB ( 0%) ggc
+   load JIT result         :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   JIT client code         :   0.00 ( 0%) usr   0.01 ( 6%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+  Client items:
+   create_code             :   0.00 ( 0%) usr   0.01 ( 6%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   compile                 :   0.36 (18%) usr   0.15 (83%) sys   0.86 (14%) wall   14939 kB (70%) ggc
+   running code            :   0.00 ( 0%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
+   TOTAL                   :   2.00             0.18             6.12              21444 kB
+
+The exact format is intended to be human-readable, and is subject to change.
+
+.. macro:: LIBGCCJIT_HAS_FEATURE_gcc_jit_timer
+
+   The timer API was added to libgccjit in GCC 6.
+   This macro is only defined in versions of libgccjit.h which have the
+   timer API, and so can be used to guard code that may need to compile
+   against earlier releases::
+
+     #ifdef LIBGCCJIT_HAS_FEATURE_gcc_jit_timer
+     gcc_jit_timer *t = gcc_jit_timer_new ();
+     gcc_jit_context_set_timer (ctxt, t);
+     #endif
+
+.. type:: gcc_jit_timer
+
+.. function:: gcc_jit_timer * gcc_jit_timer_new(void)
+
+   Create a :c:type:`gcc_jit_timer` instance, and start timing::
+
+     gcc_jit_timer *t = gcc_jit_timer_new ();
+
+   .. versionadded:: 6
+      See :macro:`LIBGCCJIT_HAS_FEATURE_gcc_jit_timer`.
+
+.. function:: void gcc_jit_timer_release(gcc_jit_timer *timer)
+
+   Release a :c:type:`gcc_jit_timer` instance::
+
+     gcc_jit_timer_release (t);
+
+   This should be called exactly once on a timer.
+
+   .. versionadded:: 6
+      See :macro:`LIBGCCJIT_HAS_FEATURE_gcc_jit_timer`.
+
+.. function:: void gcc_jit_context_set_timer(gcc_jit_context *ctxt, \
+                                             gcc_jit_timer *timer)
+
+   Associate a :c:type:`gcc_jit_timer` instance with a context::
+
+      gcc_jit_context_set_timer (ctxt, t);
+
+   A timer instance can be shared between multiple
+   :c:type:`gcc_jit_context` instances.
+
+   Timers have no locking, so if you have a multithreaded program, you
+   must provide your own locks if more than one thread could be working
+   with the same timer via timer-associated contexts.
+
+   .. versionadded:: 6
+      See :macro:`LIBGCCJIT_HAS_FEATURE_gcc_jit_timer`.
+
+.. function:: gcc_jit_timer *gcc_jit_context_get_timer(gcc_jit_context *ctxt)
+
+   Get the timer associated with a context (if any).
+
+   .. versionadded:: 6
+      See :macro:`LIBGCCJIT_HAS_FEATURE_gcc_jit_timer`.
+
+.. function:: void gcc_jit_timer_push(gcc_jit_timer *timer, \
+                                      const char *item_name)
+
+   Push the given item onto the timer's stack::
+
+      gcc_jit_timer_push (t, "running code");
+      run_the_code (ctxt, result);
+      gcc_jit_timer_pop (t);
+
+   .. versionadded:: 6
+      See :macro:`LIBGCCJIT_HAS_FEATURE_gcc_jit_timer`.
+
+.. function:: void gcc_jit_timer_pop(gcc_jit_timer *timer)
+
+   Pop the top item from the timer's stack.
+
+   .. versionadded:: 6
+      See :macro:`LIBGCCJIT_HAS_FEATURE_gcc_jit_timer`.
+
+.. function:: void gcc_jit_timer_print(gcc_jit_timer *timer, \
+                                       FILE *f_out)
+
+   Print timing information to the given stream about activity since
+   the timer was started.
+
+   .. versionadded:: 6
+      See :macro:`LIBGCCJIT_HAS_FEATURE_gcc_jit_timer`.
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index c75c076..7a3b7f7 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -1727,7 +1727,7 @@ compile ()
     }
 
   /* This runs the compiler.  */
-  toplev toplev (false, /* use_TV_TOTAL */
+  toplev toplev (get_timer (), /* external_timer */
 		 false); /* init_signals */
   enter_scope ("toplev::main");
   if (get_logger ())
@@ -2019,6 +2019,8 @@ static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
 void
 playback::context::acquire_mutex ()
 {
+  auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
+
   /* Acquire the big GCC mutex. */
   JIT_LOG_SCOPE (get_logger ());
   pthread_mutex_lock (&jit_mutex);
@@ -2186,6 +2188,9 @@ make_fake_args (vec <char *> *argvec,
       }
   }
 
+  if (get_timer ())
+    ADD_ARG ("-ftime-report");
+
 #undef ADD_ARG
 #undef ADD_ARG_TAKE_OWNERSHIP
 }
@@ -2310,7 +2315,7 @@ invoke_driver (const char *ctxt_progname,
   JIT_LOG_SCOPE (get_logger ());
   /* Currently this lumps together both assembling and linking into
      TV_ASSEMBLE.  */
-  auto_timevar assemble_timevar (tv_id);
+  auto_timevar assemble_timevar (get_timer (), tv_id);
   const char *errmsg;
   auto_vec <const char *> argvec;
 #define ADD_ARG(arg) argvec.safe_push (arg)
@@ -2390,7 +2395,7 @@ playback::context::
 dlopen_built_dso ()
 {
   JIT_LOG_SCOPE (get_logger ());
-  auto_timevar load_timevar (TV_LOAD);
+  auto_timevar load_timevar (get_timer (), TV_LOAD);
   void *handle = NULL;
   const char *error = NULL;
   result *result_obj = NULL;
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index e9832f0..afe0068 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -219,6 +219,8 @@ public:
   void write_global_decls_1 ();
   void write_global_decls_2 ();
 
+  timer *get_timer () const { return m_recording_ctxt->get_timer (); }
+
 private:
   void dump_generated_code ();
 
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 32d7f31..79a22e8 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "pretty-print.h"
 #include "hash-map.h"
 #include "toplev.h"
+#include "timevar.h"
 
 #include <pthread.h>
 
@@ -461,6 +462,7 @@ recording::context::context (context *parent_ctxt)
   : log_user (NULL),
     m_parent_ctxt (parent_ctxt),
     m_toplevel_ctxt (m_parent_ctxt ? m_parent_ctxt->m_toplevel_ctxt : this),
+    m_timer (NULL),
     m_error_count (0),
     m_first_error_str (NULL),
     m_owns_first_error_str (false),
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 439e7ce..19969d5 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -24,6 +24,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "jit-common.h"
 #include "jit-logging.h"
 
+class timer;
+
 namespace gcc {
 
 namespace jit {
@@ -255,6 +257,9 @@ public:
   void
   get_all_requested_dumps (vec <recording::requested_dump> *out);
 
+  void set_timer (timer *t) { m_timer = t; }
+  timer *get_timer () const { return m_timer; }
+
 private:
   void log_all_options () const;
   void log_str_option (enum gcc_jit_str_option opt) const;
@@ -270,6 +275,8 @@ private:
      contexts.  This has itself as its own m_toplevel_ctxt.  */
   context *m_toplevel_ctxt;
 
+  timer *m_timer;
+
   int m_error_count;
 
   char *m_first_error_str;
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 62ef6a4..c100eb4 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -45,6 +45,8 @@ namespace gccjit
     class rvalue;
      class lvalue;
        class param;
+  class timer;
+  class auto_time;
 
   /* Errors within the API become C++ exceptions of this class.  */
   class error
@@ -120,6 +122,9 @@ namespace gccjit
     void set_bool_option (enum gcc_jit_bool_option opt,
 			  int value);
 
+    void set_timer (gccjit::timer t);
+    gccjit::timer get_timer () const;
+
     location
     new_location (const std::string &filename,
 		  int line,
@@ -502,6 +507,35 @@ namespace gccjit
 
   /* Dereferencing. */
   lvalue operator* (rvalue ptr);
+
+  class timer
+  {
+  public:
+    timer ();
+    timer (gcc_jit_timer *inner_timer);
+
+    void push (const char *item_name);
+    void pop ();
+    void print (FILE *f_out) const;
+
+    void release ();
+
+    gcc_jit_timer *get_inner_timer () const;
+
+  private:
+    gcc_jit_timer *m_inner_timer;
+  };
+
+  class auto_time
+  {
+  public:
+    auto_time (timer t, const char *item_name);
+    auto_time (context ctxt, const char *item_name);
+    ~auto_time ();
+
+  private:
+    timer m_timer;
+  };
 }
 
 /****************************************************************************
@@ -603,6 +637,19 @@ context::set_bool_option (enum gcc_jit_bool_option opt,
 
 }
 
+inline void
+context::set_timer (gccjit::timer t)
+{
+  gcc_jit_context_set_timer (m_inner_ctxt, t.get_inner_timer ());
+}
+
+inline gccjit::timer
+context::get_timer () const
+{
+  return gccjit::timer (gcc_jit_context_get_timer (m_inner_ctxt));
+}
+
+
 inline location
 context::new_location (const std::string &filename,
 		       int line,
@@ -1634,6 +1681,73 @@ inline lvalue operator* (rvalue ptr)
   return ptr.dereference ();
 }
 
+// class timer
+inline
+timer::timer ()
+{
+  m_inner_timer = gcc_jit_timer_new ();
+}
+
+inline
+timer::timer (gcc_jit_timer *inner_timer)
+{
+  m_inner_timer = inner_timer;
+}
+
+inline void
+timer::push (const char *item_name)
+{
+  gcc_jit_timer_push (m_inner_timer, item_name);
+
+}
+
+inline void
+timer::pop ()
+{
+  gcc_jit_timer_pop (m_inner_timer);
+}
+
+inline void
+timer::print (FILE *f_out) const
+{
+  gcc_jit_timer_print (m_inner_timer, f_out);
+}
+
+inline gcc_jit_timer *
+timer::get_inner_timer () const
+{
+  return m_inner_timer;
+}
+
+inline void
+timer::release ()
+{
+  gcc_jit_timer_release (m_inner_timer);
+  m_inner_timer = NULL;
+}
+
+// class auto_time
+
+inline
+auto_time::auto_time (timer t, const char *item_name)
+  : m_timer (t)
+{
+  t.push (item_name);
+}
+
+inline
+auto_time::auto_time (context ctxt, const char *item_name)
+  : m_timer (ctxt.get_timer ())
+{
+  m_timer.push (item_name);
+}
+
+inline
+auto_time::~auto_time ()
+{
+  m_timer.pop ();
+}
+
 } // namespace gccjit
 
 #endif /* #ifndef LIBGCCJIT_PLUS_PLUS_H */
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 7eb66bd..2a67ef7 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "opts.h"
 #include "safe-ctype.h"
+#include "timevar.h"
 
 #include "libgccjit.h"
 #include "jit-common.h"
@@ -84,6 +85,10 @@ struct gcc_jit_param : public gcc::jit::recording::param
 {
 };
 
+struct gcc_jit_timer : public timer
+{
+};
+
 /**********************************************************************
  Error-handling.
 
@@ -2370,3 +2375,88 @@ gcc_jit_result_release (gcc_jit_result *result)
   result->log ("deleting result: %p", (void *)result);
   delete result;
 }
+
+/**********************************************************************
+ Timing support.
+ **********************************************************************/
+
+/* Create a gcc_jit_timer instance, and start timing.  */
+
+gcc_jit_timer *
+gcc_jit_timer_new (void)
+{
+  gcc_jit_timer *timer = new gcc_jit_timer ();
+  timer->start (TV_TOTAL);
+  timer->push (TV_JIT_CLIENT_CODE);
+  return timer;
+}
+
+/* Release a gcc_jit_timer instance.  */
+
+void
+gcc_jit_timer_release (gcc_jit_timer *timer)
+{
+  RETURN_IF_FAIL (timer, NULL, NULL, "NULL timer");
+
+  delete timer;
+}
+
+/* Associate a gcc_jit_timer instance with a context.  */
+
+void
+gcc_jit_context_set_timer (gcc_jit_context *ctxt,
+			   gcc_jit_timer *timer)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL ctxt");
+  RETURN_IF_FAIL (timer, ctxt, NULL, "NULL timer");
+
+  ctxt->set_timer (timer);
+}
+
+/* Get the timer associated with a context (if any).  */
+
+gcc_jit_timer *
+gcc_jit_context_get_timer (gcc_jit_context *ctxt)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL ctxt");
+
+  return (gcc_jit_timer *)ctxt->get_timer ();
+}
+
+/* Push the given item onto the timing stack.  */
+
+void
+gcc_jit_timer_push (gcc_jit_timer *timer,
+		    const char *item_name)
+{
+  RETURN_IF_FAIL (timer, NULL, NULL, "NULL timer");
+  RETURN_IF_FAIL (item_name, NULL, NULL, "NULL item_name");
+  timer->push_client_item (item_name);
+}
+
+/* Pop the top item from the timing stack.  */
+
+void
+gcc_jit_timer_pop (gcc_jit_timer *timer)
+{
+  RETURN_IF_FAIL (timer, NULL, NULL, "NULL timer");
+  /* FIXME: mismatching item? */
+  timer->pop_client_item ();
+}
+
+/* Print timing information to the given stream about activity since
+   the timer was started.  */
+
+void
+gcc_jit_timer_print (gcc_jit_timer *timer,
+		     FILE *f_out)
+{
+  RETURN_IF_FAIL (timer, NULL, NULL, "NULL timer");
+  RETURN_IF_FAIL (f_out, NULL, NULL, "NULL f_out");
+
+  timer->pop (TV_JIT_CLIENT_CODE);
+  timer->stop (TV_TOTAL);
+  timer->print (f_out);
+  timer->start (TV_TOTAL);
+  timer->push (TV_JIT_CLIENT_CODE);
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 8f4354e..cfae293 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1133,6 +1133,57 @@ gcc_jit_context_enable_dump (gcc_jit_context *ctxt,
 			     const char *dumpname,
 			     char **out_ptr);
 
+/**********************************************************************
+ Timing support.
+ **********************************************************************/
+
+/* The timer API was added to libgccjit in GCC 6.
+   This macro is only defined in versions of libgccjit.h which have the
+   timer API, and so can be used to guard code that may need to compile
+   against earlier releases.*/
+#define LIBGCCJIT_HAS_FEATURE_gcc_jit_timer
+
+typedef struct gcc_jit_timer gcc_jit_timer;
+
+/* Create a gcc_jit_timer instance, and start timing.  */
+
+extern gcc_jit_timer *
+gcc_jit_timer_new (void);
+
+/* Release a gcc_jit_timer instance.  */
+
+extern void
+gcc_jit_timer_release (gcc_jit_timer *timer);
+
+/* Associate a gcc_jit_timer instance with a context.  */
+
+extern void
+gcc_jit_context_set_timer (gcc_jit_context *ctxt,
+			   gcc_jit_timer *timer);
+
+/* Get the timer associated with a context (if any).  */
+
+extern gcc_jit_timer *
+gcc_jit_context_get_timer (gcc_jit_context *ctxt);
+
+/* Push the given item onto the timing stack.  */
+
+extern void
+gcc_jit_timer_push (gcc_jit_timer *timer,
+		    const char *item_name);
+
+/* Pop the top item from the timing stack.  */
+
+extern void
+gcc_jit_timer_pop (gcc_jit_timer *timer);
+
+/* Print timing information to the given stream about activity since
+   the timer was started.  */
+
+extern void
+gcc_jit_timer_print (gcc_jit_timer *timer,
+		     FILE *f_out);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 89bd57be4..1733b94 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -39,6 +39,7 @@
     gcc_jit_context_get_builtin_function;
     gcc_jit_context_get_first_error;
     gcc_jit_context_get_last_error;
+    gcc_jit_context_get_timer;
     gcc_jit_context_get_type;
     gcc_jit_context_get_int_type;
     gcc_jit_context_new_array_access;
@@ -71,6 +72,7 @@
     gcc_jit_context_set_int_option;
     gcc_jit_context_set_logfile;
     gcc_jit_context_set_str_option;
+    gcc_jit_context_set_timer;
     gcc_jit_context_zero;
     gcc_jit_field_as_object;
     gcc_jit_function_as_object;
@@ -98,6 +100,11 @@
     gcc_jit_rvalue_get_type;
     gcc_jit_struct_as_type;
     gcc_jit_struct_set_fields;
+    gcc_jit_timer_new;
+    gcc_jit_timer_release;
+    gcc_jit_timer_push;
+    gcc_jit_timer_pop;
+    gcc_jit_timer_print;
     gcc_jit_type_as_object;
     gcc_jit_type_get_const;
     gcc_jit_type_get_pointer;
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/testsuite/jit.dg/test-benchmark.c b/gcc/testsuite/jit.dg/test-benchmark.c
index 324ba93..7e330de 100644
--- a/gcc/testsuite/jit.dg/test-benchmark.c
+++ b/gcc/testsuite/jit.dg/test-benchmark.c
@@ -141,11 +141,13 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
 
 /* Run one iteration of the test.  */
 static void
-test_jit (const char *argv0, int opt_level)
+test_jit (const char *argv0, int opt_level, gcc_jit_timer *timer)
 {
   gcc_jit_context *ctxt;
   gcc_jit_result *result;
 
+  gcc_jit_timer_push (timer, "test_jit");
+
   ctxt = gcc_jit_context_acquire ();
   if (!ctxt)
     {
@@ -153,6 +155,8 @@ test_jit (const char *argv0, int opt_level)
       return;
     }
 
+  gcc_jit_context_set_timer (ctxt, timer);
+
   /* Set up options.  */
   gcc_jit_context_set_str_option (
     ctxt,
@@ -182,13 +186,22 @@ test_jit (const char *argv0, int opt_level)
       GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
       1);
 
+  gcc_jit_timer_push (timer, "create_code");
   create_code (ctxt, NULL);
+  gcc_jit_timer_pop (timer);
 
+  gcc_jit_timer_push (timer, "compile");
   result = gcc_jit_context_compile (ctxt);
+  gcc_jit_timer_pop (timer);
+
+  gcc_jit_timer_push (timer, "verify_code");
   verify_code (ctxt, result);
+  gcc_jit_timer_pop (timer);
 
   gcc_jit_context_release (ctxt);
   gcc_jit_result_release (result);
+
+  gcc_jit_timer_pop (timer);
 }
 
 /* Taken from timevar.c.  */
@@ -217,16 +230,19 @@ main (int argc, char **argv)
       int i;
       double start_time, end_time, elapsed_time;
       start_time = get_wallclock_time ();
+      gcc_jit_timer *timer = gcc_jit_timer_new ();
       for (i = 1; i <= num_iterations; i++)
 	{
 	  snprintf (test, sizeof (test),
 		    "%s iteration %d of %d",
 		    extract_progname (argv[0]),
 		    i, num_iterations);
-	  test_jit (argv[0], opt_level);
+	  test_jit (argv[0], opt_level, timer);
 	}
       end_time = get_wallclock_time ();
       elapsed_time = end_time - start_time;
+      gcc_jit_timer_print (timer, stderr);
+      gcc_jit_timer_release (timer);
       pass ("%s: survived %i iterations at optlevel %i",
 	    argv[0], num_iterations, opt_level);
       note (("%s: %i iterations at optlevel %i"
diff --git a/gcc/timevar.c b/gcc/timevar.c
index 76ad22a..9bc62e6 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);
diff --git a/gcc/timevar.def b/gcc/timevar.def
index cf8f37d..905b469 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -289,3 +289,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..d46dc88 100644
--- a/gcc/timevar.h
+++ b/gcc/timevar.h
@@ -115,12 +115,22 @@ 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);
 
  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 +167,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 +192,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 +219,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 +238,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 54eefcd..3527b5d 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1818,7 +1818,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.  */
@@ -2090,23 +2090,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 9527f76..4b3748b 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]