LaTeX 中与 ConTeXt \testfeatureonce 相当的测试性能工具是什么

LaTeX 中与 ConTeXt \testfeatureonce 相当的测试性能工具是什么

ConTeXt 提供了一个宏\testfeatureonce来对性能进行基准测试。语法是

\testfeatureonce{n}{...}

它运行第二个参数 times 中的代码nn假定为整数),并将经过的时间(以秒为单位)存储在宏中\elapasedtime。终端上还会打印以下诊断消息:

system > starting feature test (n=1) system > 1 feature tests done (1.353s)

下面是一个最简单的 ConTeXt 文档,展示了它的用法:

\starttext

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

\elapsedtime
\stoptext

LaTeX 中用于基准测试性能的功能等效宏是什么?

答案1

据我所知,LaTeX2e 基础中没有这样的宏(也许 LaTeX3 有等效的宏?)。但我们可以\testfeatureonce在 ConTeXt 源代码中查找定义。相关定义位于syst-aux模块

该实现分别利用 eTeX 基元\pdfresettimer\pdfelapsedtime重置内部计时器并获取自上次重置以来经过的时间。我没有找到合适的来源,但似乎 的返回值中的 65536 等于一秒\pdfelapsedtime

纯 LaTeX 代码的重新实现可能如下所示:

\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}

答案2

expl3可以使用\tex_resettimer:D\tex_elapsedtime:D,它们既适用于 pdfTeX 也适用于自 TL 2019 以来的 XeTeX(它们是原语\(pdf)resettimer\(pdf)elapsedtime已重命名)。对于 LuaTeX,您可以使用 中的 Lua 函数l3kernel。其中大部分是软件包中内容的基本版本l3benchmark(请参阅 Joseph 的回答),在提出此问题后不久发布。

\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}

编辑:错误修复。大量的测试(~5000)会因为堆积大量的\fi:s 而超出 TeX 的输入堆栈大小,因此我添加了一个辅助宏来确保所有内容都在外部执行,\if...\fi以便可以进行任意数量的运行。


使用 jfbu 转换缩放秒的想法,甚至可以在纯 (pdf、Xe 或 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

答案3

使用新l3benchmark软件包的代码(于 2018-10-26 发布至 CTAN):

\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}

基准测试代码还可以自动确定要执行的循环数:

\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}

(代码本身当然与这里的其他答案非常相似。)

答案4

一个原始的基准测试实用程序:

\documentclass{article}

\usepackage{xintkernel}

\makeatletter
\def\testfeatureonce#1#2{\pdfresettimer
    \romannumeral\xintreplicate{#1}{#2}%
    \edef\theelapsedtime{\strip@pt\dimexpr\pdfelapsedtime sp\relax s}%
    % \theelapsedtime % commented-out
}
\makeatother

\usepackage{tikz}

\begin{document}

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

\typeout{Previous test took \theelapsedtime}

\end{document}

结果被存储(但已转换为秒)以供重复使用。

....
(/usr/local/texlive/2018/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg))
Previous test took 0.92303s
[1{/usr/local/texlive/2018/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
....

该包xintkernel是非常轻量的包(也提供 \xintUniformDeviate),它本身不具备任何计算功能xint

\xintreplicate基本上与 l3kernel 中的原始代码相同(抄袭)。

欲了解更高级的基准测试,请参阅l3benchmark

以上内容未计算扩展的开销\xintreplicate(这里只是 tikz 的一小部分)。如果您想要 1000000 个复制,最好嵌套两个\romannumeral\xintreplicate{1000}

相关内容