xfig 3.2.9 taking ages to open a large file (font loading caching missing?)
Xfig is a diagramming tool
Brought to you by:
tklxfiguser
Hello,
Since version 3.2.9, xfig takes ages to open my large xfig files (count a couple minutes), such as the attached file, while 3.2.8 didn't have the issue, the file would open in less than a second. Running through gdb shows this:
(gdb) bt
#0 0x00007f762c96fde4 in FcFontSetMatchInternal (sets=sets@entry=0x7ffc86b70c00, nsets=<optimized out>, p=p@entry=0x55e57de1eac0, result=result@entry=0x7ffc86b70c9c) at ./src/fcmatch.c:896
#1 0x00007f762c970e5f in IA__FcFontMatch (config=0x55e57cdd1750, p=0x55e57de1eac0, result=0x7ffc86b70c9c) at ./src/fcmatch.c:1082
#2 0x00007f762ccc18c3 in XftFontMatch () from /lib/x86_64-linux-gnu/libXft.so.2
#3 0x000055e57c64bbe7 in getfont (psflag=<optimized out>, fnum=0, size=210, angle=0) at u_fonts.c:256
#4 0x000055e57c64be85 in textextents (t=t@entry=0x55e57de1f540) at u_fonts.c:326
#5 0x000055e57c62f498 in read_textobject (fp=fp@entry=0x55e57ce29bd0) at f_read.c:1587
#6 0x000055e57c630fa8 in read_objects (res=0x7ffc86b716e8, obj=0x7ffc86b719f0, fp=0x55e57ce29bd0) at f_read.c:585
#7 readfp_fig (settings=0x7ffc86b719b0, yoff=<optimized out>, xoff=<optimized out>, merge=<optimized out>, obj=0x7ffc86b719f0, fp=0x55e57ce29bd0) at f_read.c:394
#8 read_fig (file_name=file_name@entry=0x55e57c726dc0 <cur_filename> "graph-radial.fig", obj=obj@entry=0x7ffc86b719f0, merge=merge@entry=0 '\000', xoff=xoff@entry=0, yoff=yoff@entry=0,
settings=settings@entry=0x7ffc86b719b0) at f_read.c:231
#9 0x000055e57c631c33 in read_figc (file_name=file_name@entry=0x55e57c726dc0 <cur_filename> "graph-radial.fig", obj=obj@entry=0x7ffc86b719f0, merge=merge@entry=0 '\000',
remapimages=remapimages@entry=1 '\001', xoff=xoff@entry=0, yoff=yoff@entry=0, settings=0x7ffc86b719b0) at f_read.c:144
#10 0x000055e57c62b14b in load_file (file=file@entry=0x55e57c726dc0 <cur_filename> "graph-radial.fig", xoff=xoff@entry=0, yoff=yoff@entry=0) at f_load.c:91
#11 0x000055e57c6010b7 in main (argc=<optimized out>, argv=<optimized out>) at main.c:1374
using finish a bit I end up getting stuck in:
(gdb) finish
Run till exit from #0 readfp_fig (settings=0x7ffc86b719b0, yoff=<optimized out>, xoff=<optimized out>,
merge=<optimized out>, obj=0x7ffc86b719f0, fp=0x55e57ce29bd0) at f_read.c:394
I.e. it's readfd_fig, which seems to be calling read_objects a lot of times (which makes sense since the file is large), and it's probably something like XftFontMatch which is getting called too many times, as if xfig was reloading the font repeatedly for each object it is loading from the file?
Samuel
Right, XftFontMatch is called repeatedly. From the documentation and sources of Xft I believed Xft would use an internal cache of opened fonts, no cache in the application needed. This believe seems to mistaken. Or, the hash Xft computes to compare fonts takes that long.
Ok, but this didn't use to be a problem with 3.2.8, so something must have changed in that regard within xfig itself
Since 3.2.9 Xft instead of X core fonts are used. The display of fonts on the canvas should be much nicer.
Mmm, much nicer indeed but terribly slow to render for such kind of file, and thus becomes unusable. Is there a run-time way to revert back to X core fonts?
Changing to Xft fonts was a big change in the codebase. I do not see a way to go back, not even as a compilation option. Switching off anti-aliasing and hinting did not help either (here below an entire .conf/fontconfig/fonts.conf file),
Thus, an issue reported to me in private communication seems to be closely related: Put a text object, say "a", copy it 99 times horizontally, put into a compound, copy 99 times vertically. Save and open. Opening, as well as zooming, takes on the order of a minute. However, translating the figure is fast.
From the above, it seems that indeed the font matching is the underlying cause. That could be solved within xfig, building up some internal cache probably after profiling. Do not expect a soon fix, though. I plan to publish release 3.2.9a soon, but I am afraid I will not be able to fix this issue with the upcoming release.
Hi! I finally have some progress with this issue (it's annoying for me too). I managed to split Xft text drawing into slow font matching/loading (it can be done once in the very beginning for all fonts) and fast transformation + drawing. Unfortunately libxft public interface does not support it directly, I need to access it's internal structures (and add corresponding h-file).
Also, I can see some annoying angle quantization about 1deg, but I see it in xfig too.
Please have a look into the simple test program in the attachment.
Hi Vladislav,
in the meantime I also profiled xfig and found out that, indeed, the font loading, and here probably the font matching during the loading stage, took more than 98% of the time. Therefore I plan to build a font cache in xfig itself. From the documentation of Xft, the library should keep a cache internal to Xft, but probably it is not fast, or it should be accessed in a different way than is done in xfig. Anyway, I plan to open a font only once, but once for each font size, display zoom factor and font angle. This is different from the approach you showed, but should also yield a reasonable performance except for pathological cases (think: a waterfall of a font, or a star consisting of hundreds of radial texts aroun a circle). For the majority of drawings only a few fonts are used, hence keeping the font and manipulating the internal transformation matrix should not be necessary. (I still wonder that the font matching is the bottleneck, not the rendering stage. But perhaps the font matching involves disk seeks or expensive calls to fontconfig, thus the observed performance.)
Thinking about it, even if a pattern from an already opened font is used, just with a different font size, asking xft to open that font still will involve fontconfig, since in the meantime the fonts on disk could have changed. Thus, with my font cache as sketched above, zooming still would be expensive (but far less expensive than the current state in xfig). Also, I plan to access the font cache only lazily, i.e., fonts are only requested when they are on screen, instead of, e.g., immediately re-rendering each text object on a change of the zoom factor.
I am happy about your test program. I thought there is an quantization internally in xfig, but the test program nicely shows that the quantization comes from xft. Also, it shows wrong rotation of the individual letters, which I also observed anecdotically in xfig.
What do you think about the plan of loading fonts once, but not to touch the internal structures?
Yours,
Wrong rotation appears with Courier in my xfig; On my computer, fc-match courier finds a type 1 font from the TeX installation, /usr/share/fonts/type1/texlive-fonts-recommended/pcrr8a.pfb. The DejaVu Sans Mono font requested in your test program is truetype, though.
I like the idea of opening font once and then rescaling/rotating it. If you open a separate font for each rotation/scale you will still need to re-open all fonts for every zoom-in/zoom-out, for every object rotation. Also it's easier to have a fixed array of fonts instead of cache. On the other hand, it's good to use public interface of Xft, in my approach I had to use internal structures.
As I understand, internal Xft (or freetype) cache is for glyphs inside a font. It you reopen the font, you are not using it.
The quantization can come from angle/distance representation in libfreetype: 16.16 numbers for angles, 26.6 for distances. This precision looks OK, but it could decrease in some calculations (if you convert distance to angle, for example)
Wrong glyph rotation looks like an error in interaction between Xft and freetype. I did not see it yet.
Sorry, that is what I meant: A fixed array of the 34 different fonts in xfig, but a linked list for each of those fonts at different sizes / angles. That would, correctly, require re-opening for every zoom and rotation, but for rotation only for the rotated objects.
Incorrect rendering of rotated text is a bug in Xft, 2.3.5 <= libXft < 2.3.8, see issue 18.
I have a hack for fixing the angle quantization problem in xft: . Modified xft_test.c is attached.
I'm just drawing symbols one-by-one and fixing shift between them. Not a very nice solution, but I'm not sure that it can be done better with xft.
(By the way, should we make a separate ticket for this problem? It's not related to font loading)
Finally, with commit [ee087c] a font cache is implemented. Together with another small change introduced with [e13b9d] the huge drawing attached above, graph-radial.fig (sourceforge.net) is rendered as fast as with xfig 3.2.8b. On my aging machine both took 3 seconds to open. A fig file with text in all possible fonts also took about 3 seconds to open, 2 seconds with version 3.2.8b. Rendering with xft still seems a bit slowlier than using X core fonts, but then xft does anti-aliasing with greyscales, while core X fonts are displayed black and white only. I would consider this issue closed. Please report, if you still find issues.
Regarding discrete angles of rotated text, this is a property of xft and will not be hacked over in xfig. See ticket [#169].
Related
Tickets:
#169Commit: [e13b9d]
Commit: [ee087c]
Great news, thank you very much! I will check it
I can confirm that in my use case it's now as fast as with 3.2.8, thanks a lot!
I believe, with commit [8924de] xfig now opens graph-radial.fig slightly faster than xfig 3.2.8b.
Related
Commit: [8924de]