Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: cache calculations for 'ch' and 'ex' units #1587

Merged
merged 2 commits into from
Mar 19, 2022

Conversation

aschmitz
Copy link
Contributor

@aschmitz aschmitz commented Mar 3, 2022

I get a ~30% speedup from caching this calculation on a relatively large (~300 page) test document. We use a fair number of ch-based lengths, but not an absurd amount. Regardless, this seems to provide a significant speedup as measured by hyperfine:

Command Mean [s] Min [s] Max [s] Relative
Original 67.992 ± 1.279 66.966 71.106 1.46 ± 0.04
Cached 46.707 ± 1.056 45.688 49.402 1.00

It wasn't immediately clear to me where a cache for these would be best, but this has it anchored at any style root rather than globally, as arguably the fonts might change between documents. (That said, actually handling @font-face fonts seems to be a TODO here at the moment anyway.)

@liZe liZe modified the milestones: 56.0, 55.0 Mar 4, 2022
@liZe liZe added the performance Too slow renderings label Mar 4, 2022
@liZe
Copy link
Member

liZe commented Mar 7, 2022

Thanks (again!) for this pull request.

It wasn't immediately clear to me where a cache for these would be best, but this has it anchored at any style root rather than globally, as arguably the fonts might change between documents. (That said, actually handling @font-face fonts seems to be a TODO here at the moment anyway.)

Yes, I suppose that the cache should be stored in the FontConfiguration class. It would avoid one more "memory leak", and give the user the possibility to flush it if needed.

Moreover, the 1ch / 1em and 1ex / 1em ratios could probably be calculated once for each font face, and maybe without even using Pango (that’s needlessly expensive for what we want to achieve).

But it’s not easy to do. What do you think?

@aschmitz
Copy link
Contributor Author

aschmitz commented Mar 9, 2022

Attaching the configuration to a FontConfiguration is fair, I'll investigate doing that when I get some time.

It wasn't immediately clear to me what could potentially affect the ratios for each type: certainly the features could (tabular figures could affect the 1ch size), style will, stretch will, weight will. I know that OpenType hinting can change with font size, but I can't think of anything that would actually modify the glyphs themselves. (But, truthfully, since I couldn't rule it out, I included it in the cache.)

If we're fairly sure that the ratio doesn't change for a given font configuration across different sizes, it may be easy enough to simply cache that instead, as this is already doing it for 1ex/1em.

Doing the calculation without Pango seems like it could potentially be nice from a philosophical point of view, but with the caching it would be unlikely to be a huge time savings, so I'd probably wait until more things are shifted over to HarfBuzz rather than spend a bunch more effort on it here, since we already have nearly-working code, if that seems reasonable. (I could simply modify the 1ex/1em calculation to also handle 1ch/1em.)

aschmitz referenced this pull request Mar 9, 2022
This commit adds many small improvements in the way fonts are managed.

1. Most of the font deduplication logic has been put in add_font(), instead of
draw_first_line().

2. Font objects now have only one (reproducible) hash, based on the font
content and the face index. Before this commit, we had 3 (!) different hashes.
Fixes #1553.

3. Font fields are calculated during initialization, to avoid useless
parameters storage.

4. Harfbuzz face is not read twice from Pango font when a new Font is added.

5. Font face deduplication is now done using the Pango face pointer, instead of
the Harfbuzz face hash extracted from the Pango font. This could save some
time, especially for very long documents always using the same font face.

6. Font name displayed in PDF now includes weight and style.
@aschmitz
Copy link
Contributor Author

Digging a bit further, I'm not sure I can actually attach this to a FontConfiguration object the way styles are handled right now. I think the current style doesn't actually have a context object accessible to it, which is also the reason for all the "TODO: use context to use @font-face fonts" notes in computed_values.py.

Do you see a good way to get one in? If not, I can push the refactor to just cache a ratio for the ex and ch sizes for now, and get to the other refactor later

Presumably eventually you'll want to plumb through the context or at least a FontConfiguration object to the style, but it's not clear that this PR is necessary the right place to do that unless you see an easy way.

Based on review comments. Also modifies inline_box_verticality to use
the cache rather than recalculate every time.
@aschmitz
Copy link
Contributor Author

This now has the ratio calculation code that lets our cache be independent of font size.

@liZe: does this seem like something you'd be willing to merge as-is, or do we need to plumb FontConfiguration / context in to style handling first?

@liZe
Copy link
Member

liZe commented Mar 17, 2022

This now has the ratio calculation code that lets our cache be independent of font size.

@liZe: does this seem like something you'd be willing to merge as-is, or do we need to plumb FontConfiguration / context in to style handling first?

It’s OK, thanks for your second commit. We don’t need FontConfiguration for now, we can keep the attribute on style. I’ll take the time to merge it soon, and maybe to change a couple of minor things to please the problems I have in my head 😁.

@liZe liZe merged commit 3538b1c into Kozea:master Mar 19, 2022
liZe added a commit that referenced this pull request Mar 19, 2022
It avoids the impression that the cache is global. And it actually was, because
"copy" on the dictionary doesn’t copy children dictionaries.

Related to #1587.
liZe added a commit that referenced this pull request Mar 19, 2022
Also fixes the ex value used for vertical-align: middle.

Related to #1587.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance Too slow renderings
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants