Skip to content

caching for viewRect of LinearRegionItem to reduce CPU load#1391

Merged
j9ac9k merged 2 commits intopyqtgraph:masterfrom
jjuod:lribugfix
Oct 18, 2020
Merged

caching for viewRect of LinearRegionItem to reduce CPU load#1391
j9ac9k merged 2 commits intopyqtgraph:masterfrom
jjuod:lribugfix

Conversation

@jjuod
Copy link
Copy Markdown
Contributor

@jjuod jjuod commented Oct 2, 2020

Issue

Having a LinearRegionItem inside a ViewBox causes large CPU loads on any mouse interaction - just moving the cursor around anywhere in the ViewBox (even outside the Item) takes up 2 threads at 100 % for me. This seems to be caused by viewRect() of the LinearRegionItem, which is called on every mouse event and does some heavy coordinate transforms.

Solution

Similar issues elsewhere in Qt/pyqtgraph seem to be solved by caching the boundaries. I suspected that the viewTransformChanged() slot on pyqtgraph's GraphicsItem was intended specifically to allow that, so I set up a simple cache which is invalidated by viewTransformChanged(). This seems to work (CPU load reduced ~20x), but I'm not sure if that slot really catches every change that invalidates viewRect. Would be good if someone with better understanding could take a look.

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Oct 10, 2020

Thanks for this PR! As I frequently use linear region items I've been suspicious of some performance issue when using a significant number of them...

I'll try and review/test this in the next day or two.

@campagnola
Copy link
Copy Markdown
Member

This looks great! I can't think of a reason why the caching should cause any problems here.

However: why not just implement this on GraphicsItem instead? Then potentially many different items will benefit form it.

@jjuod
Copy link
Copy Markdown
Contributor Author

jjuod commented Oct 15, 2020

@campagnola I looked at the code for some other items briefly, and they seemed to have their own caching, albeit implemented in some slightly different way for each. (They also didn't seem to have any performance issues.) Figured I might break something if I try to harmonize that...

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Oct 15, 2020

@jjuod I'm good w/ implementing it at GraphicsItem, the other objects that inherit GraphicsItem can re-implement those methods...but that may be outside the scope of the PR so if you're reluctant to make that implementation, I'll take this PR as it is.

@jjuod
Copy link
Copy Markdown
Contributor Author

jjuod commented Oct 18, 2020

Ok, moved the caching to GraphicsItem. Works fine with instances of LinearRegionItems. Haven't tested the other items, but it doesn't seem like they could be broken by this in any way.

@j9ac9k j9ac9k merged commit 39f9c6a into pyqtgraph:master Oct 18, 2020
@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Oct 18, 2020

Merged, thanks for the PR @jjuod !

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Oct 22, 2020

Turns out we did break something!

image

this is a screenshot of the basic example app; when you zoom out, notice how the infinite lines do not scale all the way up...

I'm thinking the solution here is not to undo this PR, but to add some more logic to InfiniteLine

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Oct 22, 2020

Managed to fix this by adding the call to GraphicsItem for viewTransformChanged() for the InfiniteLine class.

    def viewTransformChanged(self):
        """
        Called whenever the transformation matrix of the view has changed.
        (eg, the view range has changed or the view was resized)
        """
        GraphicsItem.viewTransformChanged(self)
        self._invalidateCache()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants