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.
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 towordCount(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?