1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
|
.. Copyright (C) 2015-2016 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, "create_code");
/* 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, "compile");
/* 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, "running code");
/* 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_HAVE_TIMING_API
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_HAVE_TIMING_API
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 ();
This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
for its presence using
.. code-block:: c
#ifdef LIBGCCJIT_HAVE_TIMING_API
.. 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.
This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
for its presence using
.. code-block:: c
#ifdef LIBGCCJIT_HAVE_TIMING_API
.. 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.
This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
for its presence using
.. code-block:: c
#ifdef LIBGCCJIT_HAVE_TIMING_API
.. function:: gcc_jit_timer *gcc_jit_context_get_timer(gcc_jit_context *ctxt)
Get the timer associated with a context (if any).
This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
for its presence using
.. code-block:: c
#ifdef LIBGCCJIT_HAVE_TIMING_API
.. 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, "running code");
This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
for its presence using
.. code-block:: c
#ifdef LIBGCCJIT_HAVE_TIMING_API
.. function:: void gcc_jit_timer_pop(gcc_jit_timer *timer, \
const char *item_name)
Pop the top item from the timer's stack.
If "item_name" is provided, it must match that of the top item.
Alternatively, ``NULL`` can be passed in, to suppress checking.
This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
for its presence using
.. code-block:: c
#ifdef LIBGCCJIT_HAVE_TIMING_API
.. 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.
This API entrypoint was added in :ref:`LIBGCCJIT_ABI_4`; you can test
for its presence using
.. code-block:: c
#ifdef LIBGCCJIT_HAVE_TIMING_API
|