LuaTeX 和 XeTeX 的 \pdfelapsedtime 模拟

LuaTeX 和 XeTeX 的 \pdfelapsedtime 模拟

在 pdfTeX 中,该\pdfelapsedtime原语允许访问自此 pdfTeX 运行开始以来的时间,以“缩放秒数”(1/65536 秒)为单位。这对于对代码进行基准测试很有用:重复多次,并测试其所用的时间。

\newcount\benchmarkcount
\long\def\tenfold#1{#1#1#1#1#1#1#1#1#1#1}
\long\edef\thousandfold{\tenfold{\tenfold{\tenfold{#1}}}}
\long\def\benchmark#1{%
  \benchmarkcount\pdfelapsedtime
  \thousandfold{#1}%
  \typeout{\the\dimexpr\pdfelapsedtime sp-\benchmarkcount sp miliseconds}%
}

是否有可能在 XeTeX 和/或 LuaTeX 中以类似的方式访问时间?

答案1

这里,以下代码看起来与原始原语非常接近。我们首先查看 pdflatex 发行说明(2005-08-01)

  • \pdfelapsedtime是一个只读整数,它(最初)返回自本次运行开始以来经过的时间量。该量以“缩放秒数”给出:值 65536 计为一秒。如果经过的时间超过 32767 秒,则将返回 (2^31)-1。
  • \pdfresettimer更新内部计时器,以便后续调用 \pdfelapsedtime将从 0 重新开始。

现在,尝试在用户空间重新实现:

\directlua{pdfelapsedtimer_basetime=0}

os.clock()从 lua 的开头开始计数,因此pdfelapsedtimer_basetime设置为零。无需读取初始os.clock()值,反正它应该是 0。来自 lua.org:

os.clock 函数返回程序的 CPU 时间(秒数)。它的典型用途是对一段代码进行基准测试

如果用户想要重置它,pdflatex 原语是\pdfresettimer。在这种情况下,我们读出os.clock()并将其存储在 中,pdfelapsedtimer_basetime以便稍后减去偏移量。

\protected\def\pdfresettimer{\directlua{pdfelapsedtimer_basetime = os.clock()}}

最后,\pdfelapsedtime宏减去偏移量得到秒数,乘以 65536 得到缩放后的秒数,加上 0.5 以使函数math.floor正确舍入并返回一个整数。我们需要一个整数,而不是标记流中的字符,因此,\numexpr被利用。

\protected\def\pdfelapsedtime{\numexpr\directlua{tex.print(math.floor((os.clock()-pdfelapsedtimer_basetime)*65536+0.5))}\relax}

以下 MWE 是针对原始问题的实现:

\documentclass{article}

\newcount\benchmarkcount
\long\def\tenfold#1{#1#1#1#1#1#1#1#1#1#1}
\long\edef\thousandfold#1{\tenfold{\tenfold{\tenfold{#1}}}}
\long\def\benchmark#1{%
  \benchmarkcount\pdfelapsedtime
  \thousandfold{#1}%
  \typeout{\the\dimexpr\pdfelapsedtime sp-\benchmarkcount  sp}%
}

\usepackage{lipsum}

\directlua{pdfelapsedtimer_basetime=0}
\protected\def\pdfresettimer{\directlua{pdfelapsedtimer_basetime = os.clock()}}
\protected\def\pdfelapsedtime{\numexpr\directlua{tex.print(math.floor((os.clock()-pdfelapsedtimer_basetime)*65536+0.5))}\relax}

\begin{document}
\benchmark{\lipsum}
\end{document}

相关内容