早期 TeX 的安装步骤

早期 TeX 的安装步骤

首先是一些背景信息。

TeX 的旧版本包含两个程序,initexvirtex。Initex 可以创建格式文件,而 virtex 可以加载它们。这些旧版本的 TeX(和 LaTeX)建议使用特殊的安装程序来加快格式文件的加载速度。它包括以下大致步骤,具体步骤因系统而异:

  • initex plain \dump加载plain.tex宏、创建plain.fmt和退出程序
  • virtex &plain加载plain.fmt并等待更多输入
  • 系统命令来创建程序的核心转储,^Ccontrol-\类似
  • 系统命令从核心转储、undump 或类似命令生成可执行文件

现在就可以使用预加载的纯文本格式运行生成的可执行文件了。

我的问题涉及上述最后两个步骤:

  1. 在 80 年代初期,TeX 系统使用这个功能有多普遍?

  2. plain.fmt这样加载格式文件的速度会快多少latex.fmt

  3. 什么时候以及为什么停止使用从核心转储创建新的可执行文件的这个过程?

  4. Knuth 对于推荐这种“黑客式”的安装程序有何感想?

我知道第四个问题可能只有一个人能回答,但也许当时在场的人知道。

旁注:早期的 Emacs 版本也采用了这种方法,甚至包括从核心映像创建可执行文件的代码。Perl 还可以选择-u创建核心转储,目的同样是为了加快加载时间。

答案1

TeX 是在程序运行在内存(和速度)更严格的限制下的时代编写的,因此它不得不求助于许多技巧和现在看来很奇怪但在当时很常见的东西。有三个与这个问题相关(INITEX、fmt 文件、核心转储);下面将详细介绍它们中的每一个(尽管我意识到这个问题主要与最后一个有关)。

这些在第 1331 节(第 51 部分:主程序)的 TeX 程序,如 David 的回答中所述。(Knuth 也曾谈论过这些事情。1982 年 7 月的三天里,他做了 12 场讲座(我认为是针对其他大学和类似地方的(我们称之为)系统管理员),他们将在他们的系统上安装新的“便携式”TeX 程序。这是最后一次:TeX82 的内部细节 - 第 12 节。观看这些视频也许能回答一些问题。)


第一的,TeX 的源代码有一些编译时变体(就像#ifdef ... #endif在 C 中一样,实现init ... tini如下TeX 程序),如果打开,将产生一个单独的程序 INITEX(它具有初始化某些内部数据结构、计算连字模式、转储格式文件等的额外功能)。将 INITEX 作为单独程序的原因是它需要额外的内存来完成其工作(例如,计算连字模式需要为 trie 分配内存),这会减少用于排版的内存。

如果不使用上述标志进行编译,我们将得到一个单独的程序,称为 TeX 的生产版本,它可能是 VIRTEX 或 TEX(稍后会详细介绍)。(如今,随着当代 TeX 发行版(例如 TeX Live 和 MiKTeX)的出现,不再有两个单独的程序进行编译和分发;相反,我们有一个程序,如果给出标志,它将像 INITEX 一样运行-ini。)


第二格式文件。这与第一种方式密切相关,因为格式文件是由 INITEX 转储的。例如,在启动 INITEX(或tex -ini今天)后,我们可以执行\input plain然后\dump。这样做的目的是将大量 TeX 的程序状态转储到一个.fmt文件中,这样生产 TeX 程序就可以简单地加载格式文件,而不必处理plain.tex(或当时称为 BASIC.TEX:顺便说一下,这就是为什么TeXbook该格式的文档plain位于附录 B:基本控制序列中)。

在上面链接的视频中,大约在 13 分钟的时候,他提到了一些数字,这些数字可以让您了解节省的时间的数量级:他说打开和读取大约十几个短.tfm文件(如 INITEX 或tex -ini所做的那样\input plain)需要超过 15 秒,因此读取单一格式的文件更快。

§1331 的截图


第三,核心转储/恢复转储。据我了解,这个想法是,您的程序的内存可以全部转储到一个文件中,然后您可以“恢复转储”:当您的程序启动时,其所有内存都将像在转储期间一样初始化,并且程序将从头开始启动。

有关于此功能的解释和历史这里,David R. Fuchs 的评论(见采访):12)是 Knuth 编写 TeX(TeX 的当前版本,即 TeX82)时的“得力助手”:

可执行程序文件只不过是内存映像而已;要运行程序,操作系统基本上只是将可执行映像映射到您的地址空间并跳转到开始位置。但当程序停止时,您的整个状态仍然存在,位于您的地址空间中 […]

操作系统还有一个内置命令,允许您将当前内存映像保存回新的可执行文件。这个命令也没有太多内容,因为可执行文件一开始只不过是一个内存映像。因此,相当于 dump/undump 的功能实际上只是内置在操作系统中,并不被认为是什么大事或超级特殊功能。当然,所有语言运行时都知道这一点,所以它们总是被编写成理所当然地理解它们必须能够正确处理它。如果你习惯了那个环境,它几乎是自然而然的,而且不会成为负担。

因此,当 TeX(我猜想还有在这些机器上诞生的各种 Lisp 和 Emacs 等)设计出来时,完全可以预料到它们会以这种方式工作。循环和 IO 一样昂贵;因此,以 TeX 为例,它需要花费很多秒来读取基本宏包和标准字体度量文件集,并将连字模式预处理到其数据结构中。通过在安装期间对生成的预加载可执行文件执行一次保存,每个人每次运行 TeX 时都可以节省这么多秒。

您可以在以下位置阅读更多信息(关于其他系统/程序)评论,并在两个讨论主题中提到了这一点:一个是关于Emacs 转储器(2016)等等使 Atom 编辑器速度提高约 50%(2017)

此外,在视频中,Knuth 表示这种系统将在大多数地方可用,或者至少在幸运的地方可用。(13:57:“在最多—无论如何,拉尔-在幸运的系统,比方说”。)(如果您的系统没有它,您仍然可以使用格式化文件功能:您可以启动 VIRTEX 并使用 加载纯文本格式&plain,而不是启动 INITEX 和\input plain。)

因此,dump/undump 系统实际上并不像听起来那么神秘。我认为您自己已经在一定程度上回答了您的问题,因为您指出 Emacs 和 Perl 具有类似的功能。


第四,(哈哈!)是 Pascal 编码技巧,它使 dump/undump 行为成为可能。以下来自 TeX 程序:

VIRTEX 并非即时卑鄙伎俩得逞


一些分析(和推测)

在这三个技巧中,第一个技巧(INITEX 作为一个单独的程序,具有不同的内存特性)是不可避免的,以适应内存限制。但其他两个技巧(fmt 文件和 dump/undump)似乎相当相似(例如,两者都使用动词“dump”)。我们都需要两者吗?

我怀疑fmt文件功能已添加到 TeX因为dump/undump 功能并非随处可用,它基本上是 TeX 中对大多数(但不是所有)操作系统功能的一种实现。因此 fmt 文件功能是必需的,因为它是唯一可以保证随处可用的功能。

TeX 是否可以只使用格式文件功能而不使用 dump/undump?在某些系统上,这是强制的,显然这是可以接受的。在其他系统上(“最好的实现 […] 预加载格式文件”,“在允许这种预加载的系统上……”),使用 dump/undump 是很自然的,所以没有理由不这样做。虽然加载格式确实节省了大量时间(例如,打开大量 TFM 文件以获取字体信息的时间),但仍有工作需要完成(“当然,VIRTEX 程序无法立即读取格式文件……”):

  • 对各种编译时常量进行健全性检查,以获得有意义的值,
  • 将大量变量初始化为正确值(查看第21节以及提及的 30 多个“另请参阅”部分),
  • 打开并加载格式文件(然后关闭它):这占据了大部分时间,并且涉及到取消转储很多东西(第455节):字符串池,整个动态内存(TeX“几乎所有的内存分配都是自己完成的”—这基本上是一个名为内存)、各种表格等等。虽然简单地写入所有这些的最终值会比在处理时一步一步地执行plain.tex(打开文件、逐个定义宏而不是简单地写出最终的哈希表)要快,但仍然需要相当多的时间。

因此,如果可用的话,转储/取消转储技巧是值得尝试的。不过,有几个问题:

  • 即使给予了正确的内存,Pascal 程序如何知道(如果从头开始启动)它是否已经读取了格式文件(即从这样的转储启动)?

  • (在 16:40 左右提到)转储文件时程序的状态实际上并不完全正确:它有一个您启动 VIRTEX 进行核心转储时的时间戳,而不是您的作业时间,并且它有错误的\jobname。(您可以使用现代发行版自己尝试一下:如果您从tex -ini(我们能最接近 VIRTEX 的)开始,然后执行\input plain,然后执行您的文档(hello world \bye或其他),那么您将获得输出plain.dvi。)所以我们需要重新初始化其中一些。

这就是“肮脏伎俩”的用武之地:通过访问一个全局变量,该变量在核心转储的情况下会被初始化为特定值,但如果从头启动则未初始化,我们可以区分这两种情况,并且(如果从核心转储恢复)仅初始化那些需要初始化的内容。

在我看来,这就是为什么 DEK 说这个技巧“回报丰厚”(使得这个转储/取消转储成为可能,并节省了一些时间),即使这个技巧仅在某些系统上有帮助。


回答有关 dump/undump 的实际问题:

  1. 此功能很常见:根据 DRF 和视频的评论,这只是在许多系统上启动(所有)程序的常用/合理方式(在“大型 CS 部门”使用)。但 DEK 知道此功能并非存在于所有系统上。

  2. BASIC.FMT使用 VIRTEX 比使用 INITEX加载速度快了好几秒(20 多秒)\input BASIC。不确定转储/取消转储(直接启动 TEX)节省了多少时间,但不知何故我怀疑它不会节省更多的比这个。

  3. 当大多数人转向其他不支持 dump/undump 的操作系统时,该功能就停止使用了,而且需要特殊的程序:

    但是当 TeX 被移植到 Unix(然后是 Linux)时,人们有点惊讶地发现模型不同了,而且没有方便的、预定义的方式来获得此功能,并且运行时通常没有设置为易于实现。undump 就是为了处理这个问题而创建的,但它从来都不是那么好用,因为它是附加的。

    unexec(显然与 Emacs类似。)

  4. 根据我们掌握的线索,我们可以猜测 Knuth 不会认为这是黑客行为(所有程序都是这样运作的),并且会很高兴找到一种让 TeX 更快的方法——参见 David Carlisle 的回答。:-)

答案2

在回答你的第 4 个问题时,他认为这“带来了丰厚的回报”......

tex.web 说:

The \.{VIRTEX} program cannot read a format file instantaneously, of course;
the best implementations therefore allow for production versions of \TeX\ that
not only avoid the loading routine for \PASCAL\ object code, they also have
a format file pre-loaded. This is impossible to do if we stick to standard
\PASCAL; but there is a simple way to fool many systems into avoiding the
initialization, as follows:\quad(1)~We declare a global integer variable
called |ready_already|. The probability is negligible that this
variable holds any particular value like 314159 when \.{VIRTEX} is first
loaded.\quad(2)~After we have read in a format file and initialized
everything, we set |ready_already:=314159|.\quad(3)~Soon \.{VIRTEX}
will print `\.*', waiting for more input; and at this point we
interrupt the program and save its core image in some form that the
operating system can reload speedily.\quad(4)~When that core image is
activated, the program starts again at the beginning; but now
|ready_already=314159| and all the other global variables have
their initial values too. The former chastity has vanished!

In other words, if we allow ourselves to test the condition
|ready_already=314159|, before |ready_already| has been
assigned a value, we can avoid the lengthy initialization. Dirty tricks
rarely pay off so handsomely.
@^dirty \PASCAL@>
@^system dependencies@>

答案3

我将尝试根据迄今为止给出的答案和评论进行总结。

  1. 没有人知道,但这似乎相当普遍。
  2. 一份报告显示,它可以平均节省 30 秒。参见TUGboat 第 4 卷第 1 期
  3. 没有人知道确切时间,但恰逢 TeX 迁移到较新的操作系统,这使得迁移变得不那么方便。也许是 80 年代末,90 年代初。
  4. Knuth 可能并不认为在可执行文件中实际嵌入该格式是一种黑客行为,但他肯定认为自己编写的利用该格式的 Pascal 代码是一种黑客行为,甚至称其为一种肮脏的伎俩。

相关内容