What is the LaTeX equivalent of ConTeXt \testfeatureonce to benchmark performance

With expl3 you can use \tex_resettimer:D and \tex_elapsedtime:D, which exist for both pdfTeX and since TL 2019 for XeTeX (they are the primitives \(pdf)resettimer and \(pdf)elapsedtime renamed). For LuaTeX you can use the Lua functions from l3kernel. Most of this is a rudimentary version of what's in the l3benchmark package (see Joseph's answer), released shortly after this question was asked.

\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}

\ExplSyntaxOn
\sys_if_engine_luatex:TF
  {
    \cs_new:Npn \__tfo_start_timer:  { \lua_now:n { l3kernel.resettimer() } }
    \cs_new:Npn \__tfo_elapsed_time: { \lua_now:n { l3kernel.elapsedtime() } }
  }
  {
    \cs_new_eq:NN \__tfo_start_timer: \tex_resettimer:D
    \cs_new_eq:NN \__tfo_elapsed_time: \tex_elapsedtime:D
  }
\cs_new:Npn \__tfo_output:n #1
  {
    \iow_term:x
      {
        >~#1~feature~tests~done~
        (\fp_eval:n { round ( \__tfo_elapsed_time: / 65536 , 3 ) }s)
      }
  }
\cs_new:Npn \__tfo_run_n_times:nn #1 #2
  {
    \if_int_compare:w #1 > 0 \scan_stop:
      \exp_args:No \__tfo_run_n_times:nnw { \int_value:w \__int_eval:w #1 - 1 } { #2 }
    \fi:
  }
\cs_new:Npn \__tfo_run_n_times:nnw #1 #2 \fi:
  {
    \fi:
    #2
    \__tfo_run_n_times:nn { #1 } { #2 }
  }
\NewDocumentCommand\TestFeatureOnce
  { m m }
  {
    \__tfo_start_timer:
    \__tfo_run_n_times:nn { #1 } { #2 }
    \__tfo_output:n { #1 }
  }
\ExplSyntaxOff

\begin{document}

\TestFeatureOnce{10000}
    {\setbox0\hbox
        {\tikz \draw (0,0) -- (1cm, 1cm);}}

\end{document}

Edit: Bug fix. A large number of tests (~5000) would exceed TeX's input stack size by piling up tons of \fi:s, so I added a helper macro to make sure everything is executed outside the \if...\fi so that an arbitrary number of runs is possible.


With jfbu's idea to convert scaled seconds, one can even do it in plain (pdf, Xe, or Lua)TeX:

\input tikz.tex

\begingroup% pdfTeX
  \expandafter\ifx\csname pdfresettimer\endcsname\relax
  \else
    \global\let\resettimer\pdfresettimer
    \global\let\elapsedtime\pdfelapsedtime
  \fi
\endgroup
\begingroup% LuaTeX
  \expandafter\ifx\csname directlua\endcsname\relax
  \else
    \gdef\resettimer{\directlua{pdfelapsedtimer_basetime = os.clock()}}
    \gdef\elapsedtime{\directlua{tex.print((os.clock()-pdfelapsedtimer_basetime)*65536)}}
  \fi
\endgroup
% For XeTeX the primitives are already called \resettimer and \elapsedtime
\catcode`@=11
% Stolen from latex.ltx
\begingroup
  \catcode`P=12
  \catcode`T=12
  \lowercase{%
    \def\x{\def\rem@pt##1.##2PT{##1\ifnum##2>\z@.##2\fi}}}%
  \expandafter\endgroup\x
\def\strip@pt{\expandafter\rem@pt\the}%
%
\let\TFO@start@timer\resettimer
\let\TFO@elapsed@time\elapsedtime
\def\TFO@output#1{%
  \immediate\write17{%
    > #1 feature tests done (\strip@pt\dimexpr\TFO@elapsed@time sp\relax s)
  }%
}
\long\def\TFO@runNtimes@nn#1#2{%
  \ifnum#1>0\relax
    \expandafter\TFO@runNtimes@nnw\expandafter{\number\numexpr#1-1}{#2}%
  \fi
}
\long\def\TFO@runNtimes@nnw#1#2\fi{%
  \fi
  #2%
  \TFO@runNtimes@nn{#1}{#2}%
}
\long\def\TestFeatureOnce#1#2{%
  \TFO@start@timer
  \TFO@runNtimes@nn{#1}{#2}%
  \TFO@output{#1}%
}
\catcode`@=12

\TestFeatureOnce{1000}
    {\setbox0\hbox
        {\tikz \draw (0,0) -- (1cm, 1cm);}}

\bye

For all I know, there's no such macro in the LaTeX2e base (perhaps LaTeX3 has something equivalent?). But we can look up the definition of \testfeatureonce in the ConTeXt source code. The relevant definitions are in the syst-aux module.

That implementation makes use of the eTeX primitives \pdfresettimer and \pdfelapsedtime to reset an internal timer and get the elapsed time since the last reset, respectively. I didn't find a proper source for this, but it seems 65536 equals one second in the value returned by \pdfelapsedtime.

A reimplementation in pure LaTeX code might look like this:

\documentclass{article}
\usepackage{tikz}

\makeatletter
\let\resettimer=\pdfresettimer
\let\elapsedtime=\pdfelapsedtime

\newcount\c@syst@helpers@test@feature@n
\newcount\c@syst@helpers@test@feature@m

\newcommand\testfeature[2]{%
    \c@syst@helpers@test@feature@m=#1\relax
    \def\syst@helpers@test@feature@step{%
        \advance\c@syst@helpers@test@feature@n by 1\relax
        \ifnum\c@syst@helpers@test@feature@n>\c@syst@helpers@test@feature@m\else
            #2\expandafter\syst@helpers@test@feature@step
        \fi
    }%
    \retestfeature
}

\newcommand\retestfeature{
    \bgroup
    \ifcase\interactionmode \let\wait\relax \fi
    \resettimer
    \c@syst@helpers@test@feature@n=0\relax
    \syst@helpers@test@feature@step
    \wait
    \egroup
}

\newcommand\testfeatureonce[2]{%
    \begingroup
    \let\wait\relax
    \testfeature{#1}{#2}%
    \endgroup
}

\makeatother

\begin{document}

\testfeatureonce{1000}
    {\setbox0\hbox
        {\tikz{ \draw (0,0) -- (1cm, 1cm); }}}

\the\elapsedtime

\end{document}

Code using the new l3benchmark package (released to CTAN 2018-10-26):

\documentclass{article}
\usepackage{l3benchmark}
\ExplSyntaxOn
\cs_new_protected:Npn \testfeatureonce #1#2
  {
    \benchmark_once:n
      { \prg_replicate:nn {#1} {#2} }
  }
\ExplSyntaxOff
\usepackage{tikz}

\begin{document}
\testfeatureonce{1000}
    {\setbox0\hbox
        {\begin{tikzpicture} draw (0,0) -- (1cm, 1cm); \end{tikzpicture}}}
\end{document}

The benchmark code can also auto-determine how many cycles to do:

\documentclass{article}
\usepackage{l3benchmark}
\ExplSyntaxOn
\cs_new_protected:Npn \testfeatureonce #1#2
  { \benchmark:n {#2} }
\ExplSyntaxOff
\usepackage{tikz}

\begin{document}
\testfeatureonce{1000}
    {\setbox0\hbox
        {\begin{tikzpicture} draw (0,0) -- (1cm, 1cm); \end{tikzpicture}}}
\end{document}

(The code itself is of course much the same as the other answers here.)