在我与 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