1.. Copyright (C) 2015-2018 Free Software Foundation, Inc.
2   Originally contributed by David Malcolm <dmalcolm@redhat.com>
3
4   This is free software: you can redistribute it and/or modify it
5   under the terms of the GNU General Public License as published by
6   the Free Software Foundation, either version 3 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see
16   <http://www.gnu.org/licenses/>.
17
18.. default-domain:: c
19
20Performance
21===========
22
23The timing API
24--------------
25
26As of GCC 6, libgccjit exposes a timing API, for printing reports on
27how long was spent in different parts of code.
28
29You can create a :c:type:`gcc_jit_timer` instance, which will
30measure time spent since its creation.  The timer maintains a stack
31of "timer items": as control flow moves through your code, you can push
32and pop named items relating to your code onto the stack, and the timer
33will account the time spent accordingly.
34
35You can also asssociate a timer with a :c:type:`gcc_jit_context`, in
36which case the time spent inside compilation will be subdivided.
37
38For example, the following code uses a timer, recording client items
39"create_code", "compile", and "running code":
40
41.. code-block:: c
42
43  /* Create a timer.  */
44  gcc_jit_timer *timer = gcc_jit_timer_new ();
45  if (!timer)
46    {
47       error ("gcc_jit_timer_new failed");
48       return -1;
49    }
50
51  /* Let's repeatedly compile and run some code, accumulating it
52     all into the timer.  */
53  for (int i = 0; i < num_iterations; i++)
54    {
55      /* Create a context and associate it with the timer.  */
56      gcc_jit_context *ctxt = gcc_jit_context_acquire ();
57      if (!ctxt)
58        {
59          error ("gcc_jit_context_acquire failed");
60          return -1;
61        }
62      gcc_jit_context_set_timer (ctxt, timer);
63
64      /* Populate the context, timing it as client item "create_code".  */
65      gcc_jit_timer_push (timer, "create_code");
66      create_code (ctxt);
67      gcc_jit_timer_pop (timer, "create_code");
68
69      /* Compile the context, timing it as client item "compile".  */
70      gcc_jit_timer_push (timer, "compile");
71      result = gcc_jit_context_compile (ctxt);
72      gcc_jit_timer_pop (timer, "compile");
73
74      /* Run the generated code, timing it as client item "running code".  */
75      gcc_jit_timer_push (timer, "running code");
76      run_the_code (ctxt, result);
77      gcc_jit_timer_pop (timer, "running code");
78
79      /* Clean up.  */
80      gcc_jit_context_release (ctxt);
81      gcc_jit_result_release (result);
82  }
83
84  /* Print the accumulated timings.  */
85  gcc_jit_timer_print (timer, stderr);
86  gcc_jit_timer_release (timer);
87
88giving output like this, showing the internal GCC items at the top, then
89client items, then the total::
90
91  Execution times (seconds)
92  GCC items:
93   phase setup             :   0.29 (14%) usr   0.00 ( 0%) sys   0.32 ( 5%) wall   10661 kB (50%) ggc
94   phase parsing           :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     653 kB ( 3%) ggc
95   phase finalize          :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
96   dump files              :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall       0 kB ( 0%) ggc
97   callgraph construction  :   0.02 ( 1%) usr   0.01 ( 6%) sys   0.01 ( 0%) wall     242 kB ( 1%) ggc
98   callgraph optimization  :   0.03 ( 2%) usr   0.00 ( 0%) sys   0.02 ( 0%) wall     142 kB ( 1%) ggc
99   trivially dead code     :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
100   df scan insns           :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       9 kB ( 0%) ggc
101   df live regs            :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall       0 kB ( 0%) ggc
102   inline parameters       :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall      82 kB ( 0%) ggc
103   tree CFG cleanup        :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
104   tree PHI insertion      :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.02 ( 0%) wall      64 kB ( 0%) ggc
105   tree SSA other          :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.01 ( 0%) wall      18 kB ( 0%) ggc
106   expand                  :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     398 kB ( 2%) ggc
107   jump                    :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
108   loop init               :   0.01 ( 0%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall      67 kB ( 0%) ggc
109   integrated RA           :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall    2468 kB (12%) ggc
110   thread pro- & epilogue  :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     162 kB ( 1%) ggc
111   final                   :   0.01 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall     216 kB ( 1%) ggc
112   rest of compilation     :   1.37 (69%) usr   0.00 ( 0%) sys   1.13 (18%) wall    1391 kB ( 6%) ggc
113   assemble JIT code       :   0.01 ( 1%) usr   0.00 ( 0%) sys   4.04 (66%) wall       0 kB ( 0%) ggc
114   load JIT result         :   0.02 ( 1%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
115   JIT client code         :   0.00 ( 0%) usr   0.01 ( 6%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
116  Client items:
117   create_code             :   0.00 ( 0%) usr   0.01 ( 6%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
118   compile                 :   0.36 (18%) usr   0.15 (83%) sys   0.86 (14%) wall   14939 kB (70%) ggc
119   running code            :   0.00 ( 0%) usr   0.00 ( 0%) sys   0.00 ( 0%) wall       0 kB ( 0%) ggc
120   TOTAL                   :   2.00             0.18             6.12              21444 kB
121
122The exact format is intended to be human-readable, and is subject to change.
123
124.. macro:: LIBGCCJIT_HAVE_TIMING_API
125
126   The timer API was added to libgccjit in GCC 6.
127   This macro is only defined in versions of libgccjit.h which have the
128   timer API, and so can be used to guard code that may need to compile
129   against earlier releases::
130
131     #ifdef LIBGCCJIT_HAVE_TIMING_API
132     gcc_jit_timer *t = gcc_jit_timer_new ();
133     gcc_jit_context_set_timer (ctxt, t);
134     #endif
135
136.. type:: gcc_jit_timer
137
138.. function:: gcc_jit_timer * gcc_jit_timer_new(void)
139
140   Create a :c:type:`gcc_jit_timer` instance, and start timing::
141
142     gcc_jit_timer *t = gcc_jit_timer_new ();
143
144   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
145   for its presence using
146
147   .. code-block:: c
148
149     #ifdef LIBGCCJIT_HAVE_TIMING_API
150
151.. function:: void gcc_jit_timer_release(gcc_jit_timer *timer)
152
153   Release a :c:type:`gcc_jit_timer` instance::
154
155     gcc_jit_timer_release (t);
156
157   This should be called exactly once on a timer.
158
159   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
160   for its presence using
161
162   .. code-block:: c
163
164     #ifdef LIBGCCJIT_HAVE_TIMING_API
165
166.. function:: void gcc_jit_context_set_timer(gcc_jit_context *ctxt, \
167                                             gcc_jit_timer *timer)
168
169   Associate a :c:type:`gcc_jit_timer` instance with a context::
170
171      gcc_jit_context_set_timer (ctxt, t);
172
173   A timer instance can be shared between multiple
174   :c:type:`gcc_jit_context` instances.
175
176   Timers have no locking, so if you have a multithreaded program, you
177   must provide your own locks if more than one thread could be working
178   with the same timer via timer-associated contexts.
179
180   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
181   for its presence using
182
183   .. code-block:: c
184
185     #ifdef LIBGCCJIT_HAVE_TIMING_API
186
187.. function:: gcc_jit_timer *gcc_jit_context_get_timer(gcc_jit_context *ctxt)
188
189   Get the timer associated with a context (if any).
190
191   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
192   for its presence using
193
194   .. code-block:: c
195
196     #ifdef LIBGCCJIT_HAVE_TIMING_API
197
198.. function:: void gcc_jit_timer_push(gcc_jit_timer *timer, \
199                                      const char *item_name)
200
201   Push the given item onto the timer's stack::
202
203      gcc_jit_timer_push (t, "running code");
204      run_the_code (ctxt, result);
205      gcc_jit_timer_pop (t, "running code");
206
207   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
208   for its presence using
209
210   .. code-block:: c
211
212     #ifdef LIBGCCJIT_HAVE_TIMING_API
213
214.. function:: void gcc_jit_timer_pop(gcc_jit_timer *timer, \
215                                     const char *item_name)
216
217   Pop the top item from the timer's stack.
218
219   If "item_name" is provided, it must match that of the top item.
220   Alternatively, ``NULL`` can be passed in, to suppress checking.
221
222   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
223   for its presence using
224
225   .. code-block:: c
226
227     #ifdef LIBGCCJIT_HAVE_TIMING_API
228
229.. function:: void gcc_jit_timer_print(gcc_jit_timer *timer, \
230                                       FILE *f_out)
231
232   Print timing information to the given stream about activity since
233   the timer was started.
234
235   This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
236   for its presence using
237
238   .. code-block:: c
239
240     #ifdef LIBGCCJIT_HAVE_TIMING_API
241