Bug 215150 - IOSurface not being recycled after ImageBuffer is destroyed
Summary: IOSurface not being recycled after ImageBuffer is destroyed
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: CSS (show other bugs)
Version: Other
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: frankhome61
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-08-04 17:33 PDT by frankhome61
Modified: 2020-08-19 11:33 PDT (History)
7 users (show)

See Also:


Attachments
Patch (1.52 KB, patch)
2020-08-04 17:34 PDT, frankhome61
frankhome61: review?
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description frankhome61 2020-08-04 17:33:29 PDT
When investigating the code of another project, I realized that whenever we use an AcceleratedImageBuffer (IOSurface backend), the IOSurface was always destroyed with the destruction of ImageBuffer. However, I do believe it makes more sense to put the IOSurface back to surface pool once an ImageBuffer is destroyed. There is actually an existing function, IOSurface::moveToPool implemented, but never used in ImageBuffers. I propose an idea that, we move the IOSurface back to the surface pool in the destructor of ImageBufferIOSurfaceBackend. I am not sure if this change is sufficient, but the current code definitely didn't use IOSurface pool for recycling.
Comment 1 frankhome61 2020-08-04 17:34:48 PDT
Created attachment 405965 [details]
Patch
Comment 2 Said Abou-Hallawa 2020-08-04 21:07:49 PDT
Why do we need to do this for ImageBuffer?

IOSurface::moveToPool() is called from a single place which is RemoteLayerBackingStore::Buffer::discard(). The RenderLayers are backed by IOSurfaces. While scrolling many RenderLayers are invalidated and painted. I think some of them are destroyed but many of them are recycled. The good thing about about RenderLayers is their sizes are almost always the same 512x512, I think. So it makes sense to recycle their IOSurfaces because a match will be found with a high probability.

But I am not sure about the canvas and filters. Do we have the same pattern: 
1. Create an IOSurface with size = s
2. Use the IOSurface
3. Destroy the IOSurface
4. Create another IOSurface with size = s

We need to prove this case happens so often and we need to get measurements for how much this lazy destroying can affect the memory allocation.
Comment 3 frankhome61 2020-08-05 08:52:30 PDT
(In reply to Said Abou-Hallawa from comment #2)
> Why do we need to do this for ImageBuffer?
> 
> IOSurface::moveToPool() is called from a single place which is
> RemoteLayerBackingStore::Buffer::discard(). The RenderLayers are backed by
> IOSurfaces. While scrolling many RenderLayers are invalidated and painted. I
> think some of them are destroyed but many of them are recycled. The good
> thing about about RenderLayers is their sizes are almost always the same
> 512x512, I think. So it makes sense to recycle their IOSurfaces because a
> match will be found with a high probability.
> 
> But I am not sure about the canvas and filters. Do we have the same pattern: 
> 1. Create an IOSurface with size = s
> 2. Use the IOSurface
> 3. Destroy the IOSurface
> 4. Create another IOSurface with size = s
> 
> We need to prove this case happens so often and we need to get measurements
> for how much this lazy destroying can affect the memory allocation.

The scenario I was thinking of is CSS/SVG filter rendering with Accelerated rendering mode plus animation. In accelerated rendering mode where we use ImageBufferIOSurfaceBackend, when animating the filters, since CSS filter will be destroyed and recreated on each new draw, the ImageBuffer will have same life cycle as CSS filters, so does the IOSurface. That's why I was thinking doing so makes sense.
Comment 4 youenn fablet 2020-08-06 01:35:45 PDT
Comment on attachment 405965 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=405965&action=review

> Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp:110
> +    IOSurface::moveToPool(WTFMove(m_surface));

Is there any guarantee m_surface is not null?
ImageBufferIOSurfaceBackend::sinkIntoNativeImage() seems to move m_surface for instance
Comment 5 Radar WebKit Bug Importer 2020-08-11 17:34:17 PDT
<rdar://problem/66872961>
Comment 6 frankhome61 2020-08-11 17:35:27 PDT
(In reply to youenn fablet from comment #4)
> Comment on attachment 405965 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=405965&action=review
> 
> > Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp:110
> > +    IOSurface::moveToPool(WTFMove(m_surface));
> 
> Is there any guarantee m_surface is not null?
> ImageBufferIOSurfaceBackend::sinkIntoNativeImage() seems to move m_surface
> for instance

I guess we can check before throwing an IOSurface back to the pool. We only do so when m_surface is non-null.
Comment 7 youenn fablet 2020-08-13 05:44:49 PDT
(In reply to guowei_yang from comment #6)
> (In reply to youenn fablet from comment #4)
> > Comment on attachment 405965 [details]
> > Patch
> > 
> > View in context:
> > https://bugs.webkit.org/attachment.cgi?id=405965&action=review
> > 
> > > Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp:110
> > > +    IOSurface::moveToPool(WTFMove(m_surface));
> > 
> > Is there any guarantee m_surface is not null?
> > ImageBufferIOSurfaceBackend::sinkIntoNativeImage() seems to move m_surface
> > for instance
> 
> I guess we can check before throwing an IOSurface back to the pool. We only
> do so when m_surface is non-null.

Sounds good
Comment 8 Peng Liu 2020-08-19 11:33:57 PDT
Comment on attachment 405965 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=405965&action=review

> Source/WebCore/ChangeLog:8
> +        No new tests (OOPS!).

This line needs to be removed (Or add some tests).