Bug 73531

Summary: Extreme slowness drawing dashed lines
Product: cairo Reporter: M Welinder <terra>
Component: generalAssignee: Chris Wilson <chris>
Status: RESOLVED NOTOURBUG QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: normal    
Priority: medium    
Version: unspecified   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:

Description M Welinder 2014-01-13 03:14:16 UTC
First off, apologies for a bug report with precious few details.  I am
hoping this rings a bell for some cairo developer.

The Gnumeric team has received a few reports of severe cpu usage when we
do our "walking ants" animation that marks a copied selection.  I do not
see this on my Linux machine; I might see it with our win32 binary under
wine, but that's a whole lot of extra variables.

To see the walking ants animation in action, start Gnumeric, select a
large area, and press ctrl-c.  Alternatively, watch
http://jeff.ecchi.ca/public/gnumeric-381011.webm

Here's what the animation code does:

1. We set a two-item dashed line style using cairo_set_dash.
2. We set a line width using cairo_set_line_width
3. We set one of the two ant colours.
4. We set a rectangle path using cairo_rectangle
5. We draw a line along that path using cairo_stroke_preserve.
   [That draws half the ant pattern, say the black bits.]
6. We set the other ant colour.
7. We set the stipple with an offset of one "ant" length
8. We draw a line along that path using cairo_stroke.
   [That draws half the ant pattern, say the wite bits.]

Repeat that every 150ms with the two colours swapped.

The actual code is at
    https://git.gnome.org/browse/gnumeric/tree/src/item-cursor.c
near line 450.

Is there any reason why this should bring a modern machine to its knees?



Further random info:

Both my Linux and win32 cairo are 1.12.16.

One original bug report for this: https://bugzilla.gnome.org/show_bug.cgi?id=381011 starting at comment 12.
Comment 1 Uli Schlachter 2014-01-18 18:26:38 UTC
I don't really understand the code, but here is what I think I found.

The 150ms timeout is implemented in item_cursor_realize() in item-cursor.c. For items with ->style == GNM_ITEM_CURSOR_ANTED it does this:

  ic->animation_timer = g_timeout_add (150, (GSourceFunc) cb_item_cursor_animation, ic);

Looking at the callback function, we see that it just toggles ic->state and calls goc_item_invalidate() on the item. I haven't actually found that function's implementation, but debian code search gave me the following (goc_item_invalidate(item) just calls goc_item_maybe_invalidate(item, FALSE);):

http://sources.debian.net/src/goffice/0.10.9-1/goffice/canvas/goc-item.c?hl=473#L451

This calculates the bounds of the items and invalidates that rectangle on the canvas.

TL;DR: gnumeric redraws "basically all of its content" about 7 times per second and then wonders that this is slow. (Or did I miss something?)

Re "this used to work fine for over a decade": The implementation a decade ago was more intelligent (I guess instead of redrawing things, it just drew the ant line ones and then used an XOR operator to "toggle the dashes/ants").
Comment 2 Uli Schlachter 2014-01-18 18:57:30 UTC
And valgrind --tool=callgrind says that 65% of CPU time is spent inside gnm_style_borders_row_draw() (unrelated code?) which itself spends most of its cpu time in cairo_stroke(). So the high cpu usage seems to come from some unrelated code which just happens to be executed more often due to the "ant lines".

I don't see why this would be a cairo problem. Could you provide more information, perhaps some self-contained C code that shows cairo being slow?
Comment 3 M Welinder 2014-01-20 03:16:54 UTC
Thanks for the analysis and the effort.  I am now able to reproduce the
problem myself and work on it.

Apologies for having suspected cairo: this was hitting a random set of machines
suggesting something below gtk+.  In fact, I now believe this is something as
simple as different screen resolution.  More pixels, more work.  And pixels
go up with resolution squared.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.