fontconfig is slow
- AndrewAPrice
- Member
- Posts: 2300
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
fontconfig is slow
(Mostly a rant, unless others have encountered and solved this problem.)
I ported fontconfig to my OS as a dependency of Skia, and it is slow.
Specifically, the operation in Skia's SkFontConfigInterfaceDirect::matchFamilyName calls FcConfigReference, which iterates over the 22 .ttf files I have in my font directory. This takes minutes! I tried using Skia's custom font directory instead of FontConfig, but it also takes minutes, as it opens each font with TrueType and reads the faces out.
Minutes seems ridiculously long to iterate over 22 fonts. Especially if it happens at the launch of each of program. I suppose this is the purpose of the fc-cache tool, and I should create the cache as part of my build process and bundle it with my OS image?
I ported fontconfig to my OS as a dependency of Skia, and it is slow.
Specifically, the operation in Skia's SkFontConfigInterfaceDirect::matchFamilyName calls FcConfigReference, which iterates over the 22 .ttf files I have in my font directory. This takes minutes! I tried using Skia's custom font directory instead of FontConfig, but it also takes minutes, as it opens each font with TrueType and reads the faces out.
Minutes seems ridiculously long to iterate over 22 fonts. Especially if it happens at the launch of each of program. I suppose this is the purpose of the fc-cache tool, and I should create the cache as part of my build process and bundle it with my OS image?
My OS is Perception.
Re: fontconfig is slow
You can just cache these files into memory, or make a faster disk driver. A typical hard drive can read these 22 fonts in less than a second.
- AndrewAPrice
- Member
- Posts: 2300
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: fontconfig is slow
Fontconfig just provides enumeration and matching of fonts?
This might be better provided by a service that can be queried via an RPC than a library and every program has to load and process data from disk.
This might be better provided by a service that can be queried via an RPC than a library and every program has to load and process data from disk.
My OS is Perception.
- AndrewAPrice
- Member
- Posts: 2300
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: fontconfig is slow
I noticed it does a lot of small reads, such as 30 bytes at a time. I'm not doing caching at the libc level so each one of these involves 2 RPCs and disk IO.devc1 wrote:You can just cache these files into memory, or make a faster disk driver. A typical hard drive can read these 22 fonts in less than a second.
My OS is Perception.
Re: fontconfig is slow
Well, there’s your solution. You need to implement buffered I/O.AndrewAPrice wrote:devc1 wrote:I'm not doing caching at the libc level so each one of these involves 2 RPCs and disk IO.
Re: fontconfig is slow
That's what I was going to say !
Implement a VFS that contains these files loaded in memory.
Implement a VFS that contains these files loaded in memory.
Re: fontconfig is slow
It’s not the file system. It’s the library call that implements the read function. It should implement a buffer so that several I/O operations require only a single system call. Not only does this save system calls but it also reduces the number of (very slow) disk read operations.
- AndrewAPrice
- Member
- Posts: 2300
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: fontconfig is slow
I found an issue: musl does buffer file io, however musl's fseek clears the buffer.
There's a lot of back and forth jumping as fontconfig/freetype try to parse the fonts. Reading 16 bytes from position 172, seeking to 270568 to read 4 bytes, then seeking back to position 188. Or, we'll read 32 bytes from 291146, then seek 19 bytes ahead from 291178 to 291197. Another time, we seek to 444, read 2 bytes, see we seek to 454, read 2 bytes, seek to 462, read 6 bytes, seek to 468, read 6 bytes. etc. Approx 2446 times we try to read 2 bytes from position 270660.
According to https://freetype.org/freetype2/docs/des ... ign-4.html:
There's a lot of back and forth jumping as fontconfig/freetype try to parse the fonts. Reading 16 bytes from position 172, seeking to 270568 to read 4 bytes, then seeking back to position 188. Or, we'll read 32 bytes from 291146, then seek 19 bytes ahead from 291178 to 291197. Another time, we seek to 444, read 2 bytes, see we seek to 454, read 2 bytes, seek to 462, read 6 bytes, seek to 468, read 6 bytes. etc. Approx 2446 times we try to read 2 bytes from position 270660.
According to https://freetype.org/freetype2/docs/des ... ign-4.html:
Perhaps I need to add memory mapped file support.As an example, the default implementation of streams is located in the file src/base/ftsystem.c and uses the ANSI functions fopen, fseek, and fread. However, the Unix build of FreeType 2 provides an alternative implementation that uses memory-mapped files, when available on the host platform, resulting in a significant access speed-up.
My OS is Perception.
- AndrewAPrice
- Member
- Posts: 2300
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: fontconfig is slow
I implemented memory mapped IO, and it sped fontconfig up from minutes to seconds. I see that fontconfig is looking every which direction for a cache file, and that would speed up each launch if it could just open a single file rather than recomputing on each process launch. The fastest thing would be to try to avoid any file read at all.
Skia calls fontconfig to do one thing, which is to find a font that matches a family and style. This is something we could do via an RPC to a service, and save having to create an instance of fontconfig for each process. I'm building a Font Manager that loads fontconfig and exposes a MatchFont RPC. To speed things up even further, my Font Manager could cache my default fonts in memory to avoid any file IO.
Skia calls fontconfig to do one thing, which is to find a font that matches a family and style. This is something we could do via an RPC to a service, and save having to create an instance of fontconfig for each process. I'm building a Font Manager that loads fontconfig and exposes a MatchFont RPC. To speed things up even further, my Font Manager could cache my default fonts in memory to avoid any file IO.
My OS is Perception.
- AndrewAPrice
- Member
- Posts: 2300
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: fontconfig is slow
I implemented my Font Manager and substituted Skia's calls to fontconfig to be RPCs. Now the redundant work doesn't have to happen for each process.
Each process still needs to load the matched font, but so far this is much fast. I have shared memory (I added read-only support for MMIO), so a step further would be to cache common UI fonts in the Font Manager, and then it can return either a file path or a memory buffer.
Each process still needs to load the matched font, but so far this is much fast. I have shared memory (I added read-only support for MMIO), so a step further would be to cache common UI fonts in the Font Manager, and then it can return either a file path or a memory buffer.
My OS is Perception.