Bug 1132966 - use relaxed Atomic integers for tracking graphics surface memory usage; r=njn
authorNathan Froyd <froydnj@mozilla.com>
Fri, 31 Jul 2015 22:43:24 -0400
changeset 288124 5399666bb0ca21c5735349349c324461a145efc8
parent 288123 0c95a8b88ecd59024269691d21b4cd99ec474ac7
child 288125 04a196339ca46b8e87544fdff12f9f855b27c803
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs1132966
milestone42.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 1132966 - use relaxed Atomic integers for tracking graphics surface memory usage; r=njn Graphics surface memory usage tracking is done manually, with a global array containing the number of bytes per each type of surface used. Since the members of the array can be touched by several different threads, dynamic race checkers such as TSan complain about To assuage TSan's sensibilities, we need to use atomics with relaxed memory consistency; this change generates code identical to what we had before, but the atomic type assures TSan that it's OK to access members on multiple threads. We use the relaxed memory consistency to avoid memory barriers in the generated code.
gfx/thebes/gfxASurface.cpp
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -559,51 +559,65 @@ static const SurfaceMemoryReporterAttrs 
 
 PR_STATIC_ASSERT(MOZ_ARRAY_LENGTH(sSurfaceMemoryReporterAttrs) ==
                  size_t(gfxSurfaceType::Max));
 PR_STATIC_ASSERT(uint32_t(CAIRO_SURFACE_TYPE_SKIA) ==
                  uint32_t(gfxSurfaceType::Skia));
 
 /* Surface size memory reporting */
 
-static int64_t gSurfaceMemoryUsed[size_t(gfxSurfaceType::Max)] = { 0 };
-
 class SurfaceMemoryReporter final : public nsIMemoryReporter
 {
     ~SurfaceMemoryReporter() {}
 
+    // We can touch this array on several different threads, and we don't
+    // want to introduce memory barriers when recording the memory used.  To
+    // assure dynamic race checkers like TSan that this is OK, we use
+    // relaxed memory ordering here.
+    static Atomic<size_t, Relaxed> sSurfaceMemoryUsed[size_t(gfxSurfaceType::Max)];
+
 public:
+    static void AdjustUsedMemory(gfxSurfaceType aType, int32_t aBytes)
+    {
+        // A read-modify-write operation like += would require a memory barrier
+        // here, which would defeat the purpose of using relaxed memory
+        // ordering.  So separate out the read and write operations.
+        sSurfaceMemoryUsed[size_t(aType)] = sSurfaceMemoryUsed[size_t(aType)] + aBytes;
+    };
+    
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb,
                               nsISupports *aClosure, bool aAnonymize) override
     {
         const size_t len = ArrayLength(sSurfaceMemoryReporterAttrs);
         for (size_t i = 0; i < len; i++) {
-            int64_t amount = gSurfaceMemoryUsed[i];
+            int64_t amount = sSurfaceMemoryUsed[i];
 
             if (amount != 0) {
                 const char *path = sSurfaceMemoryReporterAttrs[i].path;
                 const char *desc = sSurfaceMemoryReporterAttrs[i].description;
                 if (!desc) {
                     desc = sDefaultSurfaceDescription;
                 }
 
                 nsresult rv = aCb->Callback(EmptyCString(), nsCString(path),
                                             KIND_OTHER, UNITS_BYTES,
-                                            gSurfaceMemoryUsed[i],
+                                            amount,
                                             nsCString(desc), aClosure);
                 NS_ENSURE_SUCCESS(rv, rv);
             }
         }
 
         return NS_OK;
     }
 };
 
+Atomic<size_t, Relaxed> SurfaceMemoryReporter::sSurfaceMemoryUsed[size_t(gfxSurfaceType::Max)];
+
 NS_IMPL_ISUPPORTS(SurfaceMemoryReporter, nsIMemoryReporter)
 
 void
 gfxASurface::RecordMemoryUsedForSurfaceType(gfxSurfaceType aType,
                                             int32_t aBytes)
 {
     if (int(aType) < 0 || aType >= gfxSurfaceType::Max) {
         NS_WARNING("Invalid type to RecordMemoryUsedForSurfaceType!");
@@ -611,17 +625,17 @@ gfxASurface::RecordMemoryUsedForSurfaceT
     }
 
     static bool registered = false;
     if (!registered) {
         RegisterStrongMemoryReporter(new SurfaceMemoryReporter());
         registered = true;
     }
 
-    gSurfaceMemoryUsed[size_t(aType)] += aBytes;
+    SurfaceMemoryReporter::AdjustUsedMemory(aType, aBytes);
 }
 
 void
 gfxASurface::RecordMemoryUsed(int32_t aBytes)
 {
     RecordMemoryUsedForSurfaceType(GetType(), aBytes);
     mBytesRecorded += aBytes;
 }