latex3 / unicode-math

XeLaTeX/LuaLaTeX package for using unicode/OpenType maths fonts
http://ctan.org/pkg/unicode-math
LaTeX Project Public License v1.3c
239 stars 28 forks source link

Loading multiple math font is slow #520

Open stone-zeng opened 5 years ago

stone-zeng commented 5 years ago

Description

If setting more than one fonts, then the time for loading a single font becomes longer and longer.

Add info or delete as appropriate:

Further details

\documentclass{article}
\usepackage{l3benchmark,unicode-math}

\ExplSyntaxOn
\clist_map_inline:nn
  {
    Thin, UltraLight, ExtraLight, Light, Book, Regular,
    Medium, SemiBold, Bold, ExtraBold, Heavy, Ultra
  }
  { \benchmark_once:n { \setmathfont { FiraMath-#1.otf } [ version = #1 ] } }
\ExplSyntaxOff

\begin{document}
NULL
\end{document}

On my computer, a typical result is as the following:

...
0.12 seconds (5.2e5 ops)
0.138 seconds (6e5 ops)
0.124 seconds (5.43e5 ops)
0.126 seconds (5.51e5 ops)
0.127 seconds (5.52e5 ops)
0.129 seconds (5.57e5 ops)
0.129 seconds (5.64e5 ops)
0.13 seconds (5.67e5 ops)
0.131 seconds (5.69e5 ops)
0.146 seconds (6.41e5 ops)
0.136 seconds (6.02e5 ops)
0.145 seconds (6.24e5 ops)
...

You may find that the time used and operations are all increasing.

After some investigation, I find the problem is in \@@_mathmap_noparse:nnn, where

\cs_new:Nn \__um_mathmap_noparse:nnn
  {
    % DEBUG
    % \tl_log:c { g__um_switchto_#1_tl }
    \tl_gput_right:cx { g__um_switchto_#1_tl }
      {
        \__um_set_mathcode:nnnn {#2} {\mathalpha} {\l__um_symfont_label_tl} {#3}
      }
  }

Notice that if #1 is literal here, \g__um_switchto_#1_tl will not be cleared. As we loading more fonts, this tl becomes extremely large, so makes the expansion and assignment slower and slower. For other situations e.g. #1=up, there is no such problem.

wspr commented 5 years ago

Thanks for the detailed analysis. You’re completely right — really the entire “version” feature needs careful re-consideration. The way it interacts with “range” is not handled properly, and this is another example of what goes wrong.

I’ll need to do some testing but I suspect clearing the tl here will be no worse than the current behaviour. I suspect a proper fix would be to have version-specific versions of these token list variables...