There's a \benchmark{<n>}{<code>}
, which will run <code>
<n>
times and measures the elapsed time. The overhead of the loop is minimal, so you usually don't need to worry about that.
There's also a \benchmarkTIC
and a \benchmarkTOC
command. \benchmarkTIC
will reset the timer, and \benchmarkTOC
will measure the time since the last \benchmarkTIC
and will print it to the terminal.
This is mostly copied from here, but slightly improved and with added tic
/toc
commands. All of this is just a subset of the features of l3benchmark
, so I suggest you use that instead. l3benchmark
has a \benchmark:n
command which automatically fires out the number of repetitions necessary, and also has \benchmark_tic:
and \benchmark_toc:
commands which allow nesting (the ones in the code below don't).
The code below prints this to the terminal:
> 1000 feature tests done (0.976s)
> Benchmark TIC:
> Benchmark TOC: 0.97699s
The essence is using the pdfTeX primitives \pdfresettimer
and \pdfelapsedtime
. The first bunch of lines is just a basic setup so that the code works in more engines. LuaTeX doesn't have the primitives, so their behaviour is emulated with Lua function calls. XeTeX and ε-(u)pTeX have the same primitives under the names \resettimer
and \elapsedtime
(which makes sense, since they are not PDF-related things). The code normalises eveything to \resettimer
and \elapsedtime
.
\resettimer
resets an internal (let's call it) timer in the engine to zero, and \elapsedtime
retrieves the value from that timer (in scaled seconds: 1 s × 65536).
\benchmark
does \resettimer
at the very beginning, loops the code as many times as requested, and pretty-prints \elapsedtime
at the end. \benchmarkTIC
and \benchmarkTOC
are just wrappers around \resettimer
and \elapsedtime
to write stuff to the terminal and convert the time from scaled seconds to seconds.
\begingroup
\ifcase 0%
\expandafter\ifx\csname pdfresettimer\endcsname\relax\else1\fi % pdfTeX
\expandafter\ifx\csname directlua\endcsname\relax\else2\fi % LuaTeX
\expandafter\ifx\csname resettimer\endcsname\relax\else3\fi % Others
\relax
\errmessage{Primitive support for timing unavailable}
\or \endgroup
\let\resettimer\pdfresettimer
\let\elapsedtime\pdfelapsedtime
\or \endgroup
\def\resettimer{\directlua{pdfelapsedtimer_basetime = os.clock()}}
\def\elapsedtime{\directlua{tex.print((os.clock()-pdfelapsedtimer_basetime)*65536)}}
\or \endgroup
\fi
\catcode`@=11
\let\benchmark@reset\resettimer
\let\benchmark@elapsed\elapsedtime
\begingroup
\def\benchmark@time@s{\strip@pt\dimexpr\benchmark@elapsed sp\relax s}
\def\benchmark@term{\immediate\write17}
\edef\x{\endgroup\def\noexpand\rem@pt##1.##2\detokenize{pt}}%
\x{#1\ifnum#2>\z@.#2\fi}
\def\strip@pt{\expandafter\rem@pt\the}%
\def\benchmark@output#1{\benchmark@term{> #1 feature tests done (\benchmark@time@s)}}
\long\def\benchmark@runNtimes#1#2{%
\ifnum#1>0\relax\expandafter\benchmark@Ntimes@aux\number\numexpr#1-1;{#2}\fi}
\long\def\benchmark@Ntimes@aux#1;#2\fi{\fi #2\benchmark@runNtimes{#1}{#2}}
\long\def\benchmark#1#2{%
\benchmark@reset \benchmark@runNtimes{#1}{#2}%
\benchmark@output{#1}}
\def\benchmarkTIC{\benchmark@term{> Benchmark TIC:}\benchmark@reset}
\def\benchmarkTOC{\benchmark@term{> Benchmark TOC: \benchmark@time@s}}
\catcode`@=12
% Just for the example
\input tikz.tex
% Run some code a number of times
\benchmark{1000}
{\setbox0\hbox{\tikz \draw (0,0) -- (1cm, 1cm);}}
% Benchmark some piece of code
\benchmarkTIC
\count0=0
\loop
\setbox0\hbox{\tikz \draw (0,0) -- (1cm, 1cm);}
\advance\count0 by 1
\ifnum\count0<1000
\repeat
\benchmarkTOC
\bye