blob: 2969bb320e6da3943198aa42e5b6c29ea0626402 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* 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 "base/atomic.h"
#include "base/locks.h"
#include "gc/heap.h"
#include "javaheapprof/javaheapsampler.h"
#ifdef ART_TARGET_ANDROID
#include "perfetto/heap_profile.h"
#endif
#include "runtime.h"
namespace art HIDDEN {
size_t HeapSampler::NextRandomTlabSize(size_t target) {
// Scale the target tlab size by sampling interval, so the cost of
// profiling can be reduced by increasing the sampling interval.
// The factor 1/8 is somewhat arbitrarily chosen to avoid interfering with
// Perfetto's subsequent sampling of the allocations when we call
// AHeapProfile_reportAllocation.
target = std::min(target, GetSamplingInterval() / 8);
if (target == 0) {
target = 1;
}
// Draw randomly from exponential distribution with the goal of having
// equal probability of sampling any given byte. This is the same logic
// used in AHeapProfile_reportAllocation for sampling.
double rate = 1.0 / static_cast<double>(target);
std::exponential_distribution<double> dist(rate);
art::MutexLock mu(art::Thread::Current(), rng_lock_);
int64_t next = static_cast<int64_t>(dist(rng_));
return next + 1;
}
void HeapSampler::ReportAllocation([[maybe_unused]] art::mirror::Object* obj,
[[maybe_unused]] size_t allocation_size) {
#ifdef ART_TARGET_ANDROID
uint64_t perf_alloc_id = reinterpret_cast<uint64_t>(obj);
AHeapProfile_reportAllocation(perfetto_heap_id_, perf_alloc_id, allocation_size);
#endif
}
void HeapSampler::ReportTlabAllocation(art::mirror::Object* obj,
size_t allocation_size,
size_t pre_tlab_size,
size_t post_tlab_size) {
if (pre_tlab_size > tlab_unsampled_bytes_) {
// In theory pre_tlab_size shouldn't exceed tlab_unsampled_bytes_. In
// practice our tlab_unsampled_bytes_ could be out of date if profiling
// was disabled/enabled since we last set it. Ignore the previously
// allocated bytes in that case.
pre_tlab_size = 0;
tlab_unsampled_bytes_ = 0;
}
size_t adjusted_size = allocation_size + tlab_unsampled_bytes_ - pre_tlab_size;
tlab_unsampled_bytes_ = post_tlab_size;
ReportAllocation(obj, adjusted_size);
}
size_t HeapSampler::GetSamplingInterval() {
return p_sampling_interval_.load(std::memory_order_acquire);
}
void HeapSampler::SetSamplingInterval(size_t sampling_interval) {
p_sampling_interval_.store(sampling_interval, std::memory_order_release);
}
thread_local size_t HeapSampler::tlab_unsampled_bytes_ = 0;
} // namespace art