Bug 1414168 - Base run offset calculations on the fixed header size, excluding regs_mask. r=njn
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 08 Nov 2017 10:08:37 +0900
changeset 444164 29a122463ffcc549f3ccccbc5779ea13ca68abfe
parent 444163 ef39a9dff092be182a51b0050e03c871e3bffdc2
child 444165 11bc33786fd378b717fc4ea358c12e6f96320432
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs1414168
milestone58.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 1414168 - Base run offset calculations on the fixed header size, excluding regs_mask. r=njn On 64-bit platforms, sizeof(arena_run_t) includes a padding at the end of the struct to align to 64-bit, since the last field, regs_mask, is 32-bit, and its offset can be a multiple of 64-bit depending on the configuration. But we're doing size calculations for a dynamically-sized regs_mask based on sizeof(arena_run_t), completely ignoring that padding. Instead, we use the offset of regs_mask as a base for the calculation. Practically speaking, this doesn't change much with the current set of values, but could affect the overheads when we squeeze run sizes more.
memory/build/mozjemalloc.cpp
--- a/memory/build/mozjemalloc.cpp
+++ b/memory/build/mozjemalloc.cpp
@@ -2959,59 +2959,61 @@ arena_t::MallocBinHard(arena_bin_t* aBin
 // bin->mRunNumRegions, bin->mRunNumRegionsMask, and bin->mRunFirstRegionOffset are
 // also calculated here, since these settings are all interdependent.
 static size_t
 arena_bin_run_size_calc(arena_bin_t* bin, size_t min_run_size)
 {
   size_t try_run_size, good_run_size;
   unsigned good_nregs, good_mask_nelms, good_reg0_offset;
   unsigned try_nregs, try_mask_nelms, try_reg0_offset;
+  // Size of the run header, excluding regs_mask.
+  static const size_t kFixedHeaderSize = offsetof(arena_run_t, regs_mask);
 
   MOZ_ASSERT(min_run_size >= gPageSize);
   MOZ_ASSERT(min_run_size <= gMaxLargeClass);
 
   // Calculate known-valid settings before entering the mRunSize
   // expansion loop, so that the first part of the loop always copies
   // valid settings.
   //
   // The do..while loop iteratively reduces the number of regions until
   // the run header and the regions no longer overlap.  A closed formula
   // would be quite messy, since there is an interdependency between the
   // header's mask length and the number of regions.
   try_run_size = min_run_size;
-  try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->mSizeClass) +
+  try_nregs = ((try_run_size - kFixedHeaderSize) / bin->mSizeClass) +
               1; // Counter-act try_nregs-- in loop.
   do {
     try_nregs--;
     try_mask_nelms =
       (try_nregs >> (LOG2(sizeof(int)) + 3)) +
       ((try_nregs & ((1U << (LOG2(sizeof(int)) + 3)) - 1)) ? 1 : 0);
     try_reg0_offset = try_run_size - (try_nregs * bin->mSizeClass);
-  } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1)) >
+  } while (kFixedHeaderSize + (sizeof(unsigned) * try_mask_nelms) >
            try_reg0_offset);
 
   // mRunSize expansion loop.
   while (true) {
     // Copy valid settings before trying more aggressive settings.
     good_run_size = try_run_size;
     good_nregs = try_nregs;
     good_mask_nelms = try_mask_nelms;
     good_reg0_offset = try_reg0_offset;
 
     // Try more aggressive settings.
     try_run_size += gPageSize;
-    try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->mSizeClass) +
+    try_nregs = ((try_run_size - kFixedHeaderSize) / bin->mSizeClass) +
                 1; // Counter-act try_nregs-- in loop.
     do {
       try_nregs--;
       try_mask_nelms =
         (try_nregs >> (LOG2(sizeof(int)) + 3)) +
         ((try_nregs & ((1U << (LOG2(sizeof(int)) + 3)) - 1)) ? 1 : 0);
       try_reg0_offset = try_run_size - (try_nregs * bin->mSizeClass);
-    } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1)) >
+    } while (kFixedHeaderSize + (sizeof(unsigned) * try_mask_nelms) >
              try_reg0_offset);
 
     // Don't allow runs larger than the largest possible large size class.
     if (try_run_size > gMaxLargeClass) {
       break;
     }
 
     // Try to keep the run overhead below kRunOverhead.
@@ -3022,23 +3024,23 @@ arena_bin_run_size_calc(arena_bin_t* bin
     // The run header includes one bit per region of the given size. For sizes
     // small enough, the number of regions is large enough that growing the run
     // size barely moves the needle for the overhead because of all those bits.
     // For example, for a size of 8 bytes, adding 4KiB to the run size adds
     // close to 512 bits to the header, which is 64 bytes.
     // With such overhead, there is no way to get to the wanted overhead above,
     // so we give up if the required size for regs_mask more than doubles the
     // size of the run header.
-    if (try_mask_nelms * sizeof(unsigned) >= sizeof(arena_run_t)) {
+    if (try_mask_nelms * sizeof(unsigned) >= kFixedHeaderSize) {
       break;
     }
 
   }
 
-  MOZ_ASSERT(sizeof(arena_run_t) + (sizeof(unsigned) * (good_mask_nelms - 1)) <=
+  MOZ_ASSERT(kFixedHeaderSize + (sizeof(unsigned) * good_mask_nelms) <=
              good_reg0_offset);
   MOZ_ASSERT((good_mask_nelms << (LOG2(sizeof(int)) + 3)) >= good_nregs);
 
   // Copy final settings.
   bin->mRunSize = good_run_size;
   bin->mRunNumRegions = good_nregs;
   bin->mRunNumRegionsMask = good_mask_nelms;
   bin->mRunFirstRegionOffset = good_reg0_offset;