Hello everyone,
While I'm an Inkscape user for some years now, I'm fairly new to it from
a developer point of view.
In terms of performance, I've been recently doing some analysis with the
help of cpu profiling tools.
My aim in this mail is to present some of the things I noticed and maybe
some ideas how to improve them.
The tools I've been using are the gperftools and more recently the linux
performance tool `perf` together with FlameGraphs (Disclaimer: Since
I've been using them for the first time I don't have a deep knowledge
about them).
Both tools can capture the stack at a timed interval, so it is possible
to estimate how much time is spent in different functions. These can be
visualized for example by a flame graph which I found quite handy. In
theses graphs the x-axis shows the stack records alphabetically sorted
(not chronologically) and if possible merged. The y-axis shows the call
stack.
Recording the startup of Inkscape just until before the Window shows
up[1] results in the attached results[2]. The original file is an SVG
file (Note: This is a large interactive SVG and primarily intended to be
opened in a browser[3]). By looking at the result I identified some
parts that might be of interest (See annotated PNG file).
- A - (100ms):
Based on some individual function calls (e.g. get_preferred_width) I
assume this is related to the layout calculations. Noteworthy is here
that the stack mostly has a depth of up to 80-90 frames. I don't know
whether this is usual for gtk, but for me this looks like the
calculation of the layout might get very complex. Maybe it is possible
in some places to simplify the layout (I'm referring e.g. to [4]). While
this part only takes around 100ms in this record, the actual impact
could be larger because the recording stops just before the window shows
up. However, even after it shows there is a noticeable delay until it
gets responsive.
- B - (170ms):
This part is the setup of the toolboxes at the top. I find interesting
here that with the exception of the TextToolbar, each Toolbar only takes
5-10ms to load, but because there are so many of them, they sum up over
100ms (again without the TextToolbar).
One idea I'll therefore try to look into in the next time is whether it
is possible to lazy-load them, so that the GUI relevant initialization
only runs as soon as required (when the tool is used the first time).
Since most toolbars initialize in up to 10ms the delay is insignificant
when clicking on a tool.
- C and D - (65ms / 80ms):
These relate to the initialization of the menu resp. the DesktopWidget.
I haven't had a much closer look yet, but both take longer than I
assumed. There might be some optimizations possible as well (e.g. I
noticed SwatchesPanel::_rebuild is called at least twice, each running
nearly 20ms).
- E - (260ms):
The last section is about loading the extensions. I don't know a lot
about the extensions system now and the future plans, but I also
wouldn't have expected this part to take that much time.
- Looking further -
The attached recording of the startup here is of course only a part of
interesting parts for optimization (And there are also a lot of parts
that I cannot identify with certainty).
One second aspect I want to look more into is for example the fill and
stroke dialog, which takes up to 600ms to load (not part of the attached
profiling) because all marker images are expensively loaded and rendered
as SPObjects at runtime. And if it is open on startup this time adds up
to the delay before the window even shows up.
--
All in all I admit that this a rather chaotic collection of maybe or
maybe not promising parts for performance optimizations. This surely
only touches the surface of possible analysis and improvements, but I
wanted to share this early because maybe you have some ideas as well (or
there were some things done in the past that I don't know of).
If you have any feedback I'd appreciate it a lot.
Best regards,
octycs
[1] I did this by calling exit just before
`InkscapeApplication::window_open` returns.
[2] The results still have parts that are marked as "[unknown]". I tried
solving this by passing "-fno-omit-frame-pointer" (see FlameGraph
documentation for more), but this did not have an effect. Though this
could also be because cmake automatically re-ran when I started building.
[3] Direct link:
https://octycs.eu/static/shared/190608_perf_startup_999hz.svg
[4]
https://gitlab.com/inkscape/inkscape/issues/9#note_132218218