如何对 TeX 中的代码执行进行计时?

如何对 TeX 中的代码执行进行计时?

在我与 TeX Exchange 成员的交流中,我遇到了几种计时代码执行的方法。但这些信息分散在我的帐户活动日志中。为了节省时间并有一个​​专门的地方来计时 TeX 代码,我问了这个问题。

最重要的是,我想知道是否有纯 TeX 解决方案,或者至少是 LaTeX 2ε 解决方案,这样我会优先考虑它们而不是 LaTeX3。

答案1

有一个\benchmark{<n>}{<code>},它将运行<code> <n>时间并测量已用时间。循环的开销很小,因此您通常不必担心这一点。

还有一个\benchmarkTIC和一个\benchmarkTOC命令。\benchmarkTIC将重置计时器,并将\benchmarkTOC测量自上次以来的时间\benchmarkTIC并将其打印到终端。

这大部分内容来自这里,但略有改进并添加了tic/toc命令。所有这些只是 功能的一部分l3benchmark,因此我建议您改用 。l3benchmark有一个\benchmark:n命令可以自动触发必要的重复次数,并且还有\benchmark_tic:\benchmark_toc:命令允许嵌套(下面代码中的命令不允许)。

下面的代码将其打印到终端:

> 1000 feature tests done (0.976s)
> Benchmark TIC:
> Benchmark TOC: 0.97699s

本质是使用 pdfTeX 原语\pdfresettimer\pdfelapsedtime。第一行只是基本设置,以便代码可以在更多引擎中工作。LuaTeX 没有原语,因此它们的行为是通过 Lua 函数调用模拟的。XeTeX 和 ε-(u)pTeX 具有相同的原语,名称\resettimer\elapsedtime(这是有道理的,因为它们不是与 PDF 相关的东西)。代码将所有内容标准化为\resettimer\elapsedtime

\resettimer将引擎中的内部(我们称之为)计时器重置为零,并\elapsedtime从该计时器中检索值(以秒为单位:1 秒 × 65536)。

\benchmark一开始就执行\resettimer,按要求循环代码多次,\elapsedtime最后进行漂亮的打印。\benchmarkTIC\benchmarkTOC只是包装器,用于将东西\resettimer写入\elapsedtime终端并将时间从缩放的秒转换为秒。

\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

相关内容