Text-on-path with cairo
Cairotwisted is the name a piece of code I wrote using pangocairo to lay text on a path. Over the years many people have found it useful, so here is a public post to make sure it's easier to find on the interwebs.
The code is shipped in Pango tarball under examples/cairotwisted.c and can be browsed
here. Click on the thumbnail to see the full size image output.
At the core of it there is a function to map one path
onto another one. This is done by parameterizing the second path and computing it's gradient (see
the code).
Parameterizing a Bezier curve uniformly is not easy though. I currently flatten curves to lines and use that, but that has its own down sides as the error introduced in the gradient can magnify out of bound. Any ideas?
Labels: cairo, cairotwisted, pango, pangocairo
Improving Login Time, Part 2: gnome-settings-daemon fixed
Thanks everyone for your comments on my
previous poinst. Those issues have been keeping me quite busy. And as soon as I thought I'm done, the cleaned up plot showed some new rather empty areas that now were standing out, so I
added some new annotations and continued optimizing. Well, I think I'm at a point that I can't make it any faster, so here we go.
Regarding the architecture, I made the parent process wait until the child initializes all the plugins and exit only when the child wants to enter its main loop (
bug 559168). This way, plugins can use the already existing g_idle_add() postpone work for after the parent returns. Note that there is no waiting before the idle callbacks are run. It's just a way to decide what has to be run before any other processes in the session start, and what can run in parallel with other processes.
Lets look at the plot from last time again and go over the hot spots I identified previously:
1. linking: g-s-d now doesn't link to libgnome directly, so the gap the has shrank now. However, all the modules still indirectly link to libgnome by way of libgnome-desktop, so the first module loading actually gets the hit now. Well, that was before I learned that Alex already ripped the libgnome dependency from libgnome-desktop. I don't have that installed, so the actual situation is better than what I'll show in my
after plot.
Status: Fixed (
bug 557808).
2. gtk_init: As I said there's not much to gain here. At some point I want to dig in and reduce roundtrips Gtk+ makes. Owen
did this in 2003, bringing the number of round trips from 52 down to 23. I suspect we may have gained some excess fat in the five years since, so an inspection may be in order. No status change.
3. fontconfig_monitor: I moved installing the monitors to an idle callback, but also added a direct call to FcInit() in the startup routine, to make sure the fontconfig cache is up to date before a herd of other session applications start and all try to rebuild the cache if it's indeed out of date.
Status: Fixed (Part of
bug 559166 and
bug 559550). The total time is no different, it's just partially delayed.
4. mkfontdir: I cleaned up the module to not run mkfontscale or XSetFontPath unless there's any fonts present. This optimizes the common case where users don't have any per-user fonts installed for the legacy X font system.
Status: Fixed (
bug 559163). Nothing left of it on the plot.
5. mousetweaks: Fixed it to not try to stop a daemon that we know is not running.
Status: Fixed (
bug 559165). Nothing left of it on the plot. Also made it start in an idle callback (part of
bug 559166).
6. init_kbd: Removed the trap+XSync around each individual grab request. And added a grand one outside the loop. That did it. Also start this in idle handler as it doesn't have to be started before other apps.
Status: Fixed (
bug 559164 and
bug 559482).
7. acme_volume_new: The awesome gstreamer hackers are working on it. ensonic told me that they were stat'ing each plugin twice where one would be enough. That is fixed in trunk/master. There are other ways to optimize it (not fork, not stat in the first place, etc) and all should be properly fixed in gstreamer. So I
wrote to gstreamer-devel.
Status: Awesome gstreamer hackers working on it.
8. gnome-screensaver: Rodrigo made it start in an idle callback, and I reshuffled it to do its callback after everything else.
Resolution: Fixed.
9. clipboard_manager: Also starts in idle callback now.
Status: Fixed (part of
bug 559166).
10. xrdb: Plugin disabled by default.
Status: Fixed (
bug 557807).
That was for issues I identified last time. Thanks to the very responsive g-s-d maintainer, Jens Granseuer, these patches were all reviewed and committed in a few hours and made it to the 2.25.1 tarball.
I also identified some other hot spots after that I also fixed:
11. gconf: By auditing the gconf usage of the daemon and the plugins I simply added the most feasible preloading setting on vairous directories. The effect on the plugins is minimal, but this is visible as a clear win around the beginning of the plots where the daemon is building the list of all the plugins (busy blue-and-brown area), even when you add the preloading time.
Status: Fixed (
bug 559167).
12. XSync: I noticed that a lot of the error-trap+XSync that the keyboard code across many plugins did were actually not necessary. So a bunch of those were fired too.
Status: Fixed (
bug 559346 and
bug 559562).
13. more XSync: Seems like much of the remaining XSync's or other synchronous X operations (mostly in xkb code) can also wait until the idle handler is run.
Status: Fixed: a11y-keyboard and media-keys plugins are moved to idle callback (
bug 559564).
14. GnomeBg: A byproduct of the fact that I was running g-s-d in foreground causing Nautilus not just starting, and a bug in gnome-screensaver was causing g-s-d to set background after gnome-screensaver startup. Now this is normally not a big deal because when g-s-d detects that Nautilus is running it does not set the background. The fix I committed was needed to make my plot clean though.
Status: Fixed by delaying GnomeBg object creation until needed, essentially ignoring spurious change notifications (
bug 559639).
15. status_icon: The a11y-keyboard plugin was showing a large gap that I tracked down to an innocient-looking gtk_status_icon_new_from_icon_name(). Indeed, looking at the strace log, this was causing the Gtk+ theme to be looked up in various places and opened, etc, while I knew on my desktop, and on most desktops, the a11y icon is not enabled to be shown by default. So I made the icon lookup lazy.
Status: Fixed (
bug 559558).
That's it. These are all now committed too. And just when I thought I've exhausted my list of things to fix in g-s-d, I noticed that the daemonization logic in it opens the X display and
then forks and use that same display from the child. While this seems to have been working fine, it's definitely in the
don't-do-it land. So that one has to wait until I'm done with this already-long blog post before being fixed (
bug 559695).
So! Lets look at the plot after all the fixes above. The overall time halved. Lets look at the remaining spots quickly (almost none can be fixed in g-s-d):
1. Linking the daemon
2. gtk_init
3. Preloading plugin data gconf dirs
4. linking libgnome and other unneeded libs (fixed in libgnome-desktop trunk already)
5. xrdb: the xrdb plugin is gone. This very small invocation is needed to set font settings on the server. This is used by non-GTK+ cairo applications, so I'm hesitant to kill this just yet
6. fontconfig cache check
7. xrdb for Xcursor. Not sure if this one can go away
8. Linking pulseaudio and other audio libraries
9. Linking keyboard related libraries
10. gstreamer cache check
11. End of daemon initialization. Parent process exits now.
12. Relaxing. X server running mostly.
13. Installing fontconfig inotify monitors.
14. Keyboard initialization.
That's all for tonight, and for g-s-d. Next: overall view of the login process.
Labels: g-s-d, gnome, performance