Bug 522193 - WebGL calls are slow because of memory allocation churning - r=roc
authorBenoit Jacob <bjacob@mozilla.com>
Mon, 03 Oct 2011 08:41:56 -0400
changeset 77980 704f378016118503e36b1a8d058f92c1ef305f0d
parent 77979 be9874f75baefbc9c8fa8e3d9f8942cca574a363
child 77981 11d110b351c536091fbd594599b23d5dedd5202e
push id2337
push userbjacob@mozilla.com
push dateMon, 03 Oct 2011 12:42:35 +0000
treeherdermozilla-inbound@704f37801611 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs522193
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 522193 - WebGL calls are slow because of memory allocation churning - r=roc WebGL objects keep an array of refptrs of other WebGL objects owning references to them. In practical cases, the size of this array can oscillate between 0 and 2 at high frequency. nsTArray throws away its whole storage (mHdr) when its size hits 0. This patch makes us use a nsAutoTArray with a pre-allocated size of 2 or 8 depending on WebGL object types.
content/canvas/src/WebGLContext.h
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -72,17 +72,17 @@ class WebGLTexture;
 class WebGLBuffer;
 class WebGLProgram;
 class WebGLShader;
 class WebGLFramebuffer;
 class WebGLRenderbuffer;
 class WebGLUniformLocation;
 class WebGLExtension;
 
-class WebGLZeroingObject;
+template<int PreallocatedOwnersCapacity> class WebGLZeroingObject;
 class WebGLContextBoundObject;
 
 enum FakeBlackStatus { DoNotNeedFakeBlack, DoNeedFakeBlack, DontKnowIfNeedFakeBlack };
 
 struct VertexAttrib0Status {
     enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
 };
 
@@ -104,16 +104,17 @@ int GetWebGLTexelFormat(GLenum format, G
 inline bool is_pot_assuming_nonnegative(WebGLsizei x)
 {
     return (x & (x-1)) == 0;
 }
 
 class WebGLObjectBaseRefPtr
 {
 protected:
+    template<int PreallocatedOwnersCapacity>
     friend class WebGLZeroingObject;
 
     WebGLObjectBaseRefPtr()
         : mRawPtr(0)
     {
     }
 
     WebGLObjectBaseRefPtr(nsISupports *rawPtr)
@@ -676,16 +677,22 @@ public:
     friend class WebGLTexture;
     friend class WebGLFramebuffer;
 };
 
 // this class is a mixin for the named type wrappers, and is used
 // by WebGLObjectRefPtr to tell the object who holds references, so that
 // we can zero them out appropriately when the object is deleted, because
 // it will be unbound in the GL.
+//
+// PreallocatedOwnersCapacity is the preallocated capacity for the array of refptrs to owners.
+// Having some minimal preallocated capacity is an important optimization, see bug 522193. In this
+// bug, a benchmark was using WebGLBuffer with a number of owners oscillating between 0 and 2.
+// At this time mRefOwners was a nsTArray, and the too frequent reallocations were slowing us down.
+template<int PreallocatedOwnersCapacity>
 class WebGLZeroingObject
 {
 public:
     WebGLZeroingObject()
     { }
 
     void AddRefOwner(WebGLObjectBaseRefPtr *owner) {
         mRefOwners.AppendElement(owner);
@@ -701,17 +708,17 @@ public:
         for (PRUint32 i = 0; i < mRefOwners.Length(); i++) {
             owners[i]->Zero();
         }
 
         mRefOwners.Clear();
     }
 
 protected:
-    nsTArray<WebGLObjectBaseRefPtr *> mRefOwners;
+    nsAutoTArray<WebGLObjectBaseRefPtr *, PreallocatedOwnersCapacity> mRefOwners;
 };
 
 // this class is a mixin for GL objects that have dimensions
 // that we need to track.
 class WebGLRectangleObject
 {
 protected:
     WebGLRectangleObject()
@@ -768,17 +775,17 @@ protected:
     WebGLContext *mContext;
     PRUint32 mContextGeneration;
 };
 
 #define WEBGLBUFFER_PRIVATE_IID \
     {0xd69f22e9, 0x6f98, 0x48bd, {0xb6, 0x94, 0x34, 0x17, 0xed, 0x06, 0x11, 0xab}}
 class WebGLBuffer :
     public nsIWebGLBuffer,
-    public WebGLZeroingObject,
+    public WebGLZeroingObject<8>, // almost never has more than 8 owners
     public WebGLContextBoundObject
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLBUFFER_PRIVATE_IID)
 
     WebGLBuffer(WebGLContext *context, WebGLuint name) :
         WebGLContextBoundObject(context),
         mName(name), mDeleted(PR_FALSE), mHasEverBeenBound(PR_FALSE),
@@ -904,17 +911,17 @@ protected:
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLBuffer, WEBGLBUFFER_PRIVATE_IID)
 
 #define WEBGLTEXTURE_PRIVATE_IID \
     {0x4c19f189, 0x1f86, 0x4e61, {0x96, 0x21, 0x0a, 0x11, 0xda, 0x28, 0x10, 0xdd}}
 class WebGLTexture :
     public nsIWebGLTexture,
-    public WebGLZeroingObject,
+    public WebGLZeroingObject<8>, // almost never has more than 8 owners
     public WebGLContextBoundObject
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLTEXTURE_PRIVATE_IID)
 
     WebGLTexture(WebGLContext *context, WebGLuint name) :
         WebGLContextBoundObject(context),
         mDeleted(PR_FALSE), mHasEverBeenBound(PR_FALSE), mName(name),
@@ -1343,17 +1350,17 @@ public:
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLTexture, WEBGLTEXTURE_PRIVATE_IID)
 
 #define WEBGLSHADER_PRIVATE_IID \
     {0x48cce975, 0xd459, 0x4689, {0x83, 0x82, 0x37, 0x82, 0x6e, 0xac, 0xe0, 0xa7}}
 class WebGLShader :
     public nsIWebGLShader,
-    public WebGLZeroingObject,
+    public WebGLZeroingObject<8>, // almost never has more than 8 owners
     public WebGLContextBoundObject
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLSHADER_PRIVATE_IID)
 
     WebGLShader(WebGLContext *context, WebGLuint name, WebGLenum stype) :
         WebGLContextBoundObject(context),
         mName(name), mDeleted(PR_FALSE), mType(stype),
@@ -1409,17 +1416,19 @@ protected:
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLShader, WEBGLSHADER_PRIVATE_IID)
 
 #define WEBGLPROGRAM_PRIVATE_IID \
     {0xb3084a5b, 0xa5b4, 0x4ee0, {0xa0, 0xf0, 0xfb, 0xdd, 0x64, 0xaf, 0x8e, 0x82}}
 class WebGLProgram :
     public nsIWebGLProgram,
-    public WebGLZeroingObject,
+    public WebGLZeroingObject<8>, // can actually have many more owners (WebGLUniformLocations),
+                                  // but that shouldn't be performance-critical as references to the uniformlocations are stored
+                                  // in mMapUniformLocations, limiting the churning
     public WebGLContextBoundObject
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLPROGRAM_PRIVATE_IID)
 
     WebGLProgram(WebGLContext *context, WebGLuint name) :
         WebGLContextBoundObject(context),
         mName(name), mDeleted(PR_FALSE), mDeletePending(PR_FALSE),
@@ -1536,17 +1545,17 @@ protected:
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLProgram, WEBGLPROGRAM_PRIVATE_IID)
 
 #define WEBGLRENDERBUFFER_PRIVATE_IID \
     {0x3cbc2067, 0x5831, 0x4e3f, {0xac, 0x52, 0x7e, 0xf4, 0x5c, 0x04, 0xff, 0xae}}
 class WebGLRenderbuffer :
     public nsIWebGLRenderbuffer,
-    public WebGLZeroingObject,
+    public WebGLZeroingObject<8>, // almost never has more than 8 owners
     public WebGLRectangleObject,
     public WebGLContextBoundObject
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLRENDERBUFFER_PRIVATE_IID)
 
     WebGLRenderbuffer(WebGLContext *context, WebGLuint name, WebGLuint secondBufferName = 0) :
         WebGLContextBoundObject(context),
@@ -1707,17 +1716,17 @@ public:
         return mRenderbufferPtr && !mRenderbufferPtr->Initialized();
     }
 };
 
 #define WEBGLFRAMEBUFFER_PRIVATE_IID \
     {0x0052a16f, 0x4bc9, 0x4a55, {0x9d, 0xa3, 0x54, 0x95, 0xaa, 0x4e, 0x80, 0xb9}}
 class WebGLFramebuffer :
     public nsIWebGLFramebuffer,
-    public WebGLZeroingObject,
+    public WebGLZeroingObject<8>, // almost never has more than 8 owners
     public WebGLContextBoundObject
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLFRAMEBUFFER_PRIVATE_IID)
 
     WebGLFramebuffer(WebGLContext *context, WebGLuint name) :
         WebGLContextBoundObject(context),
         mName(name), mDeleted(PR_FALSE), mHasEverBeenBound(PR_FALSE),
@@ -1982,17 +1991,19 @@ protected:
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLFramebuffer, WEBGLFRAMEBUFFER_PRIVATE_IID)
 
 #define WEBGLUNIFORMLOCATION_PRIVATE_IID \
     {0x01a8a614, 0xb109, 0x42f1, {0xb4, 0x40, 0x8d, 0x8b, 0x87, 0x0b, 0x43, 0xa7}}
 class WebGLUniformLocation :
     public nsIWebGLUniformLocation,
-    public WebGLZeroingObject,
+    public WebGLZeroingObject<2>, // never saw a WebGLUniformLocation have more than 2 owners, and since these
+                                  // are small objects and there are many of them, it's worth saving some memory
+                                  // by using a small value such as 2 here.
     public WebGLContextBoundObject
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLUNIFORMLOCATION_PRIVATE_IID)
 
     WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location) :
         WebGLContextBoundObject(context), mProgram(program), mProgramGeneration(program->Generation()),
         mLocation(location) { }
@@ -2049,17 +2060,19 @@ protected:
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLActiveInfo, WEBGLACTIVEINFO_PRIVATE_IID)
 
 #define WEBGLEXTENSION_PRIVATE_IID \
     {0x457dd0b2, 0x9f77, 0x4c23, {0x95, 0x70, 0x9d, 0x62, 0x65, 0xc1, 0xa4, 0x81}}
 class WebGLExtension :
     public nsIWebGLExtension,
     public WebGLContextBoundObject,
-    public WebGLZeroingObject
+    public WebGLZeroingObject<2> // WebGLExtensions probably won't have many owers and
+                                 // can be very small objects. Also, we have a static array of those. So, saving some memory
+                                 // by using a small value such as 2 here.
 {
 public:
     WebGLExtension(WebGLContext *baseContext)
         : WebGLContextBoundObject(baseContext)
     {}
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLEXTENSION