1/* 2 * Copyright (c) 2023-2024 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 "allocation_inspector.h" 17 18#include "ecmascript/base/number_helper.h" 19#include "ecmascript/dfx/hprof/heap_sampling.h" 20 21namespace panda::ecmascript { 22void AllocationInspector::Step([[maybe_unused]] Address object, [[maybe_unused]] size_t size) 23{ 24#ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING 25 ASSERT(!heap_->GetJSThread()->GetGcState()); 26 if (object) { 27 profiler_->ImplementSampling(object, size); 28 } 29#endif 30} 31 32// Sampling follows a Poisson distribution. 33// According to the relationship between Poisson distribution and exponential probability distribution, 34// the stepSize follows the exponential probability distribution with parameter λ = 1/rate where rate 35// is average bytes between samples. 36// Let random be a uniformly distributed random number between 0 and 1, beacuse Inverse transform sampling 37// can generate exponential probability distribution with a uniform distribution, so nextSample = (- ln random) / λ. 38size_t AllocationInspector::GetNextStepSize() 39{ 40 double random = base::RandomGenerator::NextDouble(); 41 double stepSize = -std::log(random) * rate_; 42 return stepSize < TaggedObject::TaggedObjectSize() 43 ? TaggedObject::TaggedObjectSize() 44 : (stepSize > INT_MAX ? INT_MAX : static_cast<size_t>(stepSize)); 45} 46 47void AllocationCounter::AddAllocationInspector(AllocationInspector *inspector) 48{ 49 ASSERT(inspector != nullptr); 50 size_t stepSize = inspector->GetNextStepSize(); 51 size_t nextCounter = currentCounter_ + stepSize; 52 inspector_ = inspector; 53 54 ASSERT(currentCounter_ == nextCounter_); 55 nextCounter_ = nextCounter; 56} 57 58void AllocationCounter::ClearAllocationInspector() 59{ 60 inspector_ = nullptr; 61 currentCounter_ = 0; 62 nextCounter_ = 0; 63} 64 65void AllocationCounter::AdvanceAllocationInspector(size_t allocated) 66{ 67 if (!IsActive()) { 68 return; 69 } 70 ASSERT(allocated < nextCounter_ - currentCounter_); 71 currentCounter_ += allocated; 72} 73 74void AllocationCounter::InvokeAllocationInspector(Address object, size_t objectSize, size_t alignedObjectSize) 75{ 76 if (!IsActive()) { 77 return; 78 } 79 80 ASSERT(alignedObjectSize >= nextCounter_ - currentCounter_); 81 ASSERT(object != 0); 82 { 83 DISALLOW_GARBAGE_COLLECTION; 84 inspector_->Step(object, objectSize); 85 } 86 size_t nextStepSize = inspector_->GetNextStepSize(); 87 // because next allocate or advance can add currentCounter_ to real allocated size, 88 // so need add alignedObjectSize here. 89 nextCounter_ = currentCounter_ + alignedObjectSize + nextStepSize; 90} 91} // namespace panda::ecmascript