mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2025-04-14 13:50:20 +00:00
325 lines
13 KiB
C++
325 lines
13 KiB
C++
/*
|
|
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "ecmascript/mem/mem_controller.h"
|
|
|
|
#include "ecmascript/mem/concurrent_marker.h"
|
|
#include "ecmascript/mem/parallel_evacuator.h"
|
|
|
|
namespace panda::ecmascript {
|
|
MemController::MemController(Heap *heap) : heap_(heap), allocTimeMs_(GetSystemTimeInMs())
|
|
{
|
|
minAllocLimitGrowingStep_ = heap->GetEcmaVM()->GetEcmaParamConfiguration().GetMinAllocLimitGrowingStep();
|
|
}
|
|
|
|
size_t MemController::CalculateAllocLimit(size_t currentSize, size_t minSize, size_t maxSize, size_t newSpaceCapacity,
|
|
double factor) const
|
|
{
|
|
const uint64_t limit = std::max(static_cast<uint64_t>(currentSize * factor),
|
|
static_cast<uint64_t>(currentSize) + minAllocLimitGrowingStep_) +
|
|
newSpaceCapacity;
|
|
|
|
const uint64_t limitAboveMinSize = std::max<uint64_t>(limit, minSize);
|
|
const uint64_t halfToMaxSize = (static_cast<uint64_t>(currentSize) + maxSize) / 2;
|
|
size_t result = static_cast<size_t>(std::min(limitAboveMinSize, halfToMaxSize));
|
|
result = static_cast<size_t>(std::min(result, maxSize));
|
|
return result;
|
|
}
|
|
|
|
double MemController::CalculateGrowingFactor(double gcSpeed, double mutatorSpeed)
|
|
{
|
|
double maxGrowingFactor = 4.0;
|
|
double halfMaxGrowingFactor = 2.0;
|
|
double minGrowingFactor = 1.3;
|
|
double minimumFactor = 1.1;
|
|
switch (heap_->GetMemGrowingType()) {
|
|
case MemGrowingType::HIGH_THROUGHPUT:
|
|
break;
|
|
case MemGrowingType::CONSERVATIVE:
|
|
minGrowingFactor = minimumFactor;
|
|
maxGrowingFactor = halfMaxGrowingFactor;
|
|
break;
|
|
case MemGrowingType::PRESSURE:
|
|
return minimumFactor;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
static constexpr double targetMutatorUtilization = 0.97;
|
|
if (gcSpeed == 0 || mutatorSpeed == 0) {
|
|
return maxGrowingFactor;
|
|
}
|
|
|
|
const double speedRatio = gcSpeed / mutatorSpeed;
|
|
|
|
const double a = speedRatio * (1 - targetMutatorUtilization);
|
|
const double b = speedRatio * (1 - targetMutatorUtilization) - targetMutatorUtilization;
|
|
|
|
double factor = (a < b * maxGrowingFactor) ? a / b : maxGrowingFactor;
|
|
factor = std::min(maxGrowingFactor, factor);
|
|
factor = std::max(factor, minGrowingFactor);
|
|
OPTIONAL_LOG(heap_->GetEcmaVM(), INFO) << "CalculateGrowingFactor gcSpeed"
|
|
<< gcSpeed << " mutatorSpeed" << mutatorSpeed << " factor" << factor;
|
|
return factor;
|
|
}
|
|
|
|
void MemController::StartCalculationBeforeGC()
|
|
{
|
|
startCounter_++;
|
|
if (startCounter_ != 1) {
|
|
return;
|
|
}
|
|
|
|
auto edenSpace = heap_->GetEdenSpace();
|
|
size_t edenSpaceAllocBytesSinceGC = edenSpace->GetAllocatedSizeSinceGC(edenSpace->GetTop());
|
|
// It's unnecessary to calculate newSpaceAllocAccumulatedSize. newSpaceAllocBytesSinceGC can be calculated directly.
|
|
auto newSpace = heap_->GetNewSpace();
|
|
size_t newSpaceAllocBytesSinceGC = newSpace->GetAllocatedSizeSinceGC(newSpace->GetTop());
|
|
size_t hugeObjectAllocSizeSinceGC = heap_->GetHugeObjectSpace()->GetHeapObjectSize() - hugeObjectAllocSizeSinceGC_;
|
|
size_t oldSpaceAllocAccumulatedSize = heap_->GetOldSpace()->GetTotalAllocatedSize();
|
|
size_t nonMovableSpaceAllocAccumulatedSize = heap_->GetNonMovableSpace()->GetTotalAllocatedSize();
|
|
size_t codeSpaceAllocAccumulatedSize = heap_->GetMachineCodeSpace()->GetTotalAllocatedSize();
|
|
double currentTimeInMs = GetSystemTimeInMs();
|
|
gcStartTime_ = currentTimeInMs;
|
|
size_t oldSpaceAllocSize = oldSpaceAllocAccumulatedSize - oldSpaceAllocAccumulatedSize_;
|
|
size_t nonMovableSpaceAllocSize = nonMovableSpaceAllocAccumulatedSize - nonMovableSpaceAllocAccumulatedSize_;
|
|
size_t codeSpaceAllocSize = codeSpaceAllocAccumulatedSize - codeSpaceAllocAccumulatedSize_;
|
|
|
|
double duration = currentTimeInMs - allocTimeMs_;
|
|
allocTimeMs_ = currentTimeInMs;
|
|
oldSpaceAllocAccumulatedSize_ = oldSpaceAllocAccumulatedSize;
|
|
nonMovableSpaceAllocAccumulatedSize_ = nonMovableSpaceAllocAccumulatedSize;
|
|
codeSpaceAllocAccumulatedSize_ = codeSpaceAllocAccumulatedSize;
|
|
|
|
allocDurationSinceGc_ += duration;
|
|
|
|
edenSpaceAllocSizeSinceGC_ += edenSpaceAllocBytesSinceGC;
|
|
newSpaceAllocSizeSinceGC_ += newSpaceAllocBytesSinceGC;
|
|
oldSpaceAllocSizeSinceGC_ += oldSpaceAllocSize;
|
|
oldSpaceAllocSizeSinceGC_ += hugeObjectAllocSizeSinceGC;
|
|
nonMovableSpaceAllocSizeSinceGC_ += nonMovableSpaceAllocSize;
|
|
codeSpaceAllocSizeSinceGC_ += codeSpaceAllocSize;
|
|
|
|
if (heap_->GetEcmaGCStats()->GetGCReason() != GCReason::IDLE) {
|
|
recordedIdleNewSpaceAllocations_.Push(MakeBytesAndDuration(
|
|
heap_->GetNewSpace()->GetHeapObjectSize() - newSpaceRecordLastTimeSizeIdle_,
|
|
currentTimeInMs - allocTimeMsIdle_));
|
|
recordedIdleOldSpaceAllocations_.Push(MakeBytesAndDuration(
|
|
heap_->GetOldSpace()->GetHeapObjectSize() - oldSpaceRecordLastTimeSizeIdle_,
|
|
currentTimeInMs - allocTimeMsIdle_));
|
|
}
|
|
}
|
|
|
|
void MemController::RecordAllocationForIdle()
|
|
{
|
|
double currentTimeInMs = GetSystemTimeInMs();
|
|
size_t currentNewSpaceObjectSize = heap_->GetNewSpace()->GetHeapObjectSize();
|
|
size_t currentOldSpaceObjectSize = heap_->GetOldSpace()->GetHeapObjectSize();
|
|
double duration = currentTimeInMs - allocTimeMsIdle_;
|
|
allocTimeMsIdle_ = currentTimeInMs;
|
|
if (currentNewSpaceObjectSize < newSpaceRecordLastTimeSizeIdle_ ||
|
|
currentOldSpaceObjectSize < oldSpaceRecordLastTimeSizeIdle_) {
|
|
newSpaceRecordLastTimeSizeIdle_ = currentNewSpaceObjectSize;
|
|
oldSpaceRecordLastTimeSizeIdle_ = currentOldSpaceObjectSize;
|
|
return;
|
|
}
|
|
|
|
size_t newSpaceAllocSizeSinceIdle = currentNewSpaceObjectSize - newSpaceRecordLastTimeSizeIdle_;
|
|
newSpaceRecordLastTimeSizeIdle_ = currentNewSpaceObjectSize;
|
|
size_t oldSpaceAllocSizeSinceIdle = currentOldSpaceObjectSize - oldSpaceRecordLastTimeSizeIdle_;
|
|
oldSpaceRecordLastTimeSizeIdle_ = currentOldSpaceObjectSize;
|
|
recordedIdleNewSpaceAllocations_.Push(MakeBytesAndDuration(newSpaceAllocSizeSinceIdle, duration));
|
|
recordedIdleOldSpaceAllocations_.Push(MakeBytesAndDuration(oldSpaceAllocSizeSinceIdle, duration));
|
|
}
|
|
|
|
bool MemController::CheckLowAllocationUsageState() const
|
|
{
|
|
LOG_GC(DEBUG) << "local CheckLowAllocationUsageState NewSpaceAllocBytesPerMS:" <<
|
|
GetIdleNewSpaceAllocationThroughputPerMS() << ",OldSpaceAllocBytesPerMS:" <<
|
|
GetIdleOldSpaceAllocationThroughputPerMS();
|
|
return GetIdleNewSpaceAllocationThroughputPerMS() < LOW_ALLOCATION_RATE_PER_MS &&
|
|
GetIdleOldSpaceAllocationThroughputPerMS() < LOW_ALLOCATION_RATE_PER_MS;
|
|
}
|
|
|
|
void MemController::UpdateObjectUsageRateAfterGC()
|
|
{
|
|
lastGCObjectUsageRate_ = static_cast<double>(heap_->GetHeapObjectSize()) /
|
|
static_cast<double>(heap_->GetCommittedSize());
|
|
|
|
lastGCOldSpaceObjectUsageRate_ = static_cast<double>(heap_->GetOldSpace()->GetHeapObjectSize()) /
|
|
static_cast<double>(heap_->GetOldSpace()->GetCommittedSize());
|
|
|
|
LOG_GC(DEBUG) << "UpdateObjectUsageRateAfterGC Shared lastGCObjectUsageRate:" << lastGCObjectUsageRate_
|
|
<< ",lastGCOldSpaceObjectUsageRate:" << lastGCOldSpaceObjectUsageRate_;
|
|
}
|
|
|
|
void MemController::StopCalculationAfterGC(TriggerGCType gcType)
|
|
{
|
|
startCounter_--;
|
|
if (startCounter_ != 0) {
|
|
return;
|
|
}
|
|
|
|
gcEndTime_ = GetSystemTimeInMs();
|
|
allocTimeMs_ = gcEndTime_;
|
|
if (allocDurationSinceGc_ > 0) {
|
|
oldSpaceAllocSizeSinceGC_ += heap_->GetEvacuator()->GetPromotedSize();
|
|
recordedEdenSpaceAllocations_.Push(MakeBytesAndDuration(edenSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
|
|
recordedNewSpaceAllocations_.Push(MakeBytesAndDuration(newSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
|
|
recordedOldSpaceAllocations_.Push(MakeBytesAndDuration(oldSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
|
|
recordedNonmovableSpaceAllocations_.Push(
|
|
MakeBytesAndDuration(nonMovableSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
|
|
recordedCodeSpaceAllocations_.Push(MakeBytesAndDuration(codeSpaceAllocSizeSinceGC_, allocDurationSinceGc_));
|
|
}
|
|
allocDurationSinceGc_ = 0.0;
|
|
edenSpaceAllocSizeSinceGC_ = 0;
|
|
newSpaceAllocSizeSinceGC_ = 0;
|
|
oldSpaceAllocSizeSinceGC_ = 0;
|
|
nonMovableSpaceAllocSizeSinceGC_ = 0;
|
|
codeSpaceAllocSizeSinceGC_ = 0;
|
|
|
|
hugeObjectAllocSizeSinceGC_ = heap_->GetHugeObjectSpace()->GetHeapObjectSize();
|
|
|
|
double duration = gcEndTime_ - gcStartTime_;
|
|
switch (gcType) {
|
|
case TriggerGCType::YOUNG_GC:
|
|
case TriggerGCType::OLD_GC: {
|
|
if (heap_->IsConcurrentFullMark()) {
|
|
if (heap_->GetConcurrentMarker()->IsEnabled()) {
|
|
duration += heap_->GetConcurrentMarker()->GetDuration();
|
|
}
|
|
recordedMarkCompacts_.Push(MakeBytesAndDuration(heap_->GetHeapObjectSize(), duration));
|
|
}
|
|
break;
|
|
}
|
|
case TriggerGCType::FULL_GC: {
|
|
recordedMarkCompacts_.Push(MakeBytesAndDuration(heap_->GetHeapObjectSize(), duration));
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (heap_->GetEcmaGCStats()->GetGCReason() != GCReason::IDLE) {
|
|
newSpaceRecordLastTimeSizeIdle_ = heap_->GetNewSpace()->GetHeapObjectSize();
|
|
oldSpaceRecordLastTimeSizeIdle_ = heap_->GetOldSpace()->GetHeapObjectSize();
|
|
allocTimeMsIdle_ = gcEndTime_;
|
|
}
|
|
}
|
|
|
|
void MemController::RecordAfterConcurrentMark(MarkType markType, const ConcurrentMarker *marker)
|
|
{
|
|
double duration = marker->GetDuration();
|
|
if (markType == MarkType::MARK_FULL) {
|
|
recordedConcurrentMarks_.Push(MakeBytesAndDuration(marker->GetHeapObjectSize(), duration));
|
|
} else if (markType == MarkType::MARK_YOUNG) {
|
|
recordedSemiConcurrentMarks_.Push(MakeBytesAndDuration(marker->GetHeapObjectSize(), duration));
|
|
} else if (markType == MarkType::MARK_EDEN) {
|
|
recordedEdenConcurrentMarks_.Push(MakeBytesAndDuration(marker->GetHeapObjectSize(), duration));
|
|
}
|
|
}
|
|
|
|
double MemController::CalculateMarkCompactSpeedPerMS()
|
|
{
|
|
markCompactSpeedCache_ = CalculateAverageSpeed(recordedMarkCompacts_);
|
|
if (markCompactSpeedCache_ > 0) {
|
|
return markCompactSpeedCache_;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
double MemController::CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration, LENGTH> &buffer,
|
|
const BytesAndDuration &initial, const double timeMs)
|
|
{
|
|
BytesAndDuration sum = buffer.Sum(
|
|
[timeMs](BytesAndDuration a, BytesAndDuration b) {
|
|
if (timeMs != 0 && a.second >= timeMs) {
|
|
return a;
|
|
}
|
|
return std::make_pair(a.first + b.first, a.second + b.second);
|
|
},
|
|
initial);
|
|
uint64_t bytes = sum.first;
|
|
double durations = sum.second;
|
|
if (durations == 0.0) {
|
|
return 0;
|
|
}
|
|
double speed = bytes / durations;
|
|
const int maxSpeed = static_cast<int>(1_GB);
|
|
const int minSpeed = 1;
|
|
if (speed >= maxSpeed) {
|
|
return maxSpeed;
|
|
}
|
|
if (speed <= minSpeed) {
|
|
return minSpeed;
|
|
}
|
|
return speed;
|
|
}
|
|
|
|
double MemController::CalculateAverageSpeed(const base::GCRingBuffer<BytesAndDuration, LENGTH> &buffer)
|
|
{
|
|
return CalculateAverageSpeed(buffer, MakeBytesAndDuration(0, 0), 0);
|
|
}
|
|
|
|
double MemController::GetCurrentOldSpaceAllocationThroughputPerMS(double timeMs) const
|
|
{
|
|
size_t allocatedSize = oldSpaceAllocSizeSinceGC_;
|
|
double duration = allocDurationSinceGc_;
|
|
return CalculateAverageSpeed(recordedOldSpaceAllocations_,
|
|
MakeBytesAndDuration(allocatedSize, duration), timeMs);
|
|
}
|
|
|
|
double MemController::GetEdenSpaceAllocationThroughputPerMS() const
|
|
{
|
|
return CalculateAverageSpeed(recordedEdenSpaceAllocations_);
|
|
}
|
|
|
|
double MemController::GetNewSpaceAllocationThroughputPerMS() const
|
|
{
|
|
return CalculateAverageSpeed(recordedNewSpaceAllocations_);
|
|
}
|
|
|
|
double MemController::GetEdenSpaceConcurrentMarkSpeedPerMS() const
|
|
{
|
|
return CalculateAverageSpeed(recordedEdenConcurrentMarks_);
|
|
}
|
|
|
|
double MemController::GetNewSpaceConcurrentMarkSpeedPerMS() const
|
|
{
|
|
return CalculateAverageSpeed(recordedSemiConcurrentMarks_);
|
|
}
|
|
|
|
double MemController::GetOldSpaceAllocationThroughputPerMS() const
|
|
{
|
|
return CalculateAverageSpeed(recordedOldSpaceAllocations_);
|
|
}
|
|
|
|
double MemController::GetFullSpaceConcurrentMarkSpeedPerMS() const
|
|
{
|
|
return CalculateAverageSpeed(recordedConcurrentMarks_);
|
|
}
|
|
|
|
double MemController::GetIdleNewSpaceAllocationThroughputPerMS() const
|
|
{
|
|
return CalculateAverageSpeed(recordedIdleNewSpaceAllocations_);
|
|
}
|
|
|
|
double MemController::GetIdleOldSpaceAllocationThroughputPerMS() const
|
|
{
|
|
return CalculateAverageSpeed(recordedIdleOldSpaceAllocations_);
|
|
}
|
|
|
|
} // namespace panda::ecmascript
|