修补 \usepackage / \RequirePackage

修补 \usepackage / \RequirePackage

我想对我加载的软件包(其中一些是我自己编写的)实现自动基准测试。目前我的前言部分需要 15 秒才能加载,比编译文档其余部分所需的时间要长得多。

为此,我想实现这一点回答,建议使用etoolboxpatchcmmd修补usepackage。由于我的大部分软件包加载都发生在我自己的软件包内部,所以我想在 上使用这种方法RequirePackage。然而,我选择使用xpatch的实用程序,因为我读到过,常规patchcmd无法处理带有可选参数的命令。

到目前为止我最好的尝试是这样的(请不要介意通过 AfterEndPreamble 的丑陋的自动输出):

\RequirePackage{fp}
\RequirePackage{xpatch}
\newcount\timer

\xpretocmd{\RequirePackage}{\pdfresettimer}{}{}
\xapptocmd{\RequirePackage}{
    \timer=\pdfelapsedtime
    \FPdiv\temp{\the\timer}{65.536}
    \FPtrunc\temp\temp{3}
    \AfterEndPreamble{\par{#1:} \temp}
}{}{}

% Testing 
\RequirePackage{tikz}
\RequirePackage{mathtools}

\documentclass{article}
\begin{document}

\end{document}

但不幸的是,这会产生一个错误:

! LaTeX Error: File `\timer.sty' not found.

我最好的猜测是,这是因为ProvideCommand在正常参数之后有第二个可选参数,并且xpatchcmd无法处理它,导致使用附加的文本作为其主要参数。但是我在这里已经远远超出了我的舒适区,到目前为止ProvideCommand我还没有设法理解它(并且我认为无论如何一定有更好的方法,只需用周围的代码修补命令,而无需了解其内部结构)。任何帮助都非常感谢。ProvideCommand\show

答案1

收益latexdef RequirePackage

% latex.ltx, line 10034:
\def\RequirePackage{%
  \@fileswithoptions\@pkgextension}

哦,好吧,现在我们需要做的latexdef @fileswithoptions

% latex.ltx, line 10097:
\def\@fileswithoptions#1{%
  \@ifnextchar[%]
    {\@fileswith@ptions#1}%
    {\@fileswith@ptions#1[]}}

这意味着宏吸收一个标记或一个括号参数并测试是否[出现 a。如果你在 的末尾添加这些标记\RequirePackage,则传递给 的参数\@fileswithoptions将是\@pkgextension,而 的测试[将返回 false,因此我们最终会得到

\@fileswith@ptions\@pkgextension\timer=\pdfelapsedtime

正如你所见,这将失败,因为

\def\@fileswith@ptions#1[#2]#3{%
  \@ifnextchar[%]
  {\@fileswith@pti@ns#1[{#2}]#3}%
  {\@fileswith@pti@ns#1[{#2}]#3[]}}

所以参数#3\timer代替文件名列表(不带扩展名)。

\RequirePackage抱歉,但由于您加载的包嵌套,这不会以任何合理的方式起作用。

\RequirePackage{fp}
\newcount\timer

\newcommand{\TimeRequirePackage}[1]{%
  \pdfresettimer
  \RequirePackage{#1}%
  \timer=\pdfelapsedtime
  \FPdiv\temp{\the\timer}{65.536}%
  \FPtrunc\temp\temp{3}%
  \printresult{#1}%
}
\newcommand{\printresult}[1]{\expandafter\printresultaux\expandafter{\temp}{#1}}
\newcommand{\printresultaux}[2]{\AtBeginDocument{\par#2: #1}}

% Testing 
\TimeRequirePackage{tikz}
\TimeRequirePackage{mathtools}

\documentclass{article}
\begin{document}
\end{document}

在此处输入图片描述

\temp请注意,在将其传递给\AtBeginDocument(不是)之前,需要进行扩展\AtEndPreamble

xfp

\RequirePackage{xfp}

\newcommand{\TimeRequirePackage}[1]{%
  \pdfresettimer
  \RequirePackage{#1}%
  \expanded{\noexpand\AtBeginDocument{\par#1: \fpeval{round(\pdfelapsedtime/65.536,3)}}}
}

% Testing 
\TimeRequirePackage{tikz}
\TimeRequirePackage{mathtools}

\documentclass{article}
\begin{document}
\end{document}

在此处输入图片描述

答案2

您可以使用(使用新的 latex)包钩子来定义应该测量的包列表(计算是从 egregs 答案中窃取的):

\ExplSyntaxOn
\newcommand{\BenchmarkPackages}[1]
 {%
  \clist_map_inline:nn{#1}
   {
    \AddToHook{package/before/##1}{\pdfresettimer}
    \AddToHook{package/after/##1}{\typeout{##1: \fp_eval:n{round(\pdfelapsedtime/65.536,3)}}}
   } 
 }
\ExplSyntaxOff
\BenchmarkPackages{tikz,mathtools,scrbase}


\documentclass{scrartcl}
\usepackage{tikz}
\begin{document}
alblb
\end{document}

然后会在日志中写入类似 tikz:1085.999 的内容(当然也可以存储该值并在稍后打印)。

相关内容