mesh-rb 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/ext/mesh/extconf.rb +22 -4
- data/ext/mesh/mesh.tar.gz +0 -0
- data/lib/mesh/version.rb +1 -1
- data/mesh.gemspec +3 -2
- metadata +4 -120
- data/ext/mesh/mesh/.bazelrc +0 -20
- data/ext/mesh/mesh/.bazelversion +0 -1
- data/ext/mesh/mesh/.clang-format +0 -15
- data/ext/mesh/mesh/.dockerignore +0 -5
- data/ext/mesh/mesh/.editorconfig +0 -16
- data/ext/mesh/mesh/.gitattributes +0 -4
- data/ext/mesh/mesh/.github/workflows/main.yml +0 -144
- data/ext/mesh/mesh/.gitignore +0 -51
- data/ext/mesh/mesh/AUTHORS +0 -5
- data/ext/mesh/mesh/CMakeLists.txt +0 -270
- data/ext/mesh/mesh/CODE_OF_CONDUCT.md +0 -77
- data/ext/mesh/mesh/Dockerfile +0 -30
- data/ext/mesh/mesh/LICENSE +0 -201
- data/ext/mesh/mesh/Makefile +0 -81
- data/ext/mesh/mesh/README.md +0 -97
- data/ext/mesh/mesh/WORKSPACE +0 -50
- data/ext/mesh/mesh/bazel +0 -350
- data/ext/mesh/mesh/mesh-pldi19-powers.pdf +0 -0
- data/ext/mesh/mesh/src/BUILD +0 -222
- data/ext/mesh/mesh/src/CMakeLists.txt +0 -85
- data/ext/mesh/mesh/src/bitmap.h +0 -590
- data/ext/mesh/mesh/src/cheap_heap.h +0 -170
- data/ext/mesh/mesh/src/common.h +0 -377
- data/ext/mesh/mesh/src/copts.bzl +0 -31
- data/ext/mesh/mesh/src/d_assert.cc +0 -75
- data/ext/mesh/mesh/src/fixed_array.h +0 -124
- data/ext/mesh/mesh/src/global_heap.cc +0 -547
- data/ext/mesh/mesh/src/global_heap.h +0 -569
- data/ext/mesh/mesh/src/gnu_wrapper.cc +0 -75
- data/ext/mesh/mesh/src/internal.h +0 -356
- data/ext/mesh/mesh/src/libmesh.cc +0 -239
- data/ext/mesh/mesh/src/mac_wrapper.cc +0 -528
- data/ext/mesh/mesh/src/measure_rss.cc +0 -44
- data/ext/mesh/mesh/src/measure_rss.h +0 -20
- data/ext/mesh/mesh/src/meshable_arena.cc +0 -776
- data/ext/mesh/mesh/src/meshable_arena.h +0 -309
- data/ext/mesh/mesh/src/meshing.h +0 -60
- data/ext/mesh/mesh/src/mini_heap.h +0 -532
- data/ext/mesh/mesh/src/mmap_heap.h +0 -104
- data/ext/mesh/mesh/src/one_way_mmap_heap.h +0 -77
- data/ext/mesh/mesh/src/partitioned_heap.h +0 -111
- data/ext/mesh/mesh/src/plasma/mesh.h +0 -33
- data/ext/mesh/mesh/src/real.cc +0 -52
- data/ext/mesh/mesh/src/real.h +0 -36
- data/ext/mesh/mesh/src/rng/mwc.h +0 -296
- data/ext/mesh/mesh/src/rng/mwc64.h +0 -58
- data/ext/mesh/mesh/src/rpl_printf.c +0 -1991
- data/ext/mesh/mesh/src/runtime.cc +0 -393
- data/ext/mesh/mesh/src/runtime.h +0 -114
- data/ext/mesh/mesh/src/shuffle_vector.h +0 -287
- data/ext/mesh/mesh/src/size_classes.def +0 -251
- data/ext/mesh/mesh/src/static/if.h +0 -36
- data/ext/mesh/mesh/src/static/log.h +0 -43
- data/ext/mesh/mesh/src/testing/benchmark/local_refill.cc +0 -103
- data/ext/mesh/mesh/src/testing/big-alloc.c +0 -28
- data/ext/mesh/mesh/src/testing/fragmenter.cc +0 -128
- data/ext/mesh/mesh/src/testing/global-large-stress.cc +0 -25
- data/ext/mesh/mesh/src/testing/local-alloc.c +0 -16
- data/ext/mesh/mesh/src/testing/meshing_benchmark.cc +0 -189
- data/ext/mesh/mesh/src/testing/thread.cc +0 -35
- data/ext/mesh/mesh/src/testing/unit/alignment.cc +0 -56
- data/ext/mesh/mesh/src/testing/unit/bitmap_test.cc +0 -274
- data/ext/mesh/mesh/src/testing/unit/concurrent_mesh_test.cc +0 -185
- data/ext/mesh/mesh/src/testing/unit/mesh_test.cc +0 -143
- data/ext/mesh/mesh/src/testing/unit/rng_test.cc +0 -22
- data/ext/mesh/mesh/src/testing/unit/size_class_test.cc +0 -66
- data/ext/mesh/mesh/src/testing/unit/triple_mesh_test.cc +0 -285
- data/ext/mesh/mesh/src/testing/userfaultfd-kernel-copy.cc +0 -164
- data/ext/mesh/mesh/src/thread_local_heap.cc +0 -163
- data/ext/mesh/mesh/src/thread_local_heap.h +0 -268
- data/ext/mesh/mesh/src/wrapper.cc +0 -433
- data/ext/mesh/mesh/support/export_mesh.cmake +0 -28
- data/ext/mesh/mesh/support/gen-size-classes +0 -57
- data/ext/mesh/mesh/support/install_all_configs +0 -33
- data/ext/mesh/mesh/support/remove_export_mesh.cmake +0 -48
- data/ext/mesh/mesh/support/update-bazelisk +0 -8
- data/ext/mesh/mesh/theory/32m80.png +0 -0
- data/ext/mesh/mesh/theory/64m80ind.png +0 -0
- data/ext/mesh/mesh/theory/bound_comparison.py +0 -67
- data/ext/mesh/mesh/theory/bounds/impdeg+1 +0 -135
- data/ext/mesh/mesh/theory/choose.py +0 -43
- data/ext/mesh/mesh/theory/common.py +0 -42
- data/ext/mesh/mesh/theory/compute_exp_Y.py +0 -134
- data/ext/mesh/mesh/theory/createRandomString.py +0 -69
- data/ext/mesh/mesh/theory/deg_bound_check.py +0 -100
- data/ext/mesh/mesh/theory/degcheck.py +0 -47
- data/ext/mesh/mesh/theory/dumps/32,1,80,dumb.txt +0 -81
- data/ext/mesh/mesh/theory/dumps/32,2,80,dumb.txt +0 -81
- data/ext/mesh/mesh/theory/dumps/32,3,80,dumb.txt +0 -81
- data/ext/mesh/mesh/theory/dumps/32,4,80,dumb.txt +0 -81
- data/ext/mesh/mesh/theory/dumps/32,5,80,dumb.txt +0 -81
- data/ext/mesh/mesh/theory/dumps/32,6,80,dumb.txt +0 -81
- data/ext/mesh/mesh/theory/dumps/32,7,80,dumb.txt +0 -81
- data/ext/mesh/mesh/theory/dumps/32,8,80,dumb.txt +0 -81
- data/ext/mesh/mesh/theory/dumps/32,9,80,dumb.txt +0 -81
- data/ext/mesh/mesh/theory/experiment.py +0 -303
- data/ext/mesh/mesh/theory/experiment_raw_results/.gitignore +0 -0
- data/ext/mesh/mesh/theory/greedy_experiment.py +0 -66
- data/ext/mesh/mesh/theory/greedy_experiment_copy.py +0 -46
- data/ext/mesh/mesh/theory/greedy_experiment_q.py +0 -75
- data/ext/mesh/mesh/theory/makeGraph.py +0 -64
- data/ext/mesh/mesh/theory/manyreps.png +0 -0
- data/ext/mesh/mesh/theory/manystrings.png +0 -0
- data/ext/mesh/mesh/theory/match_vs_color_experiment.py +0 -94
- data/ext/mesh/mesh/theory/maxmatch_vs_E[Y].py +0 -162
- data/ext/mesh/mesh/theory/maxmatch_vs_greedymatch.py +0 -96
- data/ext/mesh/mesh/theory/maxvdeg+1imp++32,80.png +0 -0
- data/ext/mesh/mesh/theory/mesh_util.py +0 -322
- data/ext/mesh/mesh/theory/meshers.py +0 -452
- data/ext/mesh/mesh/theory/meshingBenchmark.py +0 -96
- data/ext/mesh/mesh/theory/occupancyComparison.py +0 -133
- data/ext/mesh/mesh/theory/randmatch_vs_greedymatch.py +0 -97
- data/ext/mesh/mesh/theory/randmatch_vs_greedymatch_q.py +0 -103
- data/ext/mesh/mesh/theory/randmatch_vs_greedymatch_time.py +0 -117
- data/ext/mesh/mesh/theory/read_mesh_dump.py +0 -82
- data/ext/mesh/mesh/theory/test.py +0 -70
- data/ext/mesh/mesh/tools/bazel +0 -1
@@ -1,143 +0,0 @@
|
|
1
|
-
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
2
|
-
// Copyright 2017 University of Massachusetts, Amherst
|
3
|
-
|
4
|
-
#include <stdint.h>
|
5
|
-
#include <stdlib.h>
|
6
|
-
|
7
|
-
#include "gtest/gtest.h"
|
8
|
-
|
9
|
-
#include "internal.h"
|
10
|
-
#include "meshing.h"
|
11
|
-
#include "runtime.h"
|
12
|
-
|
13
|
-
using namespace mesh;
|
14
|
-
|
15
|
-
static constexpr uint32_t StrLen = 128;
|
16
|
-
static constexpr uint32_t ObjCount = 32;
|
17
|
-
|
18
|
-
// shows up in strace logs, but otherwise does nothing
|
19
|
-
static inline void note(const char *note) {
|
20
|
-
int _ __attribute__((unused)) = write(-1, note, strlen(note));
|
21
|
-
}
|
22
|
-
|
23
|
-
static void meshTest(bool invert) {
|
24
|
-
if (!kMeshingEnabled) {
|
25
|
-
GTEST_SKIP();
|
26
|
-
}
|
27
|
-
|
28
|
-
const auto tid = gettid();
|
29
|
-
GlobalHeap &gheap = runtime().heap();
|
30
|
-
|
31
|
-
// disable automatic meshing for this test
|
32
|
-
gheap.setMeshPeriodMs(kZeroMs);
|
33
|
-
|
34
|
-
ASSERT_EQ(gheap.getAllocatedMiniheapCount(), 0UL);
|
35
|
-
|
36
|
-
FixedArray<MiniHeap, 1> array{};
|
37
|
-
|
38
|
-
// allocate two miniheaps for the same object size from our global heap
|
39
|
-
gheap.allocSmallMiniheaps(SizeMap::SizeClass(StrLen), StrLen, array, tid);
|
40
|
-
MiniHeap *mh1 = array[0];
|
41
|
-
array.clear();
|
42
|
-
|
43
|
-
gheap.allocSmallMiniheaps(SizeMap::SizeClass(StrLen), StrLen, array, tid);
|
44
|
-
MiniHeap *mh2 = array[0];
|
45
|
-
array.clear();
|
46
|
-
|
47
|
-
ASSERT_EQ(gheap.getAllocatedMiniheapCount(), 2UL);
|
48
|
-
|
49
|
-
// sanity checks
|
50
|
-
ASSERT_TRUE(mh1 != mh2);
|
51
|
-
ASSERT_EQ(mh1->maxCount(), mh2->maxCount());
|
52
|
-
ASSERT_EQ(mh1->maxCount(), ObjCount);
|
53
|
-
|
54
|
-
ASSERT_EQ(mh1->bitmap().inUseCount(), 0UL);
|
55
|
-
ASSERT_EQ(mh2->bitmap().inUseCount(), 0UL);
|
56
|
-
|
57
|
-
// allocate two c strings, one from each miniheap at different offsets
|
58
|
-
char *s1 = reinterpret_cast<char *>(mh1->mallocAt(gheap.arenaBegin(), 0));
|
59
|
-
char *s2 = reinterpret_cast<char *>(mh2->mallocAt(gheap.arenaBegin(), ObjCount - 1));
|
60
|
-
|
61
|
-
ASSERT_TRUE(s1 != nullptr);
|
62
|
-
ASSERT_TRUE(s2 != nullptr);
|
63
|
-
|
64
|
-
// fill in the strings, set the trailing null byte
|
65
|
-
memset(s1, 'A', StrLen);
|
66
|
-
memset(s2, 'Z', StrLen);
|
67
|
-
s1[StrLen - 1] = 0;
|
68
|
-
s2[StrLen - 1] = 0;
|
69
|
-
|
70
|
-
// copy these strings so we can check the contents after meshing
|
71
|
-
char *v1 = strdup(s1);
|
72
|
-
char *v2 = strdup(s2);
|
73
|
-
ASSERT_STREQ(s1, v1);
|
74
|
-
ASSERT_STREQ(s2, v2);
|
75
|
-
|
76
|
-
ASSERT_EQ(mh1->inUseCount(), 1UL);
|
77
|
-
ASSERT_EQ(mh2->inUseCount(), 1UL);
|
78
|
-
|
79
|
-
ASSERT_EQ(mh1->bitmap().inUseCount(), 1UL);
|
80
|
-
ASSERT_EQ(mh2->bitmap().inUseCount(), 1UL);
|
81
|
-
|
82
|
-
if (invert) {
|
83
|
-
MiniHeap *tmp = mh1;
|
84
|
-
mh1 = mh2;
|
85
|
-
mh2 = tmp;
|
86
|
-
}
|
87
|
-
|
88
|
-
const auto bitmap1 = mh1->bitmap().bits();
|
89
|
-
const auto bitmap2 = mh2->bitmap().bits();
|
90
|
-
const auto len = mh1->bitmap().byteCount();
|
91
|
-
ASSERT_EQ(len, mh2->bitmap().byteCount());
|
92
|
-
|
93
|
-
ASSERT_TRUE(mesh::bitmapsMeshable(bitmap1, bitmap2, len));
|
94
|
-
|
95
|
-
note("ABOUT TO MESH");
|
96
|
-
// mesh the two miniheaps together
|
97
|
-
gheap.meshLocked(mh1, mh2);
|
98
|
-
note("DONE MESHING");
|
99
|
-
|
100
|
-
// ensure the count of set bits looks right
|
101
|
-
ASSERT_EQ(mh1->inUseCount(), 2UL);
|
102
|
-
|
103
|
-
// check that our two allocated objects still look right
|
104
|
-
ASSERT_STREQ(s1, v1);
|
105
|
-
ASSERT_STREQ(s2, v2);
|
106
|
-
|
107
|
-
// get an aliased pointer to the second string by pointer arithmetic
|
108
|
-
// on the first string
|
109
|
-
char *s3 = s1 + (ObjCount - 1) * StrLen;
|
110
|
-
ASSERT_STREQ(s2, s3);
|
111
|
-
|
112
|
-
// modify the second string, ensure the modification shows up on
|
113
|
-
// string 3 (would fail if the two miniheaps weren't meshed)
|
114
|
-
s2[0] = 'b';
|
115
|
-
ASSERT_EQ(s3[0], 'b');
|
116
|
-
|
117
|
-
ASSERT_EQ(mh1->meshCount(), 2ULL);
|
118
|
-
|
119
|
-
// now free the objects by going through the global heap -- it
|
120
|
-
// should redirect both objects to the same miniheap
|
121
|
-
gheap.free(s1);
|
122
|
-
ASSERT_TRUE(!mh1->isEmpty());
|
123
|
-
gheap.free(s2);
|
124
|
-
ASSERT_TRUE(mh1->isEmpty()); // safe because mh1 isn't "done"
|
125
|
-
|
126
|
-
note("ABOUT TO FREE");
|
127
|
-
gheap.freeMiniheap(mh1);
|
128
|
-
note("DONE FREE");
|
129
|
-
|
130
|
-
note("ABOUT TO SCAVENGE");
|
131
|
-
gheap.scavenge(true);
|
132
|
-
note("DONE SCAVENGE");
|
133
|
-
|
134
|
-
ASSERT_EQ(gheap.getAllocatedMiniheapCount(), 0UL);
|
135
|
-
}
|
136
|
-
|
137
|
-
TEST(MeshTest, TryMesh) {
|
138
|
-
meshTest(false);
|
139
|
-
}
|
140
|
-
|
141
|
-
TEST(MeshTest, TryMeshInverse) {
|
142
|
-
meshTest(true);
|
143
|
-
}
|
@@ -1,22 +0,0 @@
|
|
1
|
-
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
2
|
-
// Copyright 2017 University of Massachusetts, Amherst
|
3
|
-
|
4
|
-
#include <stdalign.h>
|
5
|
-
#include <cstdint>
|
6
|
-
#include <cstdlib>
|
7
|
-
|
8
|
-
#include "gtest/gtest.h"
|
9
|
-
|
10
|
-
#include "rng/mwc.h"
|
11
|
-
|
12
|
-
using namespace mesh;
|
13
|
-
|
14
|
-
TEST(RNG, MWCRange) {
|
15
|
-
MWC mwc{internal::seed(), internal::seed()};
|
16
|
-
for (size_t i = 0; i < 1000; i++) {
|
17
|
-
size_t n = mwc.inRange(0, 1);
|
18
|
-
if (n != 0 && n != 1) {
|
19
|
-
ASSERT_TRUE(false);
|
20
|
-
}
|
21
|
-
}
|
22
|
-
}
|
@@ -1,66 +0,0 @@
|
|
1
|
-
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
2
|
-
// Copyright 2017 University of Massachusetts, Amherst
|
3
|
-
|
4
|
-
#include <stdalign.h>
|
5
|
-
#include <cstdint>
|
6
|
-
#include <cstdlib>
|
7
|
-
|
8
|
-
#include "gtest/gtest.h"
|
9
|
-
|
10
|
-
#include "common.h"
|
11
|
-
#include "internal.h"
|
12
|
-
|
13
|
-
using namespace mesh;
|
14
|
-
|
15
|
-
#define roundtrip(n) ASSERT_TRUE(n == SizeMap::ByteSizeForClass(SizeMap::SizeClass(n)))
|
16
|
-
#define rt_debug(n) \
|
17
|
-
debug("%d c2s: %zu s2c: %d", n, SizeMap::ByteSizeForClass(SizeMap::SizeClass(n)), SizeMap::SizeClass(n))
|
18
|
-
|
19
|
-
#define pow2Roundtrip(n) ASSERT_TRUE(n == powerOfTwo::ByteSizeForClass(powerOfTwo::ClassForByteSize(n)))
|
20
|
-
|
21
|
-
TEST(SizeClass, MinObjectSize) {
|
22
|
-
ASSERT_EQ(alignof(max_align_t), kMinObjectSize);
|
23
|
-
|
24
|
-
ASSERT_EQ(kMinObjectSize, 16UL);
|
25
|
-
|
26
|
-
ASSERT_EQ(staticlog(kMinObjectSize), 4);
|
27
|
-
}
|
28
|
-
|
29
|
-
TEST(SizeClass, SmallClasses) {
|
30
|
-
roundtrip(16);
|
31
|
-
// rt_debug(16);
|
32
|
-
|
33
|
-
// ASSERT_TRUE(size2Class(8) >= 0);
|
34
|
-
// roundtrip(8);
|
35
|
-
// rt_debug(8);
|
36
|
-
|
37
|
-
roundtrip(32);
|
38
|
-
}
|
39
|
-
|
40
|
-
TEST(SizeClass, PowerOfTwo) {
|
41
|
-
ASSERT_TRUE(powerOfTwo::kMinObjectSize == 8);
|
42
|
-
ASSERT_TRUE(powerOfTwo::ClassForByteSize(8) >= 0);
|
43
|
-
|
44
|
-
pow2Roundtrip(8);
|
45
|
-
pow2Roundtrip(16);
|
46
|
-
pow2Roundtrip(32);
|
47
|
-
}
|
48
|
-
|
49
|
-
TEST(SizeClass, Reciprocal) {
|
50
|
-
for (size_t i = 0; i < kClassSizesMax; i++) {
|
51
|
-
volatile const size_t objectSize = SizeMap::class_to_size(i);
|
52
|
-
// volatile to avoid the compiler compiling it away
|
53
|
-
volatile const float recip = 1.0 / (float)objectSize;
|
54
|
-
|
55
|
-
for (size_t j = 0; j <= kPageSize; j += 8) {
|
56
|
-
// we depend on this floating point calcuation always being
|
57
|
-
// equivalent to the integer division operation
|
58
|
-
volatile const size_t off = j * recip;
|
59
|
-
volatile const size_t off2 = j / objectSize;
|
60
|
-
ASSERT_TRUE(off == off2);
|
61
|
-
}
|
62
|
-
|
63
|
-
const size_t newObjectSize = __builtin_roundf(1 / recip);
|
64
|
-
ASSERT_TRUE(newObjectSize == objectSize);
|
65
|
-
}
|
66
|
-
}
|
@@ -1,285 +0,0 @@
|
|
1
|
-
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
2
|
-
// Copyright 2017 University of Massachusetts, Amherst
|
3
|
-
|
4
|
-
#include <sched.h>
|
5
|
-
#include <stdint.h>
|
6
|
-
#include <stdlib.h>
|
7
|
-
|
8
|
-
#include <atomic>
|
9
|
-
#include <mutex>
|
10
|
-
#include <thread>
|
11
|
-
|
12
|
-
#include "gtest/gtest.h"
|
13
|
-
|
14
|
-
#include "internal.h"
|
15
|
-
#include "meshing.h"
|
16
|
-
#include "runtime.h"
|
17
|
-
#include "shuffle_vector.h"
|
18
|
-
|
19
|
-
using namespace std;
|
20
|
-
using namespace mesh;
|
21
|
-
|
22
|
-
static constexpr uint32_t StrLen = 128;
|
23
|
-
static constexpr uint32_t ObjCount = 32;
|
24
|
-
|
25
|
-
static char *s1;
|
26
|
-
static char *s2;
|
27
|
-
static char *s3;
|
28
|
-
|
29
|
-
static atomic<int> ShouldExit1;
|
30
|
-
static atomic<int> ShouldContinueTest1;
|
31
|
-
static atomic<int> ShouldExit2;
|
32
|
-
static atomic<int> ShouldContinueTest2;
|
33
|
-
|
34
|
-
#ifdef __APPLE__
|
35
|
-
#define PTHREAD_CREATE_THROW
|
36
|
-
#else
|
37
|
-
#define PTHREAD_CREATE_THROW throw()
|
38
|
-
#endif
|
39
|
-
|
40
|
-
// we need to wrap pthread_create so that we can safely implement a
|
41
|
-
// stop-the-world quiescent period for the copy/mremap phase of
|
42
|
-
// meshing -- copied from libmesh.cc
|
43
|
-
extern "C" int pthread_create(pthread_t *thread, const pthread_attr_t *attr, mesh::PthreadFn startRoutine,
|
44
|
-
void *arg) PTHREAD_CREATE_THROW;
|
45
|
-
|
46
|
-
static void writerThread1() {
|
47
|
-
ShouldContinueTest1 = 1;
|
48
|
-
|
49
|
-
for (size_t i = 1; i < numeric_limits<uint64_t>::max(); i++) {
|
50
|
-
if (i % 1000000 == 0 && ShouldExit1)
|
51
|
-
return;
|
52
|
-
|
53
|
-
s1[0] = 'A';
|
54
|
-
s2[0] = 'B';
|
55
|
-
}
|
56
|
-
|
57
|
-
debug("loop ended before ShouldExit\n");
|
58
|
-
}
|
59
|
-
|
60
|
-
static void writerThread2() {
|
61
|
-
ShouldContinueTest2 = 1;
|
62
|
-
|
63
|
-
for (size_t i = 1; i < numeric_limits<uint64_t>::max(); i++) {
|
64
|
-
if (i % 1000000 == 0 && ShouldExit2)
|
65
|
-
return;
|
66
|
-
|
67
|
-
s1[0] = 'A';
|
68
|
-
s3[0] = 'Z';
|
69
|
-
}
|
70
|
-
|
71
|
-
debug("loop ended before ShouldExit\n");
|
72
|
-
}
|
73
|
-
|
74
|
-
// shows up in strace logs, but otherwise does nothing
|
75
|
-
static inline void note(const char *note) {
|
76
|
-
int _ __attribute__((unused)) = write(-1, note, strlen(note));
|
77
|
-
}
|
78
|
-
|
79
|
-
static void meshTestConcurrentWrite(bool invert1, bool invert2) {
|
80
|
-
const auto tid = gettid();
|
81
|
-
GlobalHeap &gheap = runtime().heap();
|
82
|
-
|
83
|
-
// disable automatic meshing for this test
|
84
|
-
gheap.setMeshPeriodMs(kZeroMs);
|
85
|
-
|
86
|
-
ASSERT_EQ(gheap.getAllocatedMiniheapCount(), 0UL);
|
87
|
-
|
88
|
-
FixedArray<MiniHeap, 1> array{};
|
89
|
-
|
90
|
-
// allocate three miniheaps for the same object size from our global heap
|
91
|
-
gheap.allocSmallMiniheaps(SizeMap::SizeClass(StrLen), StrLen, array, tid);
|
92
|
-
MiniHeap *mh1 = array[0];
|
93
|
-
array.clear();
|
94
|
-
|
95
|
-
gheap.allocSmallMiniheaps(SizeMap::SizeClass(StrLen), StrLen, array, tid);
|
96
|
-
MiniHeap *mh2 = array[0];
|
97
|
-
array.clear();
|
98
|
-
|
99
|
-
gheap.allocSmallMiniheaps(SizeMap::SizeClass(StrLen), StrLen, array, tid);
|
100
|
-
MiniHeap *mh3 = array[0];
|
101
|
-
array.clear();
|
102
|
-
|
103
|
-
const auto sizeClass = mh1->sizeClass();
|
104
|
-
ASSERT_EQ(SizeMap::SizeClass(StrLen), sizeClass);
|
105
|
-
|
106
|
-
ASSERT_TRUE(mh1->isAttached());
|
107
|
-
ASSERT_TRUE(mh2->isAttached());
|
108
|
-
ASSERT_TRUE(mh3->isAttached());
|
109
|
-
|
110
|
-
ASSERT_EQ(gheap.getAllocatedMiniheapCount(), 3UL);
|
111
|
-
|
112
|
-
// sanity checks
|
113
|
-
ASSERT_TRUE(mh1 != mh2);
|
114
|
-
ASSERT_TRUE(mh2 != mh3);
|
115
|
-
ASSERT_EQ(mh1->maxCount(), mh2->maxCount());
|
116
|
-
ASSERT_EQ(mh2->maxCount(), mh3->maxCount());
|
117
|
-
ASSERT_EQ(mh1->maxCount(), ObjCount);
|
118
|
-
|
119
|
-
// allocate two c strings, one from each miniheap at different offsets
|
120
|
-
s1 = reinterpret_cast<char *>(mh1->mallocAt(gheap.arenaBegin(), 0));
|
121
|
-
s2 = reinterpret_cast<char *>(mh2->mallocAt(gheap.arenaBegin(), ObjCount - 1));
|
122
|
-
s3 = reinterpret_cast<char *>(mh3->mallocAt(gheap.arenaBegin(), 3));
|
123
|
-
|
124
|
-
ASSERT_TRUE(s1 != nullptr);
|
125
|
-
ASSERT_TRUE(s2 != nullptr);
|
126
|
-
ASSERT_TRUE(s3 != nullptr);
|
127
|
-
|
128
|
-
{
|
129
|
-
const auto f1 = reinterpret_cast<char *>(mh1->mallocAt(gheap.arenaBegin(), 2));
|
130
|
-
const auto f2 = reinterpret_cast<char *>(mh2->mallocAt(gheap.arenaBegin(), 2));
|
131
|
-
const auto f3 = reinterpret_cast<char *>(mh3->mallocAt(gheap.arenaBegin(), 2));
|
132
|
-
|
133
|
-
gheap.releaseMiniheapLocked(mh1, mh1->sizeClass());
|
134
|
-
gheap.releaseMiniheapLocked(mh2, mh1->sizeClass());
|
135
|
-
gheap.releaseMiniheapLocked(mh3, mh1->sizeClass());
|
136
|
-
|
137
|
-
gheap.free(f1);
|
138
|
-
gheap.free(f2);
|
139
|
-
gheap.free(f3);
|
140
|
-
}
|
141
|
-
|
142
|
-
ASSERT_TRUE(!mh1->isAttached());
|
143
|
-
ASSERT_TRUE(!mh2->isAttached());
|
144
|
-
ASSERT_TRUE(!mh3->isAttached());
|
145
|
-
|
146
|
-
// fill in the strings, set the trailing null byte
|
147
|
-
memset(s1, 'A', StrLen);
|
148
|
-
memset(s2, 'B', StrLen);
|
149
|
-
memset(s3, 'Z', StrLen);
|
150
|
-
s1[StrLen - 1] = 0;
|
151
|
-
s2[StrLen - 1] = 0;
|
152
|
-
s3[StrLen - 1] = 0;
|
153
|
-
|
154
|
-
// copy these strings so we can check the contents after meshing
|
155
|
-
char *v1 = strdup(s1);
|
156
|
-
char *v2 = strdup(s2);
|
157
|
-
char *v3 = strdup(s3);
|
158
|
-
ASSERT_STREQ(s1, v1);
|
159
|
-
ASSERT_STREQ(s2, v2);
|
160
|
-
ASSERT_STREQ(s3, v3);
|
161
|
-
|
162
|
-
ASSERT_EQ(mh1->inUseCount(), 1UL);
|
163
|
-
ASSERT_EQ(mh2->inUseCount(), 1UL);
|
164
|
-
ASSERT_EQ(mh3->inUseCount(), 1UL);
|
165
|
-
|
166
|
-
if (invert1) {
|
167
|
-
MiniHeap *tmp = mh1;
|
168
|
-
mh1 = mh2;
|
169
|
-
mh2 = tmp;
|
170
|
-
}
|
171
|
-
|
172
|
-
thread writer1(writerThread1);
|
173
|
-
thread writer2(writerThread2);
|
174
|
-
|
175
|
-
while (ShouldContinueTest1 != 1)
|
176
|
-
sched_yield();
|
177
|
-
while (ShouldContinueTest2 != 1)
|
178
|
-
sched_yield();
|
179
|
-
|
180
|
-
const auto bitmap1 = mh1->bitmap().bits();
|
181
|
-
const auto bitmap2 = mh2->bitmap().bits();
|
182
|
-
const auto bitmap3 = mh3->bitmap().bits();
|
183
|
-
const auto len = mh1->bitmap().byteCount();
|
184
|
-
ASSERT_EQ(len, mh2->bitmap().byteCount());
|
185
|
-
ASSERT_EQ(len, mh3->bitmap().byteCount());
|
186
|
-
|
187
|
-
ASSERT_TRUE(mh1->isMeshingCandidate());
|
188
|
-
ASSERT_TRUE(mh2->isMeshingCandidate());
|
189
|
-
ASSERT_TRUE(mh3->isMeshingCandidate());
|
190
|
-
|
191
|
-
// we have a clique
|
192
|
-
ASSERT_TRUE(mesh::bitmapsMeshable(bitmap1, bitmap2, len));
|
193
|
-
ASSERT_TRUE(mesh::bitmapsMeshable(bitmap2, bitmap3, len));
|
194
|
-
ASSERT_TRUE(mesh::bitmapsMeshable(bitmap1, bitmap3, len));
|
195
|
-
|
196
|
-
{
|
197
|
-
const internal::vector<MiniHeap *> candidates = gheap.meshingCandidatesLocked(mh1->sizeClass());
|
198
|
-
ASSERT_EQ(candidates.size(), 3ULL);
|
199
|
-
ASSERT_TRUE(std::find(candidates.begin(), candidates.end(), mh1) != candidates.end());
|
200
|
-
ASSERT_TRUE(std::find(candidates.begin(), candidates.end(), mh2) != candidates.end());
|
201
|
-
ASSERT_TRUE(std::find(candidates.begin(), candidates.end(), mh3) != candidates.end());
|
202
|
-
}
|
203
|
-
|
204
|
-
note("ABOUT TO MESH");
|
205
|
-
if (!invert2) {
|
206
|
-
gheap.meshLocked(mh1, mh2);
|
207
|
-
gheap.meshLocked(mh1, mh3);
|
208
|
-
} else {
|
209
|
-
gheap.meshLocked(mh2, mh3);
|
210
|
-
gheap.meshLocked(mh1, mh2);
|
211
|
-
}
|
212
|
-
note("DONE MESHING");
|
213
|
-
|
214
|
-
// ensure the count of set bits looks right
|
215
|
-
ASSERT_EQ(mh1->inUseCount(), 3UL);
|
216
|
-
|
217
|
-
// check that our two allocated objects still look right
|
218
|
-
ASSERT_STREQ(s1, v1);
|
219
|
-
ASSERT_STREQ(s2, v2);
|
220
|
-
ASSERT_STREQ(s3, v3);
|
221
|
-
|
222
|
-
// get an aliased pointer to the second string by pointer arithmetic
|
223
|
-
// on the first string
|
224
|
-
char *t2 = s1 + (ObjCount - 1) * StrLen;
|
225
|
-
ASSERT_STREQ(s2, t2);
|
226
|
-
char *t3 = s1 + (3) * StrLen;
|
227
|
-
ASSERT_STREQ(s3, t3);
|
228
|
-
|
229
|
-
ShouldExit1 = 1;
|
230
|
-
ShouldExit2 = 1;
|
231
|
-
writer1.join();
|
232
|
-
writer2.join();
|
233
|
-
|
234
|
-
// modify the second string, ensure the modification shows up on
|
235
|
-
// string 3 (would fail if the two miniheaps weren't meshed)
|
236
|
-
s2[0] = 'b';
|
237
|
-
ASSERT_EQ(t2[0], 'b');
|
238
|
-
|
239
|
-
s3[0] = 'b';
|
240
|
-
ASSERT_EQ(t3[0], 'b');
|
241
|
-
|
242
|
-
ASSERT_EQ(mh1->getOff(gheap.arenaBegin(), s1), 0);
|
243
|
-
ASSERT_EQ(mh1->getOff(gheap.arenaBegin(), s2), ObjCount - 1);
|
244
|
-
ASSERT_EQ(mh1->getOff(gheap.arenaBegin(), s3), 3);
|
245
|
-
|
246
|
-
{
|
247
|
-
const internal::vector<MiniHeap *> candidates = gheap.meshingCandidatesLocked(mh1->sizeClass());
|
248
|
-
ASSERT_EQ(candidates.size(), 1ULL);
|
249
|
-
ASSERT_EQ(candidates[0], mh1);
|
250
|
-
}
|
251
|
-
|
252
|
-
// we need to attach the miniheap, otherwise
|
253
|
-
ASSERT_TRUE(!mh1->isAttached());
|
254
|
-
mh1->setAttached(gettid(), gheap.freelistFor(mh1->freelistId(), sizeClass));
|
255
|
-
ASSERT_TRUE(mh1->isAttached());
|
256
|
-
|
257
|
-
// now free the objects by going through the global heap -- it
|
258
|
-
// should redirect both objects to the same miniheap
|
259
|
-
gheap.free(s1);
|
260
|
-
ASSERT_TRUE(!mh1->isEmpty());
|
261
|
-
gheap.free(s2);
|
262
|
-
ASSERT_TRUE(!mh1->isEmpty());
|
263
|
-
gheap.free(s3);
|
264
|
-
ASSERT_TRUE(mh1->isEmpty());
|
265
|
-
|
266
|
-
note("ABOUT TO FREE");
|
267
|
-
gheap.freeMiniheap(mh1);
|
268
|
-
note("DONE FREE");
|
269
|
-
|
270
|
-
note("ABOUT TO SCAVENGE");
|
271
|
-
gheap.scavenge(true);
|
272
|
-
note("DONE SCAVENGE");
|
273
|
-
|
274
|
-
ASSERT_EQ(gheap.getAllocatedMiniheapCount(), 0UL);
|
275
|
-
}
|
276
|
-
|
277
|
-
TEST(TripleMeshTest, MeshAll) {
|
278
|
-
if (!kMeshingEnabled) {
|
279
|
-
GTEST_SKIP();
|
280
|
-
}
|
281
|
-
meshTestConcurrentWrite(false, false);
|
282
|
-
meshTestConcurrentWrite(false, true);
|
283
|
-
meshTestConcurrentWrite(true, false);
|
284
|
-
meshTestConcurrentWrite(true, true);
|
285
|
-
}
|