blob: 48c3f73958fa817dcfc70f23cc19ec2c432f14a6 [file] [log] [blame]
 // Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/profiler/sampling-heap-profiler.h" #include #include #include "src/api-inl.h" #include "src/base/ieee754.h" #include "src/base/utils/random-number-generator.h" #include "src/frames-inl.h" #include "src/heap/heap.h" #include "src/isolate.h" #include "src/profiler/strings-storage.h" namespace v8 { namespace internal { // We sample with a Poisson process, with constant average sampling interval. // This follows the exponential probability distribution with parameter // λ = 1/rate where rate is the average number of bytes between samples. // // Let u be a uniformly distributed random number between 0 and 1, then // next_sample = (- ln u) / λ intptr_t SamplingAllocationObserver::GetNextSampleInterval(uint64_t rate) { if (FLAG_sampling_heap_profiler_suppress_randomness) { return static_cast(rate); } double u = random_->NextDouble(); double next = (-base::ieee754::log(u)) * rate; return next < kPointerSize ? kPointerSize : (next > INT_MAX ? INT_MAX : static_cast(next)); } // Samples were collected according to a poisson process. Since we have not // recorded all allocations, we must approximate the shape of the underlying // space of allocations based on the samples we have collected. Given that // we sample at rate R, the probability that an allocation of size S will be // sampled is 1-exp(-S/R). This function uses the above probability to // approximate the true number of allocations with size *size* given that // *count* samples were observed. v8::AllocationProfile::Allocation SamplingHeapProfiler::ScaleSample( size_t size, unsigned int count) { double scale = 1.0 / (1.0 - std::exp(-static_cast(size) / rate_)); // Round count instead of truncating. return {size, static_cast(count * scale + 0.5)}; } SamplingHeapProfiler::SamplingHeapProfiler( Heap* heap, StringsStorage* names, uint64_t rate, int stack_depth, v8::HeapProfiler::SamplingFlags flags) : isolate_(heap->isolate()), heap_(heap), new_space_observer_(new SamplingAllocationObserver( heap_, static_cast(rate), rate, this, heap->isolate()->random_number_generator())), other_spaces_observer_(new SamplingAllocationObserver( heap_, static_cast(rate), rate, this, heap->isolate()->random_number_generator())), names_(names), profile_root_(nullptr, "(root)", v8::UnboundScript::kNoScriptId, 0), samples_(), stack_depth_(stack_depth), rate_(rate), flags_(flags) { CHECK_GT(rate_, 0u); heap_->AddAllocationObserversToAllSpaces(other_spaces_observer_.get(), new_space_observer_.get()); } SamplingHeapProfiler::~SamplingHeapProfiler() { heap_->RemoveAllocationObserversFromAllSpaces(other_spaces_observer_.get(), new_space_observer_.get()); samples_.clear(); } void SamplingHeapProfiler::SampleObject(Address soon_object, size_t size) { DisallowHeapAllocation no_allocation; HandleScope scope(isolate_); HeapObject* heap_object = HeapObject::FromAddress(soon_object); Handle