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 608419 - Caching wallpaper resize to avoid some CPU cycle at startup
Caching wallpaper resize to avoid some CPU cycle at startup
Status: RESOLVED FIXED
Product: gnome-desktop
Classification: Core
Component: libgnome-desktop
2.29.x
Other Linux
: Normal enhancement
: ---
Assigned To: Desktop Maintainers
Desktop Maintainers
Depends on:
Blocks:
 
 
Reported: 2010-01-29 09:26 UTC by Didier Roche
Modified: 2010-11-25 10:43 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Add cache for wallpapers (6.53 KB, patch)
2010-01-29 09:26 UTC, Didier Roche
reviewed Details | Review
Add cache for wallpapers (6.49 KB, patch)
2010-02-01 20:07 UTC, Didier Roche
none Details | Review
Add cache for wallpapers with clean policy (7.26 KB, patch)
2010-02-15 15:47 UTC, Didier Roche
none Details | Review
Add cache for wallpapers with multiple monitor support and refactoring (8.35 KB, patch)
2010-02-17 11:43 UTC, Didier Roche
none Details | Review
Add cache for wallpapers with multiple monitors support and refactoring (8.32 KB, patch)
2010-06-22 11:58 UTC, Didier Roche
reviewed Details | Review
git format patch for adding cache (13.05 KB, patch)
2010-10-20 20:52 UTC, Didier Roche
none Details | Review
Wallpaper patch against 2.91.1 (12.16 KB, patch)
2010-11-09 21:00 UTC, Didier Roche
none Details | Review
Wallpaper patch against 2.91.1 (12.08 KB, patch)
2010-11-09 21:19 UTC, Didier Roche
none Details | Review
Wallpaper patch against 2.91.2 (12.09 KB, patch)
2010-11-17 17:21 UTC, Sebastien Bacher
none Details | Review
gnome-bg: Cache resized wallpaper to help CPU at startup (13.01 KB, patch)
2010-11-25 10:14 UTC, Vincent Untz
committed Details | Review

Description Didier Roche 2010-01-29 09:26:39 UTC
Created attachment 152554 [details] [review]
Add cache for wallpapers

Cropping and resizing wallpaper take an non negligeable amount of time on gnome-bg.
This is done each time we load a new wallpaper for a dedicated gnome session.

The idea is to create a local cache on the disk for them. We have a patch there to do that.

Cache wallpapers resized and transformed are stored in ~/.cache/wallpaper/. The cache is refreshed for each new current wallpaper depending on the resolution or transformation, and each time the source image is refreshed. The source image format is preserved.


However, the patch still misses a clean policy. It's pretty hard to define it:
- clean the cache for all files < xx days? (something like 30 days seems reasonable as we don't intend that people are changing their wallpapers so often).
As a lot of GNU/Linux system pushes noatime as a default, the drawback is that we will surely erase some cached file that the user was using recently (and with a high probability wanted to switch back). So, in that case, we will have to regenerate it. This can be acceptable
- an other idea is to keep a file containing a list with used wallpaper in order and only keep in cache the last xx (10 ?).

What's your thought on that?
Comment 1 Martin Pitt 2010-01-29 09:36:13 UTC
As for the CPU impact, it's fairly dramatic. On a Dell Mini Ten, replacing the standard 1920x1400 wallpaper (which we have to ship in that size to suit all possible resolutions) with a size fitting the netbook (1024x600) takes away some 85% of g-s-d's total CPU time at startup. On a bootchart [1], almost all of g-s-d's blue CPU usage goes away.

As for the cache clean policy, I think this cache should only ever have one image, the one currently set. If you change it, then the image is set on the fly, and this operation could/should regenerate the cache. (If that's inconvenient because it uses a different API, then it will just be regenerated at the next desktop startup). I wouldn't like to see the cache pile up many images over time.

I don't think we should try to cover use cases like "slideshow" here. If you use slideshow, you just have to live with the extra .8 s of boot time.

[1] http://people.canonical.com/~pitti/bootcharts/daniel-lucid-20100129-1.png
Comment 2 Vincent Untz 2010-01-29 10:39:47 UTC
(In reply to comment #1)
> As for the cache clean policy, I think this cache should only ever have one
> image, the one currently set.

Mostly agree here, except that...

> I don't think we should try to cover use cases like "slideshow" here. If you
> use slideshow, you just have to live with the extra .8 s of boot time.

I think this could be handled too.

Also, it might be a nice touch to cache the image for the second monitor (in case your're using randr).
Comment 3 Vincent Untz 2010-01-29 10:56:15 UTC
Review of attachment 152554 [details] [review]:

I don't know the code very well, but here's a first review.

::: gnome-desktop-2.29.4/libgnome-desktop/gnome-bg.c
@@ +588,3 @@
+                              const char        *filename,
+                              int                width,
+                              int                height)

Maybe name the function get_wallpaper_cache_path?

@@ +597,3 @@
+	changed_filename = g_strdup (filename);
+	changed_filename = g_strdelimit (changed_filename, G_DIR_SEPARATOR_S, '_');
+	cache_filename = g_strdup_printf ("%i_%i_%i_%s", placement, width, height, changed_filename);

It's probably better to use the string from placement_lookup instead of %i for placement.

Also, what about doing the g_strdup_printf first on filename, and then doing the g_strdelimit. You can get rid of changed_filename this way.

And probably name the variable cache_basename.

@@ +618,3 @@
+	if (mtime < cache_mtime)
+		return TRUE;
+	return FALSE;

return (mtime < cache_mtime)

@@ +631,3 @@
+	GdkPixbufFormat *format;
+
+	cache_filename = get_wallpaper_cache_filename (bg->placement, bg->filename, width, height);

Note that you're using filename with different meanings (basename and full path). It might be already like this in the code, but still something that you can fix in the new code ;-)

@@ +864,3 @@
 	}
+
+	refresh_cache_file(bg, scaled, dest_width, dest_height);

Missing space before "(" :-)

@@ +1717,3 @@
+		/* Try to hit local cache first */
+		cache_filename = get_wallpaper_cache_filename (bg->placement, filename, best_width, best_height);
+		if (cache_file_is_valid(filename, cache_filename))

Missing space before "("
Comment 4 Didier Roche 2010-02-01 20:07:36 UTC
Created attachment 152760 [details] [review]
Add cache for wallpapers

Here is a new version of the patch with previously requests normally fulfilled (checking is always good :)).

Concerning the cache. I was thinking to add monX for monitor num X to cache one background only for each monitor.

I just have to change some internal functions prototype to add either screen or monitor num, but I'm concerned by that exported function:
gboolean
gnome_bg_is_dark (GnomeBG *bg,
                  int      width,
                  int      height)

to add either a GDKScreen or a monitor number. But this breaks the API…
What's your thought on that? (unfortunately, GFileMonitor of GnomeBG bg doesn't have any identifier)
Comment 5 Matthias Clasen 2010-02-15 15:38:37 UTC
Using monitor numbers is not really going to work. They are not guaranteed to be stable
Comment 6 Didier Roche 2010-02-15 15:47:10 UTC
Created attachment 153837 [details] [review]
Add cache for wallpapers with clean policy

Here is the last version of the patch.
Talking to Vuntz, it seems that there is no more the capacity of setting one wallpaper by monitor, so we went to the "just cache one wallpaper by user track" as a clean policy.
Comment 7 Matthias Clasen 2010-02-15 16:14:22 UTC
> Talking to Vuntz, it seems that there is no more the capacity of setting one
> wallpaper by monitor, so we went to the "just cache one wallpaper by user
> track" as a clean policy.

There has never been a way to set per-monitor backgrounds. What we do though, is to render the one selected background for each monitor, at different resolutions.
So you may want to reconsider that.
Comment 8 Matthias Clasen 2010-02-15 16:33:37 UTC
Review of attachment 153837 [details] [review]:

I think you really want to allow multiple sizes of the same background image to be cached, to handle the multi-monitor scenario. And clear the cache when the selected background image changes.

::: gnome-desktop-2.29.90/libgnome-desktop/gnome-bg.c
@@ +656,3 @@
+				gdk_pixbuf_save (new_pixbuf, cache_filename, format_name, NULL, "quality", "100", NULL);
+			else
+				gdk_pixbuf_save (new_pixbuf, cache_filename, format_name, NULL, NULL);

If you want to take the cycle saving seriously, you should look at gdk_pixdata_serialize etc, which will let you mmap the pixbuf data without any parsing or copying. Doesn't make much sense to covert the pixbuf to a jpeg for saving on disk and then convert it back to pixbuf when loading it.

@@ +881,3 @@
 	}
+
+	if ((dest_width > 300) && (dest_height > 300))

This strikes me as pointless. Just do it always.

@@ +1735,2 @@
+		/* Try to hit local cache first */
+		cache_filename = get_wallpaper_cache_filename (bg->placement, filename, best_width, best_height);

load_from_cache should probably be factored out as a separate function here.

What I do not understand though, is what the mtime of the original image has to do with the validity of the cache...
Comment 9 Martin Pitt 2010-02-15 16:56:25 UTC
(In reply to comment #8)
> If you want to take the cycle saving seriously, you should look at
> gdk_pixdata_serialize etc, which will let you mmap the pixbuf data without any
> parsing or copying. Doesn't make much sense to covert the pixbuf to a jpeg for
> saving on disk and then convert it back to pixbuf when loading it.

Thanks for pointing out!

> +
> +    if ((dest_width > 300) && (dest_height > 300))
> 
> This strikes me as pointless. Just do it always.

The CPU overhead for small (tiled) backgrounds is negligible, thus this would save the overhead of cache processing.

> What I do not understand though, is what the mtime of the original image has to
> do with the validity of the cache...

You certainly need a way to see whether the background image changed underneath you? E. g. a distro default background which is shipped in a package might change, or you might have a program/script which fetches a daily image and sticks it into ~/wallpapers/mybackground.jpg. So the mtime comparison seems sensible to me?
Comment 10 Matthias Clasen 2010-02-15 17:41:49 UTC
If the user selects a different background, I would expect that to usually have an older mtime than the cache file. But its still different and needs to trigger cleaning the cache.
Comment 11 Martin Pitt 2010-02-15 18:22:40 UTC
(In reply to comment #10)
> If the user selects a different background, I would expect that to usually have
> an older mtime than the cache file. But its still different and needs to
> trigger cleaning the cache.

Sure. In that case the cache file name won't match any more, and it gets cleaned.

This implementation is actually not that obvious: cache_file_is_valid() does not explicitly test for existence. It just seems that get_mtime() "magically" returns something like "plus infinity" for nonexisting files?

Anyway, I'd also like to see this file existence test being more explicit.
Comment 12 Martin Pitt 2010-02-17 09:40:11 UTC
Didier provided an alternative patch which uses serializing. I did three boot charts for both cases (.jpg cache, with above patch, and the serialized cache with the new patch):

http://people.canonical.com/~pitti/bootcharts/wallpaper-cache/

This shows that with the uncompressed (serialized) g-s-d indeed needs a little less CPU time. The total boot time difference is below bootchart's accuracy though, so it's hard to quantify the savings in that, but from my experience with bootchart so far (interpreting the blue CPU activity areas) I'd say that the uncompressed image saves some 0.1 s.

However, the price for this is of course that there is now a lot more data to be read from the disk: The jpg cache was ~ 20 kB, the uncompressed cache is 1 MB.

So on the mini (utterly slow Atom CPU, fast SSD disk) compressed vs. uncompressed does not make a measurable total difference, while on more "typical" machines (fast CPU, slow disk) the cost of the bigger cache ought to outweigh the CPU saving by far.

So in summary I'd rather recommend to not use a raw cache.
Comment 13 Didier Roche 2010-02-17 11:43:50 UTC
Created attachment 154021 [details] [review]
Add cache for wallpapers with multiple monitor support and refactoring

Following Martin's remark, find attached a new version of the patch, without serialization. (I can still provide you that version if you need it, but on my 1920x1200, the serialized version is 2.5MiB whereas the initial file is 19KiB)

This one contains now:
- cleanage policy a little bit smarter: only clean every other files with same transformation x resolution. This enable the cache to support multiple monitors resolution. The "unused cache file" if you change your resolution and never come back to it seems acceptable.
- refactoring of loading from cache in its own function
- explicit file existence test for cache_file_is_valid()
Comment 14 Didier Roche 2010-06-22 11:58:53 UTC
Created attachment 164296 [details] [review]
Add cache for wallpapers with multiple monitors support and refactoring
Comment 15 Vincent Untz 2010-06-23 10:43:10 UTC
Review of attachment 164296 [details] [review]:

Can you fix the tabs vs spaces issue? :-) See other comments below:

::: libgnome-desktop/gnome-bg.c
@@ +609,3 @@
+	cache_prefix_name = get_wallpaper_cache_prefix_name (placement, width, height);
+	cache_basename = g_strdup_printf ("%s_%s", cache_prefix_name, filename);
+	cache_basename = g_strdelimit (cache_basename, G_DIR_SEPARATOR_S, '_');

We really want to use a hash (md5 should be enough) to avoid clashes between /tmp/a_1.png and /tmp/a/1.png.

@@ +629,3 @@
+
+	if (!g_file_test (cache_filename, G_FILE_TEST_IS_REGULAR))
+		return FALSE;

This test should be done before get_mtime()

@@ +651,3 @@
+	cache_dir = get_wallpaper_cache_dir ();
+
+	/* Only refresh scaled file on disk if useful (and don't cache slideshow) */

It'd be really great to also be able to cache slideshows. This would imply refreshing the cache file only when the new image in the slide show is needed. And suffixing the basename of the cache file with a number, I guess (well, before the file extension).

The code needs to be restructured a bit, but this should be doable.

@@ +656,3 @@
+		if (format != NULL) {
+			if (!g_file_test (cache_dir, G_FILE_TEST_IS_DIR))
+				g_mkdir (cache_dir, 0700);

You want g_mkdir_with_parents()

@@ +657,3 @@
+			if (!g_file_test (cache_dir, G_FILE_TEST_IS_DIR))
+				g_mkdir (cache_dir, 0700);
+			else {

I'd create cache_prefix_name here and not earlier; I was wondering why you needed it earlier.

@@ +663,3 @@
+				while (file != NULL) {
+					path = g_build_filename (cache_dir, file, NULL);
+					/* only purge files with same transformation and resolution */

Apparently, this is needed because we don't have the monitor number and we support different backgrounds on different monitors. If we can't update the code to have the monitor parameter here, at least the comment should mention this :-)

But a quick look at the code makes me think we can have it. That's actually easy: either we care about monitors and we have an argument, or we don't care about it and that's why you don't have any mention of a monitor in the callers of this function.

@@ +664,3 @@
+					path = g_build_filename (cache_dir, file, NULL);
+					/* only purge files with same transformation and resolution */
+					if (strstr (file, cache_prefix_name) && g_file_test (path, G_FILE_TEST_IS_REGULAR))

g_str_has_prefix() instead of strstr()?

@@ +667,3 @@
+						g_unlink (path);
+					file = g_dir_read_name (g_cache_dir);
+					g_free (path);

Those two lines should be in the reverse order for clarity :-)

@@ +1778,2 @@
+		/* Try to hit local cache first */
+		pixbuf = load_from_cache_file(bg, filename, best_width, best_height);

Missing space before parenthesis
Comment 16 Didier Roche 2010-10-20 20:52:27 UTC
Created attachment 172883 [details] [review]
git format patch for adding cache

I think I fixed the concerns there, as discussed IRL.

There are still space vs tabs issue in the file, but I didn't fix that everywhere, just the part in the patch.

I renamed draw_image to draw_image_for_thumb as well.
Comment 17 Didier Roche 2010-11-09 21:00:23 UTC
Created attachment 174155 [details] [review]
Wallpaper patch against 2.91.1

I've rebased again the patch against 2.91.1. Can you please have a look at it? Otherwise, no ice cream at my "pendaison crémaillère" vuntz! :)

If you need a git-format patch, I can do that in a second.
Comment 18 Didier Roche 2010-11-09 21:19:30 UTC
Created attachment 174156 [details] [review]
Wallpaper patch against 2.91.1

oupss, gconf_enum_to_string () doesn't really exists now that the branch is using gsettings, removing that and use the integer equivalent for the patch.
Comment 19 Sebastien Bacher 2010-11-17 17:21:09 UTC
Created attachment 174700 [details] [review]
Wallpaper patch against 2.91.2
Comment 20 Vincent Untz 2010-11-25 10:14:27 UTC
Created attachment 175232 [details] [review]
gnome-bg: Cache resized wallpaper to help CPU at startup

Resized and transformed wallpapers are stored in ~/.cache/wallpaper/.
The cache is refreshed for each new current wallpaper depending on the
resolution or transformation, and each time the source image is
refreshed.

The source image format is preserved.
Comment 21 Vincent Untz 2010-11-25 10:42:59 UTC
Pushed. After talking with Didier, it probably needs some testing, though :-)