259

Usually I don't mind about LaTeX's compilation speed, because a paper of less than 20 pages is compiled rather fast. However, I am working on a large document - A report with more than 80 pages. Compilation times are starting to slow me down. I saw the couple of answers here on this topic, but most of my graphics are external and I don't use Tikz. As a matter of fact, I'm not sure what's slowing the compilation down, other than the amount of text and required layout.

  1. What's your best speeding-tex-up trick, other than externalizing graphics and pre-compiling the preamble?
  2. How can I know what's slowing TeX down?
10

23 Answers 23

102

Beware of Greeks bearing gifts... Apparently, the nice todonotes package that I used dragged Tikz along with it, and introduced a major slowdown. Switching to simple marginpars gave a nice speedup. It should be noted that this package is a performance Trojan horse.

11
  • 6
    +1 for the info about "todo". However, it would be best if you don't ask questions in your answers, so please remove the last sentence (and edit your question if you want to). Jan 12, 2011 at 11:00
  • 17
    @Little Bobby Tables, @Hendrik: Except that the information is incorrect: the todo package does not load tikz, although the todonotes package does. Please be careful when referring to packages by name, especially when the information is negative.
    – Alan Munn
    Jan 12, 2011 at 12:34
  • 1
    @Hendrik Thanks. How the whole "@" thing works is a bit mysterious anyway. Do I have to use the full name or will this get to you with just "@Hendrik"?
    – Alan Munn
    Jan 12, 2011 at 13:29
  • 5
    @Alan: I've asked this on meta some time ago; there you can find the full explanation. Jan 12, 2011 at 13:33
  • 2
    What do you mean by "nice speedup"? My compilation got faster in the 10% range. Not bad but also not really life changing :/
    – Christian
    Dec 12, 2012 at 16:56
79

large documents start with pages >500 ... Create a script which runs:

pdflatex -draftmode file
bibtex file # or biber
makeindex file.idx # if needed
makeindex -s style.gls ...# for glossary if needed
pdflatex -draftmode file
pdflatex file

The compilation can now be speedup if you run bibtex/makeindex/... only when there were changes in this area. Can be detected with a diff for the auxiliary files.

10
  • 7
    Couldn't the second pdflatex run also use -draftmode?
    – Philipp
    Jan 12, 2011 at 12:47
  • 1
    @Philipp: yes, we can ... :-)
    – user2478
    Jan 12, 2011 at 13:07
  • 1
    you can it detect only for special cases, because I can define my own file extension and then yor Makefile cannot detect my use of makeindex or xindy or splitindex ...
    – user2478
    Feb 16, 2011 at 18:45
  • 4
    Just information: -draftmode can be used only for pdflatex and latex. xelatex has no such an option. Mar 14, 2012 at 8:29
  • 7
    Making this work in TexStudio: Go to Settings > User Commands, add pdflatex -draftmode %.tex | biber % --output-safechars | pdflatex -draftmode %.tex | pdflatex -synctex=1 %.tex | txs:///view
    – n1000
    Sep 24, 2016 at 15:07
56

I think the most effective way to save time is to avoid compiling the document time and time again. Compilations are often not really needed, when we change several words or a simple equation.

For large documents, we can split them into small pieces using \include command. Then \includeonly helps us to compile the only piece we are interested in, leaving the whole compilation to the last stage.

For complex tables or graphs made by TeX, put them into seperate TeX files first to verify the code, then add them to the document.

Sometimes compilation options may affect the speed. pdflatex -interaction=batchmode foo is often faster than pdflatex foo, this avoid scrolling informations. There may be more, say, xelatex -no-pdf foo is faster than xelatex foo, if it isn't the last round.

5
  • 4
    Which one will run faster, with batchmode or nonstopmode? Mar 14, 2012 at 8:03
  • 7
    @DamienWalters: batchmode is faster.
    – Leo Liu
    Mar 14, 2012 at 9:43
  • 1
    related: hilbertastronaut.blogspot.com/2008/12/…
    – alfC
    Sep 17, 2014 at 3:47
  • 9
    I disagree with the first part of that advice. Frequent compilation is very much needed when working with Tex, mainly due to the possibility of introducing a syntax error/typo etc when writing which will be almost impossible to find, as the common ones result in non-local errors. Another reason is that the advice is irrelevant, as mostly frequent compilations will not be due to added text, but things like tweaking the bibliography, which requires dozens of lengthy compilations runs and can, therefore, take hours.
    – Pixel78
    Sep 9, 2021 at 22:54
  • 2
    For \includeonly, an alternative is to use standalone package and compile the individual part instead of the whole document – the advantage is that you can use \input and don't have to break each section into a separate page.
    – user202729
    Nov 17, 2021 at 3:37
48

If you are using XeLaTeX, a substantial amount of time is spent gzipping data with highest compression (9) in the xdvipdfmx command.

~$ xdvipdfmx --help
…
-z number   Set zlib compression level (0-9) [9]
…

For me, on a 90 page document:

~$ time xelatex -interaction=nonstopmode Thesis.tex
…
real    0m6.056s
~$ ls -lh Thesis.pdf 
… 6,0M … Thesis.pdf

Without compression:

~$ time xelatex -interaction=nonstopmode -output-driver='xdvipdfmx -z0' Thesis.tex
…
real    0m2.417s
~$ ls -lh Thesis.pdf 
… 142M … Thesis.pdf

That is ~60% time saved but 23× bigger. Ok, some compression is clearly needed. My sweet spot:

~$ time xelatex -interaction=nonstopmode -output-driver='xdvipdfmx -z3' Thesis.tex
…
real    0m2.957s
~$ ls -lh Thesis.pdf 
… 6,9M … Thesis.pdf

That is 0.5s for compression or some 16% of the total time, as opposed to the majority of the time with default settings. I can usually live well with the 15% bigger file size. Of course, it does make sense to use -z9 for the final build.

I did not use XeTeX but assume the same scenario applies.

4
  • 1
    I am adding -file-line-error -synctex=1 to your suggestions above, like this: xelatex -interaction=nonstopmode -file-line-error -synctex=1 -output-driver="xdvipdfmx -z0" "$1", which is allowing me to have the speed gain while retaining synctex advantages (NB: the syntax I have here with "$1" is TeXShop's) Sep 22, 2018 at 3:21
  • Note that xdvipdfmx -z9 is faster and results in a smaller file than using xdvipdfmx -z0 together with optpdf. To increase the speed even more I also use xelatex -interaction=batchmode -draftmode -no-pdf for the first time(s) and then xdvipdfmx -z9 to convert the xdy to pdf. (n × xelatex -no-pdf + xdvipdfmx vs. (n - 1) × xelatex -no-pdf + xelatex does not really make a difference in my example)
    – miile7
    Jul 10, 2019 at 8:19
  • There are also other ways to change the compression level, see xetex - prevent xelatex from compressing the output and tex.stackexchange.com/a/53252/250119 and luatex - LuaLaTeX: How to speed up PDF generation? - TeX - LaTeX Stack Exchange
    – user202729
    Nov 14, 2021 at 14:21
  • 2
    latexmk -xelatex handles all the advice in this answer and comments to this answer: it compiles with -no-pdf by default, then once finished with the .xdv it then runs xdvipdfmx. 👍 Apr 25, 2022 at 23:00
36

The most useful trick I know is: do not do textual changes and layout changes at the same time, but make a clear division between them.

I first fix up all the text issues (there is hardly any need to recompile during that cycle) and only afterwards worry about layout and page breaks. The separation means that in the second cycle, I can usually tackle more than one display problem simultaneously.

The second most useful trick I know is: buy a computer with a faster CPU.

Precompilation of the header will only save you some startup time, but does nothing for consecutive pages, so the effect diminishes as your document grows.

5
  • 3
    I agree on the separation between typing text with rare compilations, and then doing the layout several bits at a time. When I remember to apply it, it frees my mind a lot from all the thoughts about layout. Jan 12, 2011 at 12:44
  • 5
    Note, that adding more RAM will normally not increase TeX's speed. I just tested a not-too-small document with many packages and had a 49 MB RAM usage of the pdflatex process (peak value) plus 47 MB file cache usage after the compilation process (I dropped the caches before the measurements). So 100 MB of free memory when the OS and all the other applications are loaded seems to be enough for most cases. The only thing that does matter is the single-core (integer) cpu speed. May 21, 2013 at 12:35
  • 4
    The RAM hint is more than misleading and should be removed! pdflatex is a CPU–bound process. See Tips for choosing hardware for best latex compile performance
    – Daniel
    Oct 2, 2013 at 7:05
  • 1
    is it possible to compile latex using GPU?
    – alper
    Jun 8, 2022 at 13:22
  • 1
    @alper See tex.stackexchange.com/questions/409232/…. Jul 17, 2023 at 11:00
28

Although the original post is rather old, I just stumbled upon this issue myself with a 100+ pages project with lots of figures.

If you're still working on the document and the resulting PDF file size is less important, you may try adding the following primitives at the beginning of your document

\pdfcompresslevel=0
\pdfobjcompresslevel=0

This significantly increased the PDF file size for me, but in turn reduced compilation time to (not by) about 34%. If you're done editing and want to compile the final version, just comment out these lines.

This is somehwat related to I have a name now's post, but doesn't require the command line and appears to be independent of whether you're using pdflatex or other engines.

Best, r.

4
  • I think this one is dependent on PDF? I also left a comment under that post for method in other engines, one of them (claims to be) engine independent. tex.stackexchange.com/questions/8791/…
    – user202729
    Nov 17, 2021 at 3:33
  • 1
    I tried this on a 450-page document, and made absolutely no difference. It is not figure-heavy, but uses tcolorbox in almost every page. Jan 5, 2022 at 18:11
  • 2
    This reduces my compilation time from 10 seconds to to 1.5 seconds, albeit with a file size increase of 33 times. But still a very good timesaver!
    – Mr.Yellow
    Jan 21, 2022 at 10:08
  • Note: On LuaTeX use \pdfvariable compresslevel=0 \pdfvariable objcompresslevel=0 instead, or add \usepackage{luatex85} before it. Refer to texdoc luatex for more details.
    – user202729
    Feb 2 at 22:41
17

Here is a tip:

Beamer+graphics is a time-consuming combination that I revisit every now and then when preparing presentations. What I do is keep all my graphics in a directory images that is actually a symbolic link to either images-hires or images-lowres. The latter is a script-generated directory with a copy of each image in image-hires but with a considerable resize transformation.

This process could be even smarter with a small preamble that checks the draft option of the document class and sets the correct path with \graphicspath. But I haven't done it because I didn't know this macro before and I am not very skilled at LaTeX/TeX macros and magics.

5
  • 8
    With pdflatex -draftmode file the images are not read which is useful until the very last pdflatex run.
    – user2478
    Jan 12, 2011 at 18:51
  • @Herbert: Is there a difference between passing -draftmode to pdflatex used to compile an input file without draft option passed to \documentclass and passing draft to \documentclass compiled with pdflatex invoked without -draftmode option? Mar 14, 2012 at 7:21
  • 3
    the draft option is far different from using the option -draftmode. The latter didn't produce a pdf file!
    – user2478
    Mar 14, 2012 at 9:51
  • 1
    Using imagemagick's convert program in a script with the -density and -quality option set to a low value is probably an easy, cross-platform, and free way to do this.
    – bbarker
    Apr 21, 2014 at 17:31
  • Specifically, I use $ convert figure.png -resize 20% ./preview/figure.png. Jul 13, 2017 at 8:43
15

When you need to iterate on something (say, the formatting of an equation), a quick and dirty but very effective trick is to comment out the bulk of the document using:

\iffalse

all the stuff you don't need to compile every time...

\fi

then you can focus in on the particular section you are working on, until you've got it just right with a tight edit/compile loop.

Then uncomment the rest of the document.

4
  • Super helpful for debugging also. For us beginners, could you perhaps expand a little on what's happening here/ how this works?
    – dardisco
    Jan 18, 2017 at 0:49
  • \iffalse ... \fi evaluates the code in ... if False evaluates to True (like if (false) { ... } in C-like languages), so it effectively "deactivates" the code contained inside and prevents TeX from compiling it. Jul 18, 2017 at 6:41
  • For quick formatting of a smallish amount of source, in TeXShop you may use the Experiment menu command, which just compiles the text copied from the clipboard into the Experiment source window, but using the preamble of the root document.
    – murray
    Jan 18, 2023 at 18:26
  • Nice trick indeed +
    – Mikasa
    Jul 19, 2023 at 10:07
10

Regarding your first question: the most noticeable speedup I've witnessed so far can be achieved by compiling to DVI instead of PDF. You may not be able to do that depending on the packages you use, however, but you could give it a try.

0
9

Personally, I use the -interaction=batchmode option to prevent verbose output. Also, for the first runs (except the last), you can use -draftmode option:

-draftmode
   Sets \pdfdraftmode so pdfTeX doesn't write a PDF and doesn't read 
   any included images, thus speeding up execution.

In case of error ($? -ne 0), it is sufficient to tail the log file. You can see the full code on Github.

3
7

Math Accents

Math accents can slow down a compilation. To speed up a document with many of these you can use the \accentedsymbol command defined in amsxtra subpackage of the amslatex package. In the example below, \vx can be used for \vect{x} but will not take the time required to place the accents (arrows on bold symbols for example). Note that since the typesetting is done out of context, some issues can arise (the size will not be small in a superscript for example), so for the final version you should redefine \accentedsymbol to simply define a macro that will get expanded everywhere in context.

\usepackage{amsxtra}
%\renewcommand\accentedsymbol[2]{\def#1{#2}}  % Uncomment for final version
\accentedsymbol{\vx}{\vect{x}}

Note that there are limits to how many symbols you can store this way.

Kpathsea

Not really a LaTeX issue per se, but kpathsea can be a huge performance hit if you are recursively searching directories and/or your ls-R databases are not up-to-date. You can see what it is doing by setting

export KPATHSEA_DEBUG=1

before you run latex. If it is searching many places, then this can be a huge slow-down. Details can be found in the manual. (I had a huge performance hit when I accidentally recursively linked a texmf tree deep within another tree for a package I was writing.)

7

Don't load inputenc and/or fontenc if they are not necessarily needed because:

The inputenc–fontenc combination seems slow and cumbersome, but it’s safe.

cited from Why bother with inputenc and fontenc?

1
  • 26
    This solution is only really gonna be helpful for English documents; as soon as you use about any character outside of the ASCII range, you'll need these packages.
    – doncherry
    Oct 3, 2012 at 0:46
6

It is not about "speeding up" but "how to work when latex is really slow".

I use kile+okular.

  1. In the setting of okular uncheck "reload document on file change".
  2. Add "reload button" to the toolbar of okular

After that you can continue to read pdf file, and reload it only when it is ready.

6

I made a new Python script/module/package for this purpose.

https://github.com/user202729/tex-fast-recompile

(unlike other answers, this does not actually speed up the compilation, but it makes the PDF appear faster after the source code is edited)

I'll quote a section from the readme/documentation:

How does it work?

The principle is very simple. Notice that while the user want fast refresh, the file does not change very frequently.

As such, we start the compiler before the file has changed to process the "preamble", then when the file changed we continue processing the rest of the file.

A graph for illustration:

Before:

(each * represents a file change, |--.--| represents a compilation where the . marks where the preamble processing is done)

+----------------------------------------------------> Time
     *          *                *           *
     |--.--|    |--.--|          |--.--|     |--.--|

After:

+----------------------------------------------------> Time
     *          *                *           *
     |--.--|--. --|--.           --|--.      --|

It can be easily seen that after the change, it only takes 2 instead of 5 time unit from when the file is saved to when the change is reflected in the PDF.


Note on other known methods: (mentioned in the comments etc., collected here for convenience)

Precompile the preamble

There are a few guides on this.

Note

Precompile header with xelatex explain it doesn't work with XeTeX/LuaTeX in some cases.

Externalize TikZ graphics

Refer to Externalizing TikZ-Images takes very long

You can also parallelize TikZ-externalize for some extra performance, refer to https://tikz.dev/library-external#tikz/external/mode (mode=list and make) for instruction; or refer to https://tex.stackexchange.com/a/151255/250119.

5

Depending on your file system, file read/write times might be slowing *latex down. If you are on a Unix like system, you could keep all your resources in RAM. To do so you would first mount a ramdisk:

mkdir /mnt/ramdisk;
sudo mount -t tmpfs -o size=64M tmpfs /mnt/ramdisk;

(be sure to pick a sufficiently large size so your entire project including all resources will fit)

Than every time you want to rebuild, you would run:

rsync --archive --human-readable --progress --update --exclude=\"thesis.pdf\" . /mnt/ramdisk; 
cd /mnt/ramdisk; 
pdflatex thesis.tex; 
cd /path/to/your/thesis;

This syncs all changes you may have made since the last run (using rsync) and than invokes *latex on that copy of your files. The output is found in /mnt/ramdisk/thesis.pdf. I will simply open this in my viewer but at least in some circumstances one might like to sacrifice some time and copy the result to the original location (cp /mnt/ramdisk/thesis.pdf thesis.pdf).

This worked really well for me, as I used this setup to bring down compile times from 45 to 3 seconds.

5
  • How can I find the size required? Can I take size of complete folder with all tex files and images?
    – kaba
    Jan 1, 2020 at 18:02
  • Yes, take the size of all images, tex files and the pdf output and add a view MB just to be on the save side. If your value is to low (latex should give you an error like "cannot read/write file" if that is the case) you can always increase it (maybe using mount -o remount ...). Just don't be too generous. You can use free to check how much RAM is available and you don't want to use significant parts of your RAM unless you really know what you are doing. On my 8GB RAM laptop I wouldn't want to use more than 1GB or 2GB.
    – JakeI
    Jan 1, 2020 at 22:17
  • Thanks for explanation!
    – kaba
    Jan 2, 2020 at 10:49
  • 2
    Sometimes there's already a RAM-disk at /tmp/ -- although check UNIX sites for more details.
    – user202729
    Nov 11, 2021 at 16:17
  • This tip more than halved the compile time for me on a large document! 🚀
    – codeMonkey
    Nov 17, 2023 at 15:03
5
  1. For a large document, I would suggest making seperate tex files and using \include{filename} to include these files into the main file. Then, in the preamble, you can add command \includeonly{filename1} to start working on the file. There has been a quick fix around to comment out the code at \include to temporarily remove the files you are not using, but it disturbs the aux files. So, it's not recommended.
  2. Do not use todonotes package. It seems that i am not the only one who has an slowing down issue with this package.
  3. Use draftmode. It specially helps when you have a lot of images and it can be declared in the very beginning. I choose to keep the declaration code in individual lines so it's simpler to just comment/uncomment the lines to switch draftmode on/off.
\documentclass[
12pt,
draft
]{article}
  1. Don't compile every now and then. It's probably not applicable to you or many others here, but people recently migrating from WYSIWYG softwares like MS word are more used to seeing a compiled document everytime. It helps to get used to read the TEX code for how it is.
1
  • 2
    As for 4, I disagree for large input documents because this contradicts my experience. If I recompile too seldom, the compiler throws errors (e.g, due to my own typos or to package deficiencies), and these errors are sometimes cryptic and hence extremely difficult to debug because it's unknown which of a dozen changes of mine exactly caused them. As for the draft option, it's an interesting one; thx!
    – user292998
    Jun 2, 2023 at 18:52
4

I have a little tip:

If you want to include lots of figures, try to make them in vector graphics (.svg, .pdf, .ps), rather than raster graphics (.jpg, .png).

In my practice, a latex file containing 20 pages & 22 figures takes 56 seconds to compile when all figures are in .png, but only 4 seconds when I replace all of them with .pdf figures.

This may help people like me preparing latex draft for journal publication, since plots made with Python Matplotlib, IDL, Matlab, Origin or Excel can be easily exported in .pdf format.

2
  • PDF may contain also compressed BMP graphics (which is rasterized), so a simple conversion of any image into PDF won't help by itself. You have to be knowing what you are doing or be lucky.
    – user292998
    Jun 2, 2023 at 18:12
  • @AlMa0 Thank you. That's very helpful reminder. This method does not work if one have already raster images and convert them into .pdf . It works when the figure can be exported to vector graphics when it's produced. E.g., fig.savefig('image.pdf') in Python, and save image as - pdf in Excel.
    – Patrick Wu
    Jun 4, 2023 at 5:31
3

So, What I did to handle the costly compilation is that, I first split up the document into the several chapters and every chapter into its own file, using the \input command. The main document has all the \input statements.
Example:
Inside the main_file.tex

\input{chapter1}
\input{chapter1_results}
\input{chapter2}
\input{chapter3}

Only the ones that are critical are not commented out. 'chapter1_results.tex' takes a lot of time to compile because of presence of figures. So I do the following, and its fast as hell.

Inside the main_file.tex

\input{chapter1}
%\input{chapter1_results}
\input{chapter2}
\input{chapter3}
4
  • 2
    This is very similar to Leo Liu's answer.
    – Werner
    Jul 18, 2016 at 19:41
  • 6
    Why don't you use \includeonly as described in Leo Liu's answer?
    – PTNobel
    Jul 18, 2016 at 20:05
  • You are absolutely right! thanks for pointing out. I didnt know there was an \include command unitl now... I looked for \input, but didnt find it... Read the first two answers and glanced over the other comments. I should delete it right? \include makes the whole file a separate logical unit, where as \input just copy&pastes the content. I still find that commenting is easier than typing and removing \includeonly every time you need a file! I guess it might still be useful.
    – Pandian Le
    Jul 18, 2016 at 21:04
  • There's also the standalone package, so you can configure such that the individual files can be compiled manually (instead of editing the main file).
    – user202729
    Nov 11, 2021 at 16:19
2

Guess I'm pretty late to the party, but I use something that has not been mentioned here. My documents contain a significant amount of very high quality images, so I make two copies of the image file with one low resolution jpg and one high resolution png. I rename the files such that they have the suffix LOWRES.jpg or HIGHRES.png (I use png because that's what the image making software exports to). And I made a macro in TeXstudio that switches between the two image files.

This is some of my images in my images folder of my tex document:

enter image description here

And in my tex document I would have something like \includegraphics[width=5cm]{methanalLOWRES.jph} And the suffix would be changed by the macro below depending on whether I want to quickly compile a draft or compile to the best quality (which takes a significantly longer time). I use this in conjunction with \includeonly and it has signficantly reduced the compilation time.

%SCRIPT

scope = editor.document().cursor(0, 0, -1);

if (editor.search("HIGHRES.png", "g") > 0) {
  editor.replace("HIGHRES.png","g",scope,"LOWRES.jpg");

} else {
  if (editor.search("LOWRES.jpg", "g") > 0) {
    editor.replace("LOWRES.jpg","g",scope,"HIGHRES.png");
  }
}

I added this as a script macro on TeXstudio, so I am unsure if it will work on TeXmaker or other LaTeX editors, but the script is fairly basic and you should be able to implement your own for your own situation.

EDIT: I use this website to resize my images https://bulkresizephotos.com. I simply just make the width 800px, and it outputs a lower resolution jpg file which I download (and unzip if multiple files were submitted). I believe imagemagick can do something similar, but I have not looked into it.

I just saw YuppieNetworking's answer above, which is very similar to my answer, nonetheless I will keep my answer here should someone want to use the script

2
  • 7
    You could also define a macro: \newcommand{\res}{LOWRES}, so that you could then \includegraphics{methanal\res.jpg}. Then you could switch the macro when you what the high quality version.
    – Teepeemm
    Jan 3, 2019 at 1:28
  • 3
    ImageMagick: for i in *HIGHRES.png ; do convert -resize 800x $i ${i%HIGHRES.png}LOWRES.png ; done.
    – sztruks
    Jan 13, 2020 at 13:36
1

It is slow and will get even slower (which is an empirically well-established issue for all software development and not only for LaTeX). As usual, the ultimately best way may be to improve the architecture and the source code of (La)TeX and its packages and clean up the messy code in the process. That is, rewrite everything from scratch (which seems to be a project attainable only for folks having both finances and decades to spend on typesetting for the rest of their lifetime), starting with the goals and the documentation (i.e, how things should be). Outdated interfaces might be left out in the process, which, ultimately, would lead to a different and incompatible typesetting system.

The way out is to become a serious typesetting developer or to learn to live with what you get, in particular, slow compilation.

Not being a serious LaTeX developer, I have two versions of any of my large books: a draft version and a clean version. A book has two main files (say, draft.tex and clean.tex, where draft.tex defines my own macro \draft and inputs clean.tex). The program latex compiles the draft version quickly into DVI (sometimes followed by dvips), and lualatex/xelatex compiles the clean version slowly into PDF. Moreover, the document source is split into many files so that I can edit them while both latex and lualatex/xelatex run in the background. The only disadvantage is that your document source will likely have to contain several occurrences of \ifdefined\draft…\else…\fi (most often in the preamble and seldom in the main text), e.g., when loading different fonts and hyperlink-related packages.

2
  • 4
    (For reference Typst took 4 years to be developed, and at the moment it still has lots of bugs left as well as other issues.)
    – user202729
    Jun 2, 2023 at 7:01
  • 2
    @user202729 I presume you mean the time according to the wall clock, which is a rather rough measure. How many man-years, i.e., the pure user time, was spent on Typst?
    – user292998
    Jun 2, 2023 at 17:42
1

Another solution.

Decompress the format file in advance

Technically this method relies on internal implementation details of the engines, but it works anyway.

You can do the following. Assuming the file to be compiled is helloworld.tex.

gunzip < "$(kpsewhich -engine=luahbtex lualatex.fmt)" > lualatexunzipped.fmt
lualatex '&lualatexunzipped' helloworld.tex

The first command should be done once, and keep the resulting generated lualatexunzipped.fmt file in the same directory as the TeX file (or somewhere that is pointed to by kpsewhich -var-value=TEXFORMATS).

Then, the second command should be used to compile a file instead of the usual lualatex helloworld.tex.

Speed up:

$ time lualatex helloworld.tex
real    0m0.775s
user    0m0.546s
sys     0m0.215s
$ cp "$(kpsewhich -engine=luahbtex lualatex.fmt)" lualatexa.fmt
$ time lualatex '&lualatexa' helloworld.tex
real    0m0.642s
user    0m0.490s
sys     0m0.145s
$ time lualatex '&lualatexunzipped' helloworld.tex
real    0m0.543s
user    0m0.382s
sys     0m0.155s

Note that if the format file name is lualatex then apparently kpathsea will be invoked to search something, which takes another approximately 0.1 seconds. Thus, copying the format file to ./lualatexa.fmt alone (without decompression) already save 0.1s.

You can save ≈ 0.1 to 0.2 seconds per compilation this way. Significant if your file is small.

Explanation

First, read my answer on precompiled preamble to understand what .fmt format files are.

Then, roughly speaking, this is because the implementation of the TeX engines use the gzip format for the .fmt files, and gzdopen function is used to read the file. However, it has a compression level 0 which states that the input is the same as the output.

As long as the decompressed file is not a valid gzip archive (and that gzdopen does not complain when the level being passed in is different from the level of the actual archive), everything should be fine.

Note 2

If the decompressed file happens to be a valid gzip archive (perhaps because it starts with the magic number 1f 8b?) then you might be able to use the following to compress it at level 0:

python -c 'import sys, gzip; sys.stdout.buffer.write(gzip.compress(sys.stdin.buffer.read(), compresslevel=0))' < lualatexunzipped.fmt > lualatexzipped0.fmt

My version of gzip does not accept -0 as input, although it accepts -1 until -9.

Note

Unsurprisingly, this will bloat the format file size.

From LuaTeX source code:

/*tex

    Tests has shown that a level 3 compression is the most optimal tradeoff
    between file size and load time.

*/

#define COMPRESSION "R3"

For other engines

gunzip < "$(kpsewhich -engine=xetex xelatex.fmt)" > xelatexunzipped.fmt
xelatex '&xelatexunzipped' helloworld.tex

gunzip < "$(kpsewhich -engine=pdftex pdflatex.fmt)" > pdflatexunzipped.fmt
pdflatex '&pdflatexunzipped' helloworld.tex

Combine this solution with precompiled preamble

Similarly, this solution can be combined with precompiled preamble for even more speedup.

Dangerous: modify the user format files

Do the following.

mktexfmt pdflatex
pdflatex_fmt="$(kpsewhich -engine=pdftex pdflatex.fmt)" 
mv "$pdflatex_fmt" "$pdflatex_fmt".gz
gunzip "$pdflatex_fmt".gz

mktexfmt xelatex
xelatex_fmt="$(kpsewhich -engine=xetex xelatex.fmt)" 
mv "$xelatex_fmt" "$xelatex_fmt".gz
gunzip "$xelatex_fmt".gz

mktexfmt lualatex
lualatex_fmt="$(kpsewhich -engine=luahbtex lualatex.fmt)" 
mv "$lualatex_fmt" "$lualatex_fmt".gz
gunzip "$lualatex_fmt".gz

In each block, the first command creates a per-user format file. Read the warning.

*************************************************************
*                                                           *
* WARNING: you are switching to fmtutil's per-user formats. *
*         Please read the following warnings!               *
*                                                           *
*************************************************************

You have run fmtutil-user (as opposed to fmtutil-sys) for the first time;
this has created format files which are local to your personal account.

From now on, any changes in system formats will *not* be automatically
reflected in your files; furthermore, running fmtutil-sys will no longer
have any effect for you.

As a consequence, you yourself have to rerun fmtutil-user after any
change in the system directories. For example, when one of the LaTeX or
other format source files changes, which happens frequently.
See https://tug.org/texlive/scripts-sys-user.html for details.

If you want to undo this, remove the files mentioned above.

The remaining 3 commands just decompress that file.

Note, however, that this solution is slightly slower than the solution above because of kpathsea path search for something.

References

  • texdoc pdftex documents the usage of TEXFORMATS and other Web2c variables.
0

There's this solution...

First, the disadvantages

  • only works on POSIX systems
  • requires LuaLaTeX
  • somewhat cumbersome (for now)
  • requires shell-escape and manually install some Lua library
  • may fail to work for weird reasons, or damage your computer

The only advantages are...

  • real incremental compilation! (*)
  • cheaper than BaKoMa (†)
  • supports LuaLaTeX

(*): My attempts to use precompiled preamble (which is basically user-written format file) in LuaLaTeX has all failed, partially because Lua states and some other things cannot be dumped. maybe I should just switch back to pdflatex for the speed, especially now I am better at forcing TeX to do what I want (†): There's now WYSIWYG editing though. (unfortunately)


The basic idea is to use fork() to spawn new process when part of the file change, instead of re-run it from scratch.

Proof of concept code:

%! TEX program = lualatex
\documentclass[12pt]{article}
\usepackage[paperheight=5cm,paperwidth=5cm,margin=0.6cm]{geometry}
\usepackage{luacode}
\usepackage{luapackageloader}
\begin{document}

% you can write some LaTeX here too

\begin{luacode*}
-- load the package
package.path = "/usr/share/lua/5.3/?.lua;/usr/share/lua/5.3/?/init.lua;/usr/lib/lua/5.3/?.lua;/usr/lib/lua/5.3/?/init.lua;./?.lua;./?/init.lua"
package.cpath = "/usr/lib/lua/5.3/?.so;/usr/lib/lua/5.3/loadall.so;./?.so"
local posix=require "posix"

function copyfile(source, target)
    local infile=io.open(source, "rb")
    local outfile=io.open(target, "wb")
    outfile:write(infile:read("*all"))
    infile:close()
    outfile:close()
end

--first backup the partial PDF content
copyfile(tex.jobname..".pdf", "backup-"..tex.jobname..".pdf")
copyfile(tex.jobname..".log", "backup-"..tex.jobname..".log") -- strictly speaking this is not necessary

while true do
    local pid = posix.fork()
    if pid == 0 then
        -- is child, compile b.tex
        break
    else
        -- is parent
        posix.wait(pid) 
        print("======== Press enter to recompile ========")
        io.read()
        -- **critical**: restore the partial PDF content
        copyfile("backup-"..tex.jobname..".pdf", tex.jobname..".pdf")
        copyfile("backup-"..tex.jobname..".log", tex.jobname..".log")
    end
end
\end{luacode*}

\input{b.tex}

\end{document}

First create a file named b.tex, put in some content.

Then run lualatex a.tex where a.tex is the main file (above).

When you edit b.tex, press enter in the lualatex process. It will regenerate a.pdf instantaneously... as long as b.tex isn't too long.

3
  • Actually this solution is quite buggy and more likely to fail than not.
    – user202729
    Apr 2, 2022 at 7:47
  • Actually no-backup (other than hard-link to preserve the (busy) file) seems to be sufficient for pdf and synctex. But aux is the odd one, it doesn't seek.
    – user202729
    Apr 2, 2022 at 8:45
  • Another thing (unrelated to this answer however), \usepackage speed is improved in newer expl3 version, so upgrading might make it faster, see chat.stackexchange.com/transcript/message/60905323#60905323 for some discussion.
    – user202729
    Apr 16, 2022 at 10:37
0

Another solution:

Use Tectonic

Tectonic is a modernized, complete, self-contained TeX/LaTeX engine, powered by XeTeX and TeXLive.

-- https://tectonic-typesetting.github.io/en-US/

If you're using XeLaTeX/LuaLaTeX and needs its Unicode support, Tectonic appears to be a good option. Otherwise, there is always the option of switching to PDFLaTeX.

To my surprise, even though it is based on XeLaTeX, it is actually faster than XeLaTeX (for the files I tested).

I don't know why it's faster (but a guess is that it avoids the kpathsea path lookup overhead).

Benchmark

For the following file:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
    \draw (0, 0) to [bend left] (2, 1);
    \draw (0.7, -0.4) -- (0.8, 1.2);
\end{tikzpicture}
\end{document}

I benchmark it with hyperfine and get:

[tmp]$ hyperfine --warmup=1 'tectonic --keep-intermediates a.tex' 'xelatex a.tex'
Benchmark 1: tectonic --keep-intermediates a.tex
  Time (mean ± σ):     643.8 ms ±  53.5 ms    [User: 551.1 ms, System: 88.6 ms]
  Range (min … max):   594.0 ms … 742.8 ms    10 runs
 
Benchmark 2: xelatex a.tex
  Time (mean ± σ):     834.2 ms ±  43.5 ms    [User: 484.7 ms, System: 345.3 ms]
  Range (min … max):   792.2 ms … 903.7 ms    10 runs
 
Summary
  tectonic --keep-intermediates a.tex ran
    1.30 ± 0.13 times faster than xelatex a.tex

For the following file:

\documentclass{article}
\usepackage{lipsum}
\begin{document}
\lipsum[1-20]
\end{document}

The benchmark is:

Benchmark 1: tectonic --keep-intermediates a.tex
  Time (mean ± σ):     478.7 ms ±   4.9 ms    [User: 391.1 ms, System: 84.5 ms]
  Range (min … max):   472.1 ms … 485.8 ms    10 runs
 
Benchmark 2: xelatex a.tex
  Time (mean ± σ):     522.6 ms ±  13.3 ms    [User: 348.0 ms, System: 184.9 ms]
  Range (min … max):   512.5 ms … 553.6 ms    10 runs
 
Summary
  tectonic --keep-intermediates a.tex ran
    1.09 ± 0.03 times faster than xelatex a.tex

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .