plasma-umass / Mesh

A memory allocator that automatically reduces the memory footprint of C/C++ applications.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

32-bits system support?

jku65123 opened this issue · comments

It looks like this cool library only works in 64-bits system, any ideas on how much works to make it on 32-bits system (there are a lot 32-bits devices out there) ? and where to change if we want to support 32-bits? Thanks!

you're right in that we only support 64-bit systems right now. At a minimum, we'd need to decrease the max arena size to 2 GB here: https://github.com/plasma-umass/Mesh/blob/master/src/common.h#L98

I'm not sure what else would be necessary TBH. I think we would be willing to take patches, as long as they aren't very intrusive or complex.

commented

I got it working on a rpi3 rasbian with the following changes for 32 bit:

Basically:

In configure:

  • Set modern_cpu to false in configure because the check throws an index out of range

In meshable_arena.cc:

  • Change the include of unistd_64.h (doesn't exist on arm) to unistd.h

In bitmap.h:

  • The AtomicBitmapBase assumes 4 entries in _bits to be changed, I reverted that back to the loop as it will now contain 8 entries.
  • wordCount will be twice as much as the bits is divided by 32 instead of 64, so the static_asserts such as wordCount(representationSize(maxBits)) == 4 need to be changed to wordCount(representationSize(maxBits)) == 8
  • In RelaxedBitmapBase there are a few magic numbers 64 and 63. Those need to be changed to 32 and 31.
  • Static asserts at the bottom to check for bitmap size need to have its size doubled as well
  • The MaxBitCount enum needs to be based on uint32_t instead of uint64_t

In common.h:

  • The kArenaSize needed to be set to 1GB. I tried 2GB but it was refused in the syscall mmap2 (checked with strace)
  • The kMinObjectSize needs to be set to 8 instead of 16 so the unit test for alignment doesn't fail

In the size class unit test:

  • 2 asserts that check on kMinObjectSize needed to be adjusted for the change above

I don't know enough C++ magic to do these changes based on a compiler flag so I changed to code directly.

Full diff:

diff --git a/configure b/configure
index 0e84ff6..9659f03 100755
--- a/configure
+++ b/configure
@@ -46,9 +46,10 @@ modern_cpu = True
 if system() == 'Linux':
     # we need to check if the CPU is recent enough to use popcnt and
     # AVX instructions
-    cpuinfo = slurp('/proc/cpuinfo').splitlines()
-    flags = [l for l in cpuinfo if l.startswith('flags')][0]
-    modern_cpu = 'popcnt' in flags and 'avx' in flags
+#    cpuinfo = slurp('/proc/cpuinfo').splitlines()
+#    flags = [l for l in cpuinfo if l.startswith('flags')][0]
+#    modern_cpu = 'popcnt' in flags and 'avx' in flags
+     modern_cpu = 0

 if modern_cpu:
     c.append('cflags', '-march=westmere')
diff --git a/src/bitmap.h b/src/bitmap.h
index 0008833..d68b3b8 100644
--- a/src/bitmap.h
+++ b/src/bitmap.h
@@ -73,6 +73,12 @@ private:
   const Container &_cont;
 };

+template<size_t A, size_t B> struct TAssertEquality {
+  static_assert(A==B, "Not equal");
+  static constexpr bool _cResult = (A==B);
+};
+
+
 template <size_t maxBits>
 class AtomicBitmapBase {
 private:
@@ -83,18 +89,25 @@ public:

   enum { MaxBitCount = maxBits };

+
 protected:
   AtomicBitmapBase(size_t bitCount) {
     d_assert_msg(bitCount <= maxBits, "max bits (%zu) exceeded: %zu", maxBits, bitCount);

-    static_assert(wordCount(representationSize(maxBits)) == 4, "unexpected representation size");
-    // for (size_t i = 0; i < wordCount(representationSize(maxBits)); i++) {
-    //   _bits[i].store(0, std::memory_order_relaxed);
-    // }
-    _bits[0].store(0, std::memory_order_relaxed);
+    static_assert(wordCount(representationSize(maxBits)) == 8, "unexpected representation size");
+     for (size_t i = 0; i < wordCount(representationSize(maxBits)); i++) {
+       _bits[i].store(0, std::memory_order_relaxed);
+     }
+    /*_bits[0].store(0, std::memory_order_relaxed);
     _bits[1].store(0, std::memory_order_relaxed);
     _bits[2].store(0, std::memory_order_relaxed);
     _bits[3].store(0, std::memory_order_relaxed);
+
+    _bits[4].store(0, std::memory_order_relaxed);
+    _bits[5].store(0, std::memory_order_relaxed);
+    _bits[6].store(0, std::memory_order_relaxed);
+    _bits[7].store(0, std::memory_order_relaxed);
+*/
     std::atomic_thread_fence(std::memory_order_release);
   }

@@ -102,13 +115,20 @@ protected:
   }

   inline void ATTRIBUTE_ALWAYS_INLINE setAndExchangeAll(size_t *oldBits, const size_t *newBits) {
-    // for (size_t i = 0; i < wordCount(representationSize(maxBits)); i++) {
-    //   oldBits[i] = _bits[i].exchange(newBits[i]);
-    // }
-    oldBits[0] = _bits[0].exchange(newBits[0], std::memory_order_acq_rel);
+     for (size_t i = 0; i < wordCount(representationSize(maxBits)); i++) {
+       oldBits[i] = _bits[i].exchange(newBits[i]);
+     }
+
+    /*oldBits[0] = _bits[0].exchange(newBits[0], std::memory_order_acq_rel);
     oldBits[1] = _bits[1].exchange(newBits[1], std::memory_order_acq_rel);
     oldBits[2] = _bits[2].exchange(newBits[2], std::memory_order_acq_rel);
     oldBits[3] = _bits[3].exchange(newBits[3], std::memory_order_acq_rel);
+
+    oldBits[4] = _bits[4].exchange(newBits[4], std::memory_order_acq_rel);
+    oldBits[5] = _bits[5].exchange(newBits[5], std::memory_order_acq_rel);
+    oldBits[6] = _bits[6].exchange(newBits[6], std::memory_order_acq_rel);
+    oldBits[7] = _bits[7].exchange(newBits[7], std::memory_order_acq_rel);
+    */
   }

 public:
@@ -163,7 +183,7 @@ private:
 public:
   typedef size_t word_t;

-  enum { MaxBitCount = std::numeric_limits<uint64_t>::max() };
+  enum { MaxBitCount = std::numeric_limits<uint32_t>::max() };

 protected:
   RelaxedBitmapBase(size_t bitCount)
@@ -200,9 +220,9 @@ public:
   inline void setAll(uint64_t bitCount) {
     const size_t numWords = wordCount(representationSize(bitCount));
     for (size_t i = 0; bitCount > 0; i++) {
-      if (bitCount >= 64) {
+      if (bitCount >= 32) {
         _bits[i] = (unsigned long)-1;
-        bitCount -= 64;
+        bitCount -= 32;
       } else {
         _bits[i] = (1ULL << bitCount) - 1;
         bitCount = 0;
@@ -251,7 +271,7 @@ protected:
     return _bitCount;
   }

-  const size_t _bitCount : 63;
+  const size_t _bitCount : 31;
   const size_t _isDynamicallyAllocated : 1;
   word_t *_bits;
 };
@@ -273,21 +293,21 @@ protected:

 public:
   inline void ATTRIBUTE_ALWAYS_INLINE invert() {
-    // constexpr size_t numWords = wordCount(representationSize(maxBits));
-    // for (size_t i = 0; i < numWords; i++) {
-    //   _bits[i] = ~_bits[i];
-    // }
-    _bits[0] = ~_bits[0];
+     constexpr size_t numWords = wordCount(representationSize(maxBits));
+     for (size_t i = 0; i < numWords; i++) {
+       _bits[i] = ~_bits[i];
+     }
+    /*_bits[0] = ~_bits[0];
     _bits[1] = ~_bits[1];
     _bits[2] = ~_bits[2];
-    _bits[3] = ~_bits[3];
+    _bits[3] = ~_bits[3];*/
   }

   inline void ATTRIBUTE_ALWAYS_INLINE setAll(uint64_t bitCount) {
     for (size_t i = 0; bitCount > 0; i++) {
-      if (bitCount >= 64) {
+      if (bitCount >= 32) {
         _bits[i] = (unsigned long)-1;
-        bitCount -= 64;
+        bitCount -= 32;
       } else {
         _bits[i] = (1ULL << bitCount) - 1;
         bitCount = 0;
@@ -538,17 +558,17 @@ public:
     const auto wordCount = byteCount() / sizeof(size_t);
     for (ssize_t i = startWord; i >= 0; i--) {
       uint64_t mask = (1UL << (startOff + 1)) - 1;
-      if (startOff == 63) {
+      if (startOff == 31) {
         mask = ~0UL;
       }
       const auto bits = Super::_bits[i] & mask;
       const auto origStartOff = startOff;
-      startOff = 63;
+      startOff = 31;

       if (bits == 0ULL)
         continue;

-      const size_t off = 64 - __builtin_clzl(bits) - 1;
+      const size_t off = 32 - __builtin_clzl(bits) - 1;

       const auto bit = kWordBits * i + off;
       return bit < bitCount() ? bit : bitCount();
@@ -578,8 +598,10 @@ typedef bitmap::BitmapBase<bitmap::AtomicBitmapBase<256>> Bitmap;
 typedef bitmap::BitmapBase<bitmap::RelaxedFixedBitmapBase<256>> RelaxedFixedBitmap;
 typedef bitmap::BitmapBase<bitmap::RelaxedBitmapBase> RelaxedBitmap;

-static_assert(sizeof(Bitmap) == sizeof(size_t) * 4, "Bitmap unexpected size");
-static_assert(sizeof(RelaxedFixedBitmap) == sizeof(size_t) * 4, "Bitmap unexpected size");
+
+
+static_assert(sizeof(Bitmap) == sizeof(size_t) * 8, "Bitmap unexpected size");
+static_assert(sizeof(RelaxedFixedBitmap) == sizeof(size_t) * 8, "Bitmap unexpected size");
 static_assert(sizeof(RelaxedBitmap) == sizeof(size_t) * 2, "Bitmap unexpected size");
 }  // namespace internal
 }  // namespace mesh
diff --git a/src/common.h b/src/common.h
index 7854558..ae7198b 100644
--- a/src/common.h
+++ b/src/common.h
@@ -52,7 +52,7 @@ static constexpr int kMapShared = 1;
 static constexpr int kMapShared = kMeshingEnabled ? MAP_SHARED : MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
 #endif

-static constexpr size_t kMinObjectSize = 16;
+static constexpr size_t kMinObjectSize = 8;
 static constexpr size_t kMaxSize = 16384;
 static constexpr size_t kClassSizesMax = 96;
 static constexpr size_t kAlignment = 8;
@@ -101,7 +101,7 @@ static constexpr std::chrono::milliseconds kMeshPeriodMs{100};  // 100 ms
 // controls aspects of miniheaps
 static constexpr size_t kMaxMeshes = 256;  // 1 per bit

-static constexpr size_t kArenaSize = 64ULL * 1024ULL * 1024ULL * 1024ULL;  // 64 GB
+static constexpr size_t kArenaSize = 1ULL * 1024ULL * 1024ULL * 1024ULL;  // 1 GB
 static constexpr size_t kAltStackSize = 16 * 1024UL;                       // 16k sigaltstacks
 #define SIGQUIESCE (SIGRTMIN + 7)
 #define SIGDUMP (SIGRTMIN + 8)
diff --git a/src/meshable_arena.cc b/src/meshable_arena.cc
index b325531..023b2a5 100644
--- a/src/meshable_arena.cc
+++ b/src/meshable_arena.cc
@@ -15,7 +15,7 @@
 #include <unistd.h>

 //#include <sys/memfd.h>
-#include <asm/unistd_64.h>
+#include <asm/unistd.h>
 #include <linux/memfd.h>
 #endif

diff --git a/src/unit/bitmap_test.cc b/src/unit/bitmap_test.cc
index 5c0fcc9..30a7f22 100644
--- a/src/unit/bitmap_test.cc
+++ b/src/unit/bitmap_test.cc
@@ -13,10 +13,10 @@

 TEST(BitmapTest, RepresentationSize) {
   ASSERT_EQ(0UL, mesh::bitmap::representationSize(0));
-  ASSERT_EQ(8UL, mesh::bitmap::representationSize(1));
+  ASSERT_EQ(4UL, mesh::bitmap::representationSize(1));
   ASSERT_EQ(8UL, mesh::bitmap::representationSize(64));
   ASSERT_EQ(32UL, mesh::bitmap::representationSize(256));
-  ASSERT_EQ(4UL, mesh::bitmap::representationSize(256) / sizeof(size_t));
+  ASSERT_EQ(8UL, mesh::bitmap::representationSize(256) / sizeof(size_t));
 }

 TEST(BitmapTest, LowestSetBitAt) {
diff --git a/src/unit/size_class_test.cc b/src/unit/size_class_test.cc
index f9e61c3..cefce8c 100644
--- a/src/unit/size_class_test.cc
+++ b/src/unit/size_class_test.cc
@@ -21,9 +21,9 @@ using namespace mesh;
 TEST(SizeClass, MinObjectSize) {
   ASSERT_EQ(alignof(max_align_t), kMinObjectSize);

-  ASSERT_EQ(kMinObjectSize, 16UL);
+  ASSERT_EQ(kMinObjectSize, 8UL);

-  ASSERT_EQ(staticlog(kMinObjectSize), 4);
+  ASSERT_EQ(staticlog(kMinObjectSize), 3);
 }

 TEST(SizeClass, SmallClasses) {

@bpowers Is there any stress test I can run to make sure there aren't any issues after a long period of time?