1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/ecma_string.h"
17#include "ecmascript/ecma_vm.h"
18#include "ecmascript/js_hclass.h"
19#include "ecmascript/js_object-inl.h"
20#include "ecmascript/js_thread.h"
21
22#include "ecmascript/mem/mem_common.h"
23#include "ecmascript/mem/heap.h"
24#include "ecmascript/mem/space.h"
25#include "ecmascript/object_factory.h"
26#include "ecmascript/tagged_array-inl.h"
27#include "ecmascript/tests/test_helper.h"
28
29using namespace panda::ecmascript;
30using namespace panda::ecmascript::base;
31
32namespace panda::test {
33class MemControllerTest : public BaseTestWithScope<false> {
34};
35
36HWTEST_F_L0(MemControllerTest, AllocationVerify)
37{
38#ifdef NDEBUG
39    auto ecmaVm = thread->GetEcmaVM();
40    auto heap = const_cast<Heap *>(ecmaVm->GetHeap());
41    auto objectFactory = ecmaVm->GetFactory();
42    auto memController = heap->GetMemController();
43
44    heap->CollectGarbage(TriggerGCType::FULL_GC);
45
46    for (int i = 0; i < 1024; i++) {
47        // old space object
48        [[maybe_unused]] auto oldArray = objectFactory->NewTaggedArray(128, JSTaggedValue::Undefined(),
49                                                                       MemSpaceType::OLD_SPACE);
50    }
51    sleep(5);
52    heap->CollectGarbage(TriggerGCType::FULL_GC);
53    double mutatorSpeed1 = memController->GetCurrentOldSpaceAllocationThroughputPerMS(0);
54    for (int i = 0; i < 1024; i++) {
55        // old space object
56        [[maybe_unused]] auto oldArray = objectFactory->NewTaggedArray(128, JSTaggedValue::Undefined(),
57                                                                       MemSpaceType::OLD_SPACE);
58    }
59    sleep(10);
60
61    heap->CollectGarbage(TriggerGCType::FULL_GC);
62    double mutatorSpeed2 = memController->GetCurrentOldSpaceAllocationThroughputPerMS(0);
63    ASSERT_TRUE(mutatorSpeed2 < mutatorSpeed1);
64#endif
65}
66
67HWTEST_F_L0(MemControllerTest, VerifyMutatorSpeed)
68{
69#ifdef NDEBUG
70    auto ecmaVm = thread->GetEcmaVM();
71    auto heap = const_cast<Heap *>(ecmaVm->GetHeap());
72    auto objectFactory = ecmaVm->GetFactory();
73    auto memController = heap->GetMemController();
74
75    heap->CollectGarbage(TriggerGCType::YOUNG_GC);
76    size_t oldSpaceAllocatedSizeBefore = memController->GetOldSpaceAllocAccumulatedSize();
77    size_t nonMovableSpaceAllocatedSizeBefore = memController->GetNonMovableSpaceAllocAccumulatedSize();
78    double allocDurationBefore = memController->GetAllocTimeMs();
79    sleep(1);
80
81    // new space object
82    [[maybe_unused]] auto newArray =
83        objectFactory->NewTaggedArray(2, JSTaggedValue::Undefined(), MemSpaceType::SEMI_SPACE);
84    // old space object
85    auto oldArray = objectFactory->NewTaggedArray(2, JSTaggedValue::Undefined(), MemSpaceType::OLD_SPACE);
86    // non movable object
87    auto nonMovableArray = objectFactory->NewTaggedArray(2, JSTaggedValue::Undefined(), MemSpaceType::NON_MOVABLE);
88    // huge space object
89    static constexpr size_t SIZE = 1_MB;
90    auto hugeArray = objectFactory->NewTaggedArray(SIZE);
91
92    auto newSpace = heap->GetNewSpace();
93    size_t newSpaceAllocBytesSinceGC = newSpace->GetAllocatedSizeSinceGC(newSpace->GetTop());
94    ASSERT_EQ(newSpaceAllocBytesSinceGC, TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), 2));
95    heap->CollectGarbage(TriggerGCType::YOUNG_GC);
96    newSpace = heap->GetNewSpace();
97    ASSERT_EQ(newSpace->GetAllocatedSizeSinceGC(newSpace->GetTop()), static_cast<size_t>(0));
98
99    size_t oldSpaceAllocatedSizeAfter = memController->GetOldSpaceAllocAccumulatedSize();
100    size_t nonMovableSpaceAllocatedSizeAfter = memController->GetNonMovableSpaceAllocAccumulatedSize();
101    double allocDurationAfter = memController->GetAllocTimeMs();
102
103    size_t hugeObjectAllocSizeInLastGC = memController->GetHugeObjectAllocSizeSinceGC();
104
105    ASSERT_TRUE(allocDurationAfter - allocDurationBefore > 1000);
106    ASSERT_TRUE(oldSpaceAllocatedSizeAfter - oldSpaceAllocatedSizeBefore
107                == oldArray->ComputeSize(JSTaggedValue::TaggedTypeSize(), 2));
108    ASSERT_TRUE(nonMovableSpaceAllocatedSizeAfter - nonMovableSpaceAllocatedSizeBefore
109                == nonMovableArray->ComputeSize(JSTaggedValue::TaggedTypeSize(), 2));
110    // The allocated size of huge object must be larger than the object size.
111    ASSERT_TRUE(hugeObjectAllocSizeInLastGC > hugeArray->ComputeSize(JSTaggedValue::TaggedTypeSize(), SIZE));
112#endif
113}
114
115HWTEST_F_L0(MemControllerTest, CalculateMarkCompactSpeedPerMSTest)
116{
117#ifdef NDEBUG
118    auto ecmaVm = thread->GetEcmaVM();
119    auto heap = const_cast<Heap *>(ecmaVm->GetHeap());
120    auto memController = heap->GetMemController();
121    auto compactSpeed = memController->CalculateMarkCompactSpeedPerMS();
122    EXPECT_TRUE(compactSpeed == 0);
123#endif
124}
125
126HWTEST_F_L0(MemControllerTest, StartCalculationBeforeGC)
127{
128    auto ecmaVm = thread->GetEcmaVM();
129    auto heap = const_cast<Heap *>(ecmaVm->GetHeap());
130    auto memController = heap->GetMemController();
131
132    double allocTimeMsBefore = memController->GetAllocTimeMs();
133    size_t oldSpaceSizeBefore = memController->GetOldSpaceAllocAccumulatedSize();
134    size_t nonMovableSpaceSizeBefore = memController->GetNonMovableSpaceAllocAccumulatedSize();
135    size_t codeSpaceSizeBefore = memController->GetCodeSpaceAllocAccumulatedSize();
136
137    sleep(1);
138    memController->StartCalculationBeforeGC();
139    memController->CheckLowAllocationUsageState();
140
141    double allocTimeMsAfter = memController->GetAllocTimeMs();
142    size_t oldSpaceSizeAfter = memController->GetOldSpaceAllocAccumulatedSize();
143    size_t nonMovableSpaceSizeAfter = memController->GetNonMovableSpaceAllocAccumulatedSize();
144    size_t codeSpaceSizeAfter = memController->GetCodeSpaceAllocAccumulatedSize();
145    double allocDurationSinceGc = memController->GetAllocDurationSinceGc();
146
147    EXPECT_TRUE(allocTimeMsAfter - allocTimeMsBefore > 1000);
148    EXPECT_TRUE(oldSpaceSizeAfter > oldSpaceSizeBefore);
149    EXPECT_TRUE(nonMovableSpaceSizeAfter > nonMovableSpaceSizeBefore);
150    EXPECT_TRUE(codeSpaceSizeAfter == codeSpaceSizeBefore);
151    EXPECT_TRUE(allocDurationSinceGc == allocTimeMsAfter - allocTimeMsBefore);
152}
153
154HWTEST_F_L0(MemControllerTest, StopCalculationAfterGC)
155{
156    auto ecmaVm = thread->GetEcmaVM();
157    auto heap = const_cast<Heap *>(ecmaVm->GetHeap());
158    auto objectFactory = ecmaVm->GetFactory();
159    auto memController = heap->GetMemController();
160    heap->CollectGarbage(TriggerGCType::FULL_GC);
161
162    [[maybe_unused]] auto newArray =
163        objectFactory->NewTaggedArray(2, JSTaggedValue::Undefined(), MemSpaceType::SEMI_SPACE);
164    [[maybe_unused]] auto oldArray =
165        objectFactory->NewTaggedArray(2, JSTaggedValue::Undefined(), MemSpaceType::OLD_SPACE);
166    [[maybe_unused]] auto nonMovableArray =
167        objectFactory->NewTaggedArray(2, JSTaggedValue::Undefined(), MemSpaceType::NON_MOVABLE);
168    static constexpr size_t SIZE = 1_MB;
169    [[maybe_unused]] auto hugeArray = objectFactory->NewTaggedArray(SIZE);
170
171    heap->CollectGarbage(TriggerGCType::YOUNG_GC);
172
173    double allocDurationSinceGc = memController->GetAllocDurationSinceGc();
174    size_t codeSpaceAllocSizeSinceGC = memController->GetCodeSpaceAllocAccumulatedSize();
175    EXPECT_EQ(allocDurationSinceGc, static_cast<double>(0.0));
176    EXPECT_EQ(codeSpaceAllocSizeSinceGC, static_cast<size_t>(0));
177    size_t hugeObjectSize = heap->GetHugeObjectSpace()->GetHeapObjectSize();
178    size_t hugeAllocSizeSinceGC = memController->GetHugeObjectAllocSizeSinceGC();
179    EXPECT_EQ(hugeAllocSizeSinceGC, hugeObjectSize);
180    double markCompactSpeed = memController->CalculateMarkCompactSpeedPerMS();
181    EXPECT_GE(markCompactSpeed, 0);
182}
183}  // namespace panda::test
184