diagrams / SVGFonts

Fonts from the SVG-Font format
http://hackage.haskell.org/package/SVGFonts
Other
20 stars 12 forks source link

Fonts are loaded repeatedly #16

Closed byorgey closed 7 years ago

byorgey commented 9 years ago

It seems that fonts are sometimes repeatedly reloaded from disk, once for each call to textSVG or a similar function. See the previous discussion at https://github.com/timbod7/haskell-chart/pull/83 .

tkvogt commented 9 years ago

I will add a function that uses a lookup to prevent this

byorgey commented 9 years ago

I'm not sure I understand. How exactly will doing a lookup prevent this?

tkvogt commented 9 years ago

haskell-chart already uses a lookup for custom fonts. The default fonts on the other hand have no lookup and the compiler most likely does not recognize constant assignement in a do notation of a paramerterized function. To prevent a mistake like this it is convenient to add a global Hashmap that caches the Font data, although it might add a little overhead.

byorgey commented 9 years ago

Hmm, I see. It is certainly worth trying.

Fuuzetsu commented 7 years ago

Hi; this is still around and makes performance honestly not acceptable in any application using textSVG multiple times, sadly. Is there any plan to fix it? I may give it a go shortly but if there's a patch lying around somewhere I'd rather spare myself the pain.

Fuuzetsu commented 7 years ago

Hm, upon testing, seems loading only happens once. Perhaps something else should be blame for poor performance now.


main :: IO ()
main = renderSVG "/tmp/rendered.svg" (dims2D 500 500) $
  vcat $ flip map [1 .. 10] (\i -> stroke $ textSVG' textOpts ("STRING " ++ show i))

textOpts :: TextOpts Double
textOpts = TextOpts
  { textFont = lin
  , mode = INSIDE_H
  , spacing = KERN
  , underline = False
  , textWidth = 20
  , textHeight = 20 }
COST CENTRE       MODULE                            %time %alloc

>>=.\             Data.Attoparsec.Internal.Types     23.0   15.8
>>=.\.succ'       Data.Attoparsec.Internal.Types     18.3    9.0
>>=               Data.Attoparsec.Internal.Types      6.1    0.0
plus.\            Data.Attoparsec.Internal.Types      4.4    7.5
fmap.\            Data.Attoparsec.Internal.Types      4.1    4.1
fmap.\.succ'      Data.Attoparsec.Internal.Types      3.5    7.0
breakn            Text.XML.Light.Lexer                3.2    5.8
decode_text.(...) Text.XML.Light.Lexer                2.9    7.7
plus.\.lose'      Data.Attoparsec.Internal.Types      2.6    0.0
breakn.(...)      Text.XML.Light.Lexer                2.5    8.5
linenumber        Text.XML.Light.Lexer                1.9    9.3
plus              Data.Attoparsec.Internal.Types      1.7    0.0
pure.\            Data.Attoparsec.Internal.Types      1.6    0.0
*>                Data.Attoparsec.Internal.Types      1.6    1.4
myfloat           Graphics.SVGFonts.ReadPath          1.3    0.2
atParam           Diagrams.Segment                    1.2    1.7
decimal.step      Data.Attoparsec.ByteString.Char8    1.0    0.8
pathFromString    Graphics.SVGFonts.ReadPath          1.0    0.1
pathElement       Graphics.SVGFonts.ReadPath          1.0    0.3
loadFont          Graphics.SVGFonts.ReadFont          0.9    2.8
decode_attr       Text.XML.Light.Lexer                0.7    3.3
uncons            Text.XML.Light.Lexer                0.4    2.7

I suppose this can be closed in favour of "parser sucks" ticket or something of sorts

byorgey commented 7 years ago

@Fuuzetsu thanks for the nudge on this issue. Can you be more specific about the poor performance you are seeing? If the parser is only being called once then it should not make a difference how many times you use textSVG.

Fuuzetsu commented 7 years ago

I think there are few problems:

  1. Initial load overhead is too high: if we want to render few pieces of text, it sucks that loading the font takes so long; better loading qould help here. I managed to speed up parser by third pretty trivially on a branch somewhere

  2. Following up on above, memory cost seems way too high for what we're doing, we're reading 18MB file in effectively a flat format so why does it take so 100+MB resident memory to load the font? This sucks for programs where memory cost would otherwise be low.

  3. Actual usage seems to cost a lot. Even for simple, short strings it takes a lot of time and memory to create a Diagram. If you have multiple strings then things get really bad. For examppe I was able to reduce memory usage and runtime by around an order of magnitude just by reducing number of times we call textSVG. I have to measure if maybe it's worth rendering 1 big string at once where possible. For comparison, using text from diagrams instead of textSVG nearly completely eliminates any runtime and memory issuea from ghc-events-anaylze whereas it qould happily take many many minutes and tens of GBs of memory even on small input.

I can maybe fix 1 and 2 reducing constant overhead but really I'm interested in 3. Honestly I just want some fast text, not even vectorised, that is sized as far as diagrams is concerned. My current hack is to take longest string from my set, textSVG and take width as an approximation for getting biggest "width". As far as addressing core problem (textSVG is slow and memory hungry), I know very little about diagrams and don't know if we can have much improvement there...

I think this issue can be closed if there are issues for above points as I managed to convince myself that only 1 load is occuring.

EDIT: I think I managed to drastically improve the situation and will send PR shortly, just cleaning… EDIT2: It runs better but not for the right reason and not by a factor I thought it was so holding off on that PR…

byorgey commented 7 years ago

Re: your edit, great! I'm sure (1) and (2) could be improved. As for (3), it may be more an issue with diagrams itself than with SVGFonts. The diagrams text function creates a simple text object which uses native text support in the backend. SVGFonts, on the other hand, creates (possibly complicated) paths. Empirically we are talking about ~20 Bezier segments per letter. I don't actually think diagrams should be that slow in handling paths with hundreds or thousands of segments but I am not sure.

byorgey commented 7 years ago

OK, I'm closing this issue for now then. I've opened #22 as a placeholder for further performance improvements.