summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRasmus Andersson <rasmus@notion.se>2021-03-25 20:49:12 +0300
committerRasmus Andersson <rasmus@notion.se>2021-03-25 20:49:12 +0300
commit56cba2d659d15129a665a3f540efc85c2b704d12 (patch)
tree0b43ba3af77fd6d69eebd8eebf34d237b10fc924
parent034e568938497cd398109b191dc2b9e8f5d261e8 (diff)
downloadinter-56cba2d659d15129a665a3f540efc85c2b704d12.tar.xz
tooling: adds a --profile=<file> option to fontbuild for profiling runs and adds misc/tools/fmtprofile.py for printing and inspecting profile results
-rw-r--r--CONTRIBUTING.md31
-rwxr-xr-xmisc/fontbuild22
-rwxr-xr-xmisc/tools/fmtprofile.py24
3 files changed, 76 insertions, 1 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f98e933f0..3bf410f14 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -180,6 +180,37 @@ Type `misc/tools/kernsample.py -h` for help on how to use the program.
This only includes existing kerning and is thus only useful for adjustments. Additions must still be done manually.
+### Performance profiling
+
+`fontbuild` has a `--profile=<file>` option built in which when provided profiles the execution
+and writes a pstat file. Example:
+
+```
+misc/fontbuild --profile=build/tmp/1.pstat compile -o build/tmp/f.otf build/ufo/Inter-Regular.ufo
+```
+
+You can print pstat files with the `fmtprofile.py` tool:
+
+```
+misc/tools/fmtprofile.py -n 20 build/tmp/1.pstat
+```
+
+You can inspect pstat files interactively with the `pstats` module:
+
+```
+python3 -m pstats build/tmp/1.pstat
+```
+
+For profiling Python programs that are not fontbuild, you can do this:
+
+```
+python -m cProfile -o 1.pstats -s time script.py
+```
+
+See <https://docs.python.org/3/library/profile.html> for more information about profiling
+Python programs.
+
+
### Miscellaneous tools
There are several tools included with Inter to help "wrangle" metrics, generate glyphs, create PDFs and so on. You can find these tools in the `misc/tools` directory. They are all command-line tools and their usage can be queried by providing the help flag `-h`.
diff --git a/misc/fontbuild b/misc/fontbuild
index 170057d1a..c649fc5e1 100755
--- a/misc/fontbuild
+++ b/misc/fontbuild
@@ -88,6 +88,9 @@ class Main(object):
argparser.add_argument('-q', '--quiet', action='store_true',
help='Only print errors')
+ argparser.add_argument('--profile', metavar='<file>',
+ help='Run in profiler for debugging, writing pstats data to <file>')
+
argparser.add_argument('-C', metavar='<dir>', dest='chdir',
help='Run as if %(prog)s started in <dir> instead of the '+\
'current working directory.')
@@ -126,7 +129,24 @@ class Main(object):
cmd = 'cmd_' + args.command.replace('-', '_')
if not hasattr(self, cmd):
fatal('Unrecognized command %s. Try --help' % args.command)
- getattr(self, cmd)(argv[i:])
+ cmdfn = getattr(self, cmd)
+ if args.profile:
+ try:
+ import cProfile as profile
+ except:
+ import profile
+ import __main__
+ __main__.__dict__["cmdfn"] = cmdfn
+ __main__.__dict__["argv"] = argv[i:]
+ profile.run('cmdfn(argv)', args.profile)
+ print("")
+ print("profile saved to %r. You can now inspect it with for example:" %
+ args.profile)
+ print("misc/tools/fmtprofile.py -n 20 %r" % args.profile)
+ print("python3 -m pstats %r" % args.profile)
+ print("")
+ else:
+ cmdfn(argv[i:])
diff --git a/misc/tools/fmtprofile.py b/misc/tools/fmtprofile.py
new file mode 100755
index 000000000..695d88ee7
--- /dev/null
+++ b/misc/tools/fmtprofile.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+# encoding: utf8
+#
+# Formats a Python profile dump from for example `fontbuild --profile=file ...`
+#
+import argparse, pstats
+from pstats import SortKey
+
+def main():
+ argparser = argparse.ArgumentParser(description='Formats a Python profile dump')
+ argparser.add_argument('infile', metavar='<file>', type=str, help='Python pstats file')
+ argparser.add_argument('-n', '--limit', metavar='N', default=None, type=int,
+ help='Only print the top N entries')
+ argparser.add_argument('--sort', metavar='<key>', default=['time'], nargs='+', type=str,
+ help='Sort by keys (default is time.) Available keys: ' + ', '.join(SortKey))
+ args = argparser.parse_args()
+ p = pstats.Stats(args.infile)
+ p.strip_dirs()
+ p.sort_stats(SortKey(*args.sort))
+ p.print_stats(args.limit)
+
+
+if __name__ == '__main__':
+ main()