Misc changes for GC in new MM (#4699)
This commit is contained in:
committed by
Vasily Levchenko
parent
f7af8bc763
commit
97262c273f
@@ -2396,6 +2396,11 @@ task hash_map0(type: KonanLocalTest) {
|
|||||||
source = "runtime/collections/hash_map0.kt"
|
source = "runtime/collections/hash_map0.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task hash_map1(type: KonanLocalTest) {
|
||||||
|
goldValue = "OK\n"
|
||||||
|
source = "runtime/collections/hash_map1.kt"
|
||||||
|
}
|
||||||
|
|
||||||
task hash_set0(type: KonanLocalTest) {
|
task hash_set0(type: KonanLocalTest) {
|
||||||
goldValue = "OK\n"
|
goldValue = "OK\n"
|
||||||
source = "runtime/collections/hash_set0.kt"
|
source = "runtime/collections/hash_set0.kt"
|
||||||
|
|||||||
@@ -94,58 +94,6 @@ fun testBasic() {
|
|||||||
assertEquals(0, m.size)
|
assertEquals(0, m.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testRehashAndCompact() {
|
|
||||||
val m = HashMap<String, String>()
|
|
||||||
for (repeat in 1..10) {
|
|
||||||
val n = when (repeat) {
|
|
||||||
1 -> 1000
|
|
||||||
2 -> 10000
|
|
||||||
3 -> 10
|
|
||||||
else -> 100000
|
|
||||||
}
|
|
||||||
for (i in 1..n) {
|
|
||||||
assertFalse(m.containsKey(i.toString()))
|
|
||||||
assertEquals(null, m.put(i.toString(), "val$i"))
|
|
||||||
assertTrue(m.containsKey(i.toString()))
|
|
||||||
assertEquals(i, m.size)
|
|
||||||
}
|
|
||||||
for (i in 1..n) {
|
|
||||||
assertTrue(m.containsKey(i.toString()))
|
|
||||||
}
|
|
||||||
for (i in 1..n) {
|
|
||||||
assertEquals("val$i", m.remove(i.toString()))
|
|
||||||
assertFalse(m.containsKey(i.toString()))
|
|
||||||
assertEquals(n - i, m.size)
|
|
||||||
}
|
|
||||||
assertTrue(m.isEmpty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun testClear() {
|
|
||||||
val m = HashMap<String, String>()
|
|
||||||
for (repeat in 1..10) {
|
|
||||||
val n = when (repeat) {
|
|
||||||
1 -> 1000
|
|
||||||
2 -> 10000
|
|
||||||
3 -> 10
|
|
||||||
else -> 100000
|
|
||||||
}
|
|
||||||
for (i in 1..n) {
|
|
||||||
assertFalse(m.containsKey(i.toString()))
|
|
||||||
assertEquals(null, m.put(i.toString(), "val$i"))
|
|
||||||
assertTrue(m.containsKey(i.toString()))
|
|
||||||
assertEquals(i, m.size)
|
|
||||||
}
|
|
||||||
for (i in 1..n) {
|
|
||||||
assertTrue(m.containsKey(i.toString()))
|
|
||||||
}
|
|
||||||
m.clear()
|
|
||||||
assertEquals(0, m.size)
|
|
||||||
for (i in 1..n) {
|
|
||||||
assertFalse(m.containsKey(i.toString()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fun testEquals() {
|
fun testEquals() {
|
||||||
val expected = mapOf("a" to "1", "b" to "2", "c" to "3")
|
val expected = mapOf("a" to "1", "b" to "2", "c" to "3")
|
||||||
val m = HashMap(expected)
|
val m = HashMap(expected)
|
||||||
@@ -257,8 +205,6 @@ fun testEntriesIteratorSet() {
|
|||||||
|
|
||||||
@Test fun runTest() {
|
@Test fun runTest() {
|
||||||
testBasic()
|
testBasic()
|
||||||
testRehashAndCompact()
|
|
||||||
testClear()
|
|
||||||
testEquals()
|
testEquals()
|
||||||
testHashCode()
|
testHashCode()
|
||||||
testToString()
|
testToString()
|
||||||
@@ -272,4 +218,4 @@ fun testEntriesIteratorSet() {
|
|||||||
testEntriesIteratorSet()
|
testEntriesIteratorSet()
|
||||||
//testDegenerateKeys()
|
//testDegenerateKeys()
|
||||||
println("OK")
|
println("OK")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package runtime.collections.hash_map1
|
||||||
|
|
||||||
|
import kotlin.native.MemoryModel
|
||||||
|
import kotlin.native.Platform
|
||||||
|
import kotlin.native.internal.GC
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
fun assertTrue(cond: Boolean) {
|
||||||
|
if (!cond)
|
||||||
|
println("FAIL")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assertFalse(cond: Boolean) {
|
||||||
|
if (cond)
|
||||||
|
println("FAIL")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assertEquals(value1: Any?, value2: Any?) {
|
||||||
|
if (value1 != value2)
|
||||||
|
println("FAIL")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assertNotEquals(value1: Any?, value2: Any?) {
|
||||||
|
if (value1 == value2)
|
||||||
|
println("FAIL")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assertEquals(value1: Int, value2: Int) {
|
||||||
|
if (value1 != value2)
|
||||||
|
println("FAIL")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testRehashAndCompact() {
|
||||||
|
val m = HashMap<String, String>()
|
||||||
|
for (repeat in 1..10) {
|
||||||
|
val n = when (repeat) {
|
||||||
|
1 -> 1000
|
||||||
|
2 -> 10000
|
||||||
|
3 -> 10
|
||||||
|
else -> 100000
|
||||||
|
}
|
||||||
|
for (i in 1..n) {
|
||||||
|
assertFalse(m.containsKey(i.toString()))
|
||||||
|
assertEquals(null, m.put(i.toString(), "val$i"))
|
||||||
|
assertTrue(m.containsKey(i.toString()))
|
||||||
|
assertEquals(i, m.size)
|
||||||
|
}
|
||||||
|
for (i in 1..n) {
|
||||||
|
assertTrue(m.containsKey(i.toString()))
|
||||||
|
}
|
||||||
|
for (i in 1..n) {
|
||||||
|
assertEquals("val$i", m.remove(i.toString()))
|
||||||
|
assertFalse(m.containsKey(i.toString()))
|
||||||
|
assertEquals(n - i, m.size)
|
||||||
|
}
|
||||||
|
assertTrue(m.isEmpty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testClear() {
|
||||||
|
val m = HashMap<String, String>()
|
||||||
|
for (repeat in 1..10) {
|
||||||
|
val n = when (repeat) {
|
||||||
|
1 -> 1000
|
||||||
|
2 -> 10000
|
||||||
|
3 -> 10
|
||||||
|
else -> 100000
|
||||||
|
}
|
||||||
|
for (i in 1..n) {
|
||||||
|
assertFalse(m.containsKey(i.toString()))
|
||||||
|
assertEquals(null, m.put(i.toString(), "val$i"))
|
||||||
|
assertTrue(m.containsKey(i.toString()))
|
||||||
|
assertEquals(i, m.size)
|
||||||
|
}
|
||||||
|
for (i in 1..n) {
|
||||||
|
assertTrue(m.containsKey(i.toString()))
|
||||||
|
}
|
||||||
|
m.clear()
|
||||||
|
assertEquals(0, m.size)
|
||||||
|
for (i in 1..n) {
|
||||||
|
assertFalse(m.containsKey(i.toString()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun runTest() {
|
||||||
|
// TODO: Do not manually control this.
|
||||||
|
if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) {
|
||||||
|
GC.threshold = 1000000
|
||||||
|
GC.thresholdAllocations = 1000000
|
||||||
|
}
|
||||||
|
testRehashAndCompact()
|
||||||
|
testClear()
|
||||||
|
println("OK")
|
||||||
|
}
|
||||||
@@ -71,6 +71,11 @@ public:
|
|||||||
owner_.deletionQueue_.splice(owner_.deletionQueue_.end(), deletionQueue_);
|
owner_.deletionQueue_.splice(owner_.deletionQueue_.end(), deletionQueue_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClearForTests() noexcept {
|
||||||
|
queue_.clear();
|
||||||
|
deletionQueue_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MultiSourceQueue& owner_; // weak
|
MultiSourceQueue& owner_; // weak
|
||||||
KStdList<Node> queue_;
|
KStdList<Node> queue_;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
using namespace kotlin;
|
using namespace kotlin;
|
||||||
|
|
||||||
mm::GlobalData::GlobalData() = default;
|
mm::GlobalData::GlobalData() = default;
|
||||||
mm::GlobalData::~GlobalData() = default;
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
mm::GlobalData mm::GlobalData::instance_;
|
mm::GlobalData mm::GlobalData::instance_ [[clang::no_destroy]];
|
||||||
|
|||||||
@@ -29,8 +29,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
GlobalData();
|
GlobalData();
|
||||||
~GlobalData();
|
~GlobalData() = delete;
|
||||||
|
|
||||||
|
// This `GlobalData` is never destroyed.
|
||||||
static GlobalData instance_;
|
static GlobalData instance_;
|
||||||
|
|
||||||
ThreadRegistry threadRegistry_;
|
ThreadRegistry threadRegistry_;
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public:
|
|||||||
// Make sure to clean everything allocated by the tests.
|
// Make sure to clean everything allocated by the tests.
|
||||||
for (auto& threadData : threadDatas_) {
|
for (auto& threadData : threadDatas_) {
|
||||||
threadData->objectFactoryThreadQueue().ClearForTests();
|
threadData->objectFactoryThreadQueue().ClearForTests();
|
||||||
|
threadData->globalsThreadQueue().ClearForTests();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -263,6 +263,48 @@ extern "C" void Kotlin_native_internal_GC_collectCyclic(ObjHeader*) {
|
|||||||
ThrowIllegalArgumentException();
|
ThrowIllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void Kotlin_native_internal_GC_setThreshold(ObjHeader*, int32_t value) {
|
||||||
|
if (value < 0) {
|
||||||
|
ThrowIllegalArgumentException();
|
||||||
|
}
|
||||||
|
mm::GlobalData::Instance().gc().SetThreshold(static_cast<size_t>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int32_t Kotlin_native_internal_GC_getThreshold(ObjHeader*) {
|
||||||
|
auto threshold = mm::GlobalData::Instance().gc().GetThreshold();
|
||||||
|
auto maxValue = std::numeric_limits<int32_t>::max();
|
||||||
|
if (threshold > static_cast<size_t>(maxValue)) {
|
||||||
|
return maxValue;
|
||||||
|
}
|
||||||
|
return static_cast<int32_t>(maxValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void Kotlin_native_internal_GC_setCollectCyclesThreshold(ObjHeader*, int64_t value) {
|
||||||
|
// TODO: Remove when legacy MM is gone.
|
||||||
|
ThrowIllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int64_t Kotlin_native_internal_GC_getCollectCyclesThreshold(ObjHeader*) {
|
||||||
|
// TODO: Remove when legacy MM is gone.
|
||||||
|
ThrowIllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void Kotlin_native_internal_GC_setThresholdAllocations(ObjHeader*, int64_t value) {
|
||||||
|
if (value < 0) {
|
||||||
|
ThrowIllegalArgumentException();
|
||||||
|
}
|
||||||
|
mm::GlobalData::Instance().gc().SetAllocationThresholdBytes(static_cast<size_t>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int64_t Kotlin_native_internal_GC_getThresholdAllocations(ObjHeader*) {
|
||||||
|
auto threshold = mm::GlobalData::Instance().gc().GetAllocationThresholdBytes();
|
||||||
|
auto maxValue = std::numeric_limits<int64_t>::max();
|
||||||
|
if (threshold > static_cast<size_t>(maxValue)) {
|
||||||
|
return maxValue;
|
||||||
|
}
|
||||||
|
return static_cast<int64_t>(maxValue);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" OBJ_GETTER(Kotlin_native_internal_GC_detectCycles, ObjHeader*) {
|
extern "C" OBJ_GETTER(Kotlin_native_internal_GC_detectCycles, ObjHeader*) {
|
||||||
// TODO: Remove when legacy MM is gone.
|
// TODO: Remove when legacy MM is gone.
|
||||||
RETURN_OBJ(nullptr);
|
RETURN_OBJ(nullptr);
|
||||||
|
|||||||
@@ -42,30 +42,6 @@ void Kotlin_native_internal_GC_start(ObjHeader*) {
|
|||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_native_internal_GC_setThreshold(ObjHeader*, int32_t value) {
|
|
||||||
TODO();
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t Kotlin_native_internal_GC_getThreshold(ObjHeader*) {
|
|
||||||
TODO();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Kotlin_native_internal_GC_setCollectCyclesThreshold(ObjHeader*, int64_t value) {
|
|
||||||
TODO();
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t Kotlin_native_internal_GC_getCollectCyclesThreshold(ObjHeader*) {
|
|
||||||
TODO();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Kotlin_native_internal_GC_setThresholdAllocations(ObjHeader*, int64_t value) {
|
|
||||||
TODO();
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t Kotlin_native_internal_GC_getThresholdAllocations(ObjHeader*) {
|
|
||||||
TODO();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Kotlin_native_internal_GC_setTuneThreshold(ObjHeader*, int32_t value) {
|
void Kotlin_native_internal_GC_setTuneThreshold(ObjHeader*, int32_t value) {
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,10 +38,18 @@ public:
|
|||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
NoOpGC() noexcept = default;
|
NoOpGC() noexcept {}
|
||||||
~NoOpGC() = default;
|
~NoOpGC() = default;
|
||||||
|
|
||||||
|
void SetThreshold(size_t value) noexcept { threshold_ = value; }
|
||||||
|
size_t GetThreshold() noexcept { return threshold_; }
|
||||||
|
|
||||||
|
void SetAllocationThresholdBytes(size_t value) noexcept { allocationThresholdBytes_ = value; }
|
||||||
|
size_t GetAllocationThresholdBytes() noexcept { return allocationThresholdBytes_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
size_t threshold_ = 0;
|
||||||
|
size_t allocationThresholdBytes_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mm
|
} // namespace mm
|
||||||
|
|||||||
Reference in New Issue
Block a user