What computer performance metrics are most relevant to RF performance?



  • This might be a silly question, But I've been wondering for months, and someone here may be able to provide clarity.

    I'm seeking a computer that could maximise drawing speed for many masters (up to about 24) in multi-axis designspaces, probably with Skateboard running as part of the workflow. I have a relatively new MacBook Pro, but it gets pretty laggy around 8 masters, and nearly unusable around 12 masters.

    Is it all about MegaHertz? Does RAM matter (beyond working with other apps open at the same time)? Would something like geekbench "single core" speed metrics be relevant, while "multi core" metrics would be irrelevant? Or am I confusing multi-threading (which I don't think Python/RoboFont uses) with multi-core speed?

    As you can probably tell, I'm confused. However, if I were to borrow time on a powerful Mac computer to work on finishing a large variable font in RoboFont, what speed metric(s) should I try to optimize for?

    Thanks for any insights!


  • admin

    hello @StephenNixon,

    I can’t really give you an answer in terms of RAM, MegaHertz, etc. (still using an old MacBook Air myself) but I can try to encourage you to use your current resources more efficiently – if your current workflow is slow, you can change it.

    you seem to have already identified the bottleneck: opening 8 or more (full) masters in the UI. you can only edit a few glyphs at once, so a lot of resources are being ‘wasted’ to open all the other glyphs which you are currently NOT editing.

    try to think about ways to reduce the amount of glyphs you open in the interface. if your fonts are very large, try working with subsets: open just a few glyphs at a time, edit them, then save them back into the full fonts. (this is how I was able to produce a family with 420 styles in 2011)

    hope this helps, even though it’s not the answer you were looking for :)

    ps. have you tried the SimpleFontWindow?



  • Hey @gferreira, thank you so much for your insight.

    My mind is blown by the SimpleFontWindow! That is super helpful, already. My computer is flying through this designspace now – especially if I also close Skateboard during repetitive drawing tasks. :)

    Question about SimpleFontWindow, just to make sure I understand properly: does using this avoid opening the full fonts? That is, if I open 12 masters with SimpleFontWindow, then open the glyph n in each of them, am I only using resources to edit 12 glyphs, total? By extension, if I open n in Master A, then close it, then open n in Master B, etc, would I only ever be opening 1 glyph at a time? Or, to truly limit myself to a subset of glyphs, do I need to do something more clever, such as splitting up UFOs into partial character sets, then recombine them later? I doubt this is necessary, but I want to be sure...


  • admin

    @StephenNixon thanks, happy to hear this is helpful.

    SimpleFontWindow.py is a classic script by @frederik, the original is here. it avoids drawing and refreshing the glyph cells in the Font Overview, which is the most ‘expensive’ operation when working with fonts in the UI.


    here’s an explanation of the ‘editing partial UFOs method’ I mentioned above.

    ⚠️ please backup your files before trying this out!!

    the workflow has 3 steps:

    1. import some glyphs into temporary fonts
    2. edit those glyphs
    3. export the edited glyphs back into their source fonts

    here’s a script to import glyphs into temporary fonts (step 1):

    import os
    
    # list of source fonts
    ufoPaths = [
        '/myFolder/myFamily/Regular.ufo',
        '/myFolder/myFamily/Thin-Compressed.ufo',
        '/myFolder/myFamily/Black-Expanded.ufo',
        # ...add many more fonts here...
    ]
    
    # list of glyph names to edit
    glyphNames = 'a aacute eacute n o H O six'.split()
    
    # custom lib key to store the path of the source glyphset in temp fonts
    key = 'com.myDomain.tempEdit.glyphSetPath'
    
    # iterate over the source fonts
    for ufoPath in ufoPaths:
    
        # open source font without the UI
        srcFont = OpenFont(ufoPath, showInterface=False)
    
        # make a temporary font with UI to edit some glyphs
        tmpFont = NewFont(familyName=srcFont.info.familyName, styleName=srcFont.info.styleName)
    
        # store the path to the source glyphset (so we can save the edited glyphs later)
        glyphSetPath = os.path.join(ufoPath, 'glyphs')
        tmpFont.lib[key] = glyphSetPath
    
        # iterate over the given glyph names
        for glyphName in glyphNames:
            # skip non-existing source glyphs
            if glyphName not in srcFont:
                continue
    
            # get the source glyph
            srcGlyph = srcFont[glyphName]
    
            # if the glyph has components, make sure to import their base glyphs first
            if srcGlyph.components:
                for component in srcGlyph.components:
                    if not component.baseGlyph in tmpFont:
                        tmpFont[component.baseGlyph] = srcFont[component.baseGlyph]
    
            # import source glyph into temporary font
            tmpFont[glyphName] = srcGlyph
    

    (note: if you have a lot of source fonts, you can also import them as layers of a single temp font)

    here’s a script to write the selected temporary glyphs back into their source fonts (step 3):

    from fontTools.ufoLib.glifLib import GlyphSet
    
    key = 'com.myDomain.tempEdit.glyphSetPath'
    
    f = CurrentFont()
    
    # get source glyphset for current temp font
    glyphsFolder = f.lib[key]
    glyphSet = GlyphSet(glyphsFolder, validateWrite=True)
    
    # write selected glyphs back into the glyphset
    for glyphName in f.selectedGlyphNames:
        print(f'writing {glyphName}...')
        glyphSet.writeGlyph(glyphName, f[glyphName].naked(), f[glyphName].drawPoints)
    
    # save glyphset
    glyphSet.writeContents()
    

    this method has allowed me to work on huge families quickly. I hope someone else finds it useful too!



  • Wow, thanks so much for showing me how to do that!

    On thing this calls to mind: I do miss the "smart set" feature of the main font window. For example, I have sets like uppercase and lowercase to quickly view just the basic Latin letters. Do you think your scripts might be the simplest way to "filter" the SimpleFontWindow, or is there a more basic possibility if I'm in a non-massive font and can afford the approach?



  • To the original question,

    I think most of the issue is that though modern computers have multiple cores, but because of CPython's global interpreter lock, RF only runs on one core. So I suppose you would want to optimize for higher clock speed and not care so much about how many cores.

    A hack that we have used an an extreme situations is duplicating the RF app (right click > Duplicate), renaming them to be RoboFont1, 2, 3, etc. Then, you can work in one RF while the other one is doing something in the background. I haven't checked this out but I think this takes better advantage of multiple cores. (It may be a mess for other reasons ¯_(ツ)_/¯)

    One thing that you didn't mention is file read/write speed. There are a lot of files to read in a UFO, and an SSD would offer an improvement over fusion or HDD in that metric.

    As for RAM, RF doesn't tend to be as much of a RAM hog as, say, a browser, which is good!



  • Thanks for the breakdown, @colinmford! I suspected that to be the case, but it's helpful to have it confirmed.

    Very good point on the SSD. I haven't had a spinning-disk hard drive for awhile, but yes, I could see that really degrading performance for UFOs.

    Hmm, interesting hack on running multiple instances of RoboFont! On certain file-processing workflows, I might try to take advantage of that...


Log in to reply