After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 687881 - repeatedly lstat()s stylesheet background images from main thread
repeatedly lstat()s stylesheet background images from main thread
Status: RESOLVED FIXED
Product: gnome-shell
Classification: Core
Component: general
3.6.x
Other Linux
: Normal normal
: ---
Assigned To: gnome-shell-maint
gnome-shell-maint
Depends on:
Blocks: 687362
 
 
Reported: 2012-11-07 20:18 UTC by Simon McVittie
Modified: 2012-12-16 19:47 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
St: avoid blocking IO to resolve relative urls (8.57 KB, patch)
2012-11-22 00:23 UTC, Giovanni Campagna
needs-work Details | Review
St: avoid blocking IO to resolve relative urls (8.85 KB, patch)
2012-11-24 01:07 UTC, Giovanni Campagna
committed Details | Review
St: fix regression from f7af96dbb2152c796c5877585e7d1e555471d6ce (2.43 KB, patch)
2012-12-16 17:07 UTC, Giovanni Campagna
committed Details | Review

Description Simon McVittie 2012-11-07 20:18:15 UTC
+++ This bug was initially created as a clone of Bug #687362 +++

Since Bug #679268 was fixed, Shell can be observed performing I/O from the main thread to canonicalize textures' filenames:

31106 1352317144.557113 lstat("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000033>
31106 1352317144.557220 lstat("/home/jhbuild", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000033>
31106 1352317144.557344 lstat("/home/jhbuild/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000058>
31106 1352317144.557491 lstat("/home/jhbuild/usr/share", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000047>
31106 1352317144.557637 lstat("/home/jhbuild/usr/share/gnome-shell", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000047>
31106 1352317144.557758 lstat("/home/jhbuild/usr/share/gnome-shell/theme", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000030>
31106 1352317144.557862 lstat("/home/jhbuild/usr/share/gnome-shell/theme/calendar-arrow-left.svg", {st_mode=S_IFREG|0644, st_size=2526, ...}) = 0 <0.000030>
31106 1352317144.558221 lstat("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000031>
31106 1352317144.558321 lstat("/home/jhbuild", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000029>
31106 1352317144.558420 lstat("/home/jhbuild/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000029>
31106 1352317144.558520 lstat("/home/jhbuild/usr/share", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000028>
31106 1352317144.558620 lstat("/home/jhbuild/usr/share/gnome-shell", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000026>
31106 1352317144.558716 lstat("/home/jhbuild/usr/share/gnome-shell/theme", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000026>
31106 1352317144.558813 lstat("/home/jhbuild/usr/share/gnome-shell/theme/calendar-arrow-right.svg", {st_mode=S_IFREG|0644, st_size=2527, ...}) = 0 <0.000027>

(This is from a strace of Shell while opening the calendar menu for the first time - Bug #687465.)

Worse, it does this sequence several times for the same image:

31106 1352317144.573754 lstat("/home/jhbuild/usr/share/gnome-shell/theme/calendar-arrow-right.svg", {st_mode=S_IFREG|0644, st_size=2527, ...}) = 0 <0.000029>

because it resolves the URL whenever the background image becomes attached to a StThemeNode.

One way to avoid this (partially) would be to store the background image, etc. in the theme node as a tuple (ref to base stylesheet, image), and then defer resolution until the image is actually loaded into the cache.

Another way would be to do the resolution eagerly when the stylesheet is first loaded: first parse the stylesheet, then iterate through all rules looking for images, then attach a map (relative image name -> absolute filename) to the stylesheet or the object that owns it. This presumably happens during Shell startup, while we're doing significant I/O (and are unable to draw anything) in any case.

That would also be a prerequisite for eagerly loading images before they're going to be needed, if we want to do that for Bug #687362.
Comment 1 Simon McVittie 2012-11-09 15:23:11 UTC
This should be a bit less of a problem after applying the patch "Keep similar theme nodes so we don't have to recompute CSS so often" from Bug #687465: realpath() is still called once for each StThemeNode that has a background/border/etc. image, but that patch reduces the number of distinct StThemeNodes, and hence the number of realpath() calls.
Comment 2 Jasper St. Pierre (not reading bugmail) 2012-11-09 19:52:25 UTC
I didn't know that realpath actually called stat(); I thought it just did path manipulation only. Is there something like abspath or similar which has the effect of canonicalizing the path without the additional stat?
Comment 3 Simon McVittie 2012-11-12 12:03:04 UTC
(In reply to comment #2)
> I didn't know that realpath actually called stat(); I thought it just did path
> manipulation only.

It's documented to chase symlinks, which can't be done without I/O (either lstat() or readlink()). I don't know a direct C equivalent of Python's os.path.abspath().
Comment 4 Giovanni Campagna 2012-11-22 00:23:03 UTC
Created attachment 229610 [details] [review]
St: avoid blocking IO to resolve relative urls

realpath() does a series of lstat() on each path component to resolve
symbolic links, but we just want to get an absolute path, and we don't
really care if it is physical or not. Going through a GFile does the
canonicalization we need, and is a lot faster.

Turns out that there is a C equivalent of os.path.abspath().
I'm using GFile in _resolve_url() because eventually I want to support
arbitrary GFiles as stylesheets and textures, and most importantly
GResourceFiles
Comment 5 Colin Walters 2012-11-22 00:30:45 UTC
Review of attachment 229610 [details] [review]:

::: src/st/st-theme-node.c
@@ +1750,3 @@
+                                                term->content.str->stryng->str);
+
+                  node->background_image = g_strdup (g_file_get_path (file));

Ditto here.

@@ +1860,3 @@
+                                            decl->value->content.str->stryng->str);
+
+              node->background_image = g_strdup (g_file_get_path (file));

And here

@@ +2757,3 @@
 
+          file = _st_theme_resolve_url (node->theme, base_stylesheet, url);
+          filename = g_strdup (g_file_get_path (file));

And here

::: src/st/st-theme.c
@@ +856,3 @@
+                                                  a_nodesheet,
+                                                  import_rule->url->stryng->str);
+                    filename = g_strdup (g_file_get_path (file));

g_file_get_path () already copies (unfortunately...)

See also http://git.gnome.org/browse/ostree/tree/src/libotutil/ot-gio-utils.c?id=f2b1be6a1eb8a42b2f5b1f187d4b5d37b7510b88#n264
Comment 6 Giovanni Campagna 2012-11-22 01:48:56 UTC
Ok, I'll get at the review comments, but just in case someone else was about to work on this, I started a big rewriting of the StTheme code, to reduce the number of string comparisons and linear searches required to build a StThemeNode.
Comment 7 Giovanni Campagna 2012-11-24 01:07:24 UTC
Created attachment 229751 [details] [review]
St: avoid blocking IO to resolve relative urls

realpath() does a series of lstat() on each path component to resolve
symbolic links, but we just want to get an absolute path, and we don't
really care if it is physical or not. Going through a GFile does the
canonicalization we need, and is a lot faster.
Comment 8 Jasper St. Pierre (not reading bugmail) 2012-12-06 06:57:02 UTC
Review of attachment 229751 [details] [review]:

::: src/st/st-theme.c
@@ +1032,2 @@
+      dirname = g_path_get_dirname (base_filename);
+      stylesheet = g_file_new_for_path (dirname);

I wonder if we should cache this in the stylesheet private instead...

@@ +1039,3 @@
   else
     {
+      resource = g_file_new_for_path (url);

When could this happen? We really shouldn't allow arbitrary images from HTTP or other URLs, or else somebody could make a goatse theme or something.

Is this trying to support a use case like Gravatars in the user menu or similar?
Comment 9 Bastien Nocera 2012-12-06 07:05:27 UTC
(In reply to comment #8)
> @@ +1039,3 @@
>    else
>      {
> +      resource = g_file_new_for_path (url);
> 
> When could this happen? We really shouldn't allow arbitrary images from HTTP or
> other URLs, or else somebody could make a goatse theme or something.
> 
> Is this trying to support a use case like Gravatars in the user menu or
> similar?

Gravatar support would have copied the image locally, so that you didn't have to have a working network to see your face in GDM.
Comment 10 Simon McVittie 2012-12-06 12:13:16 UTC
In this patch, there seem to be three cases. In pseudocode:

if (scheme)
  {
    the stylesheet said something like file:///usr/.../foo.png
    (OK in principle) or possibly a http or other URI (bad)
  }
else if (base_stylesheet)
  {
    the stylesheet said something relative like bar/foo.png or ../foo.png,
    or something absolute like /usr/.../foo.png; either way,
    resolve it relative to the stylesheet
  }
else
  {
    ... if we have no stylesheet, where did we get this image from?
  }

I would expect this to work more like this:

if (scheme)
  {
    if (scheme is file, case-insensitively)
      {
        the path part is an absolute filename
      }
    else
      {
        fatal error ("your theme tries to access the internet or something")
        or perhaps just ignore this image
      }
  }
else if (path is absolute)
  {
    use it
  }
else if (base_stylesheet)
  {
    the path part is a filename relative to the base_stylesheet, resolve
    it to absolute
  }
else
  {
    either fatal error ("we shouldn't get here without a stylesheet")
    or assume the path is relative to getcwd()?
  }
Comment 11 Giovanni Campagna 2012-12-10 18:10:58 UTC
Uhm, for some reason I didn't get bugzilla mails for this...
Anyway, as I said earlier, the point of using GFile in place of paths is that it allows us to use GResource for the main theme, and bundle the One and Only theme in a fat binary, with one i-node and zero system calls to load it.
That's pending on using GFile to load and feed libcroco the CSS file, which I started to write but then turned in essentially a rewrite of the St theming system.
Comment 12 Jasper St. Pierre (not reading bugmail) 2012-12-10 19:20:05 UTC
OK, that makes sense. I'd still like to prevent users loading from http:// URLs or similar. Lock down URLs to file://
Comment 13 Giovanni Campagna 2012-12-10 23:34:34 UTC
I don't understand why this lockdown. Of course it's a stupid idea to load images from http://, but the theme author would notice it the moment the shell takes 20 seconds of synchronous HTTP code just to load (or worse, fails horribly if network is not available...).
I mean, there's nothing wrong with letting someone shoot on his foot. It's his (questionable) decision.
Comment 14 Jasper St. Pierre (not reading bugmail) 2012-12-15 01:56:36 UTC
(In reply to comment #13)
> I don't understand why this lockdown. Of course it's a stupid idea to load
> images from http://, but the theme author would notice it the moment the shell
> takes 20 seconds of synchronous HTTP code just to load (or worse, fails
> horribly if network is not available...).
> I mean, there's nothing wrong with letting someone shoot on his foot. It's his
> (questionable) decision.

I've already seen multiple extensions that do this with Gio.FileIcon, but yeah, maybe it's worth letting him shoot his foot off.

I was concerned about goatse, not slowness.
Comment 15 Jasper St. Pierre (not reading bugmail) 2012-12-15 02:17:18 UTC
(In reply to comment #10)
> else if (path is absolute)
>   {
>     use it
>   }

This is the only path missing at this point, and I'm not sure it's worthwhile to keep around. Will re-review the patch.
Comment 16 Jasper St. Pierre (not reading bugmail) 2012-12-15 02:19:37 UTC
Review of attachment 229751 [details] [review]:

OK.
Comment 17 Giovanni Campagna 2012-12-15 02:42:37 UTC
Comment on attachment 229751 [details] [review]
St: avoid blocking IO to resolve relative urls

Attachment 229751 [details] pushed as f7af96d - St: avoid blocking IO to resolve relative urls
Leaving the bug open for the announced GResource work, and maybe something
more...
Comment 18 Cosimo Cecchi 2012-12-15 19:18:48 UTC
The committed patch does

+                  node->background_image = g_strdup (g_file_get_path (file));

in a lot of places - AFAICS this will leak the file path every time since g_file_get_path() allocates a new string.
Comment 19 Jasper St. Pierre (not reading bugmail) 2012-12-16 00:05:57 UTC
Gah, Giovanni! You commited the wrong patch!
Comment 20 Giovanni Campagna 2012-12-16 17:07:16 UTC
Created attachment 231658 [details] [review]
St: fix regression from f7af96dbb2152c796c5877585e7d1e555471d6ce

A bad rebase caused the wrong patch to be pushed.
Comment 21 Jasper St. Pierre (not reading bugmail) 2012-12-16 19:26:05 UTC
Review of attachment 231658 [details] [review]:

OK.
Comment 22 Giovanni Campagna 2012-12-16 19:47:06 UTC
Attachment 231658 [details] pushed as 9860b1c - St: fix regression from f7af96dbb2152c796c5877585e7d1e555471d6ce