1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
/*
* 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 {
size_t HeapSampler::NextGeoDistRandSample() {
// Make sure that rng_ and geo_dist are thread safe by acquiring a lock to access.
art::MutexLock mu(art::Thread::Current(), geo_dist_rng_lock_);
size_t nsample = geo_dist_(rng_);
if (nsample == 0) {
// Geometric distribution results in +ve values but could have zero.
// In the zero case, return 1.
nsample = 1;
}
return nsample;
}
size_t HeapSampler::PickAndAdjustNextSample(size_t sample_adjust_bytes) {
size_t bytes_until_sample;
if (GetSamplingInterval() == 1) {
bytes_until_sample = 1;
return bytes_until_sample;
}
bytes_until_sample = NextGeoDistRandSample();
VLOG(heap) << "JHP:PickAndAdjustNextSample, sample_adjust_bytes: "
<< sample_adjust_bytes
<< " bytes_until_sample: " << bytes_until_sample;
// Adjust the sample bytes
if (sample_adjust_bytes > 0 && bytes_until_sample > sample_adjust_bytes) {
bytes_until_sample -= sample_adjust_bytes;
VLOG(heap) << "JHP:PickAndAdjustNextSample, final bytes_until_sample: "
<< bytes_until_sample;
}
return bytes_until_sample;
}
// Report to Perfetto an allocation sample.
// Samples can only be reported after the allocation is done.
// Also bytes_until_sample can only be updated after the allocation and reporting is done.
// Thus next bytes_until_sample is previously calculated (before allocation) to be able to
// get the next tlab_size, but only saved/updated here.
void HeapSampler::ReportSample(art::mirror::Object* obj, size_t allocation_size) {
VLOG(heap) << "JHP:***Report Perfetto Allocation: alloc_size: " << allocation_size;
uint64_t perf_alloc_id = reinterpret_cast<uint64_t>(obj);
VLOG(heap) << "JHP:***Report Perfetto Allocation: obj: " << perf_alloc_id;
#ifdef ART_TARGET_ANDROID
AHeapProfile_reportSample(perfetto_heap_id_, perf_alloc_id, allocation_size);
#endif
}
// Check whether we should take a sample or not at this allocation and calculate the sample
// offset to use in the expand Tlab calculation. Thus the offset from current pos to the next
// sample.
// tlab_used = pos - start
size_t HeapSampler::GetSampleOffset(size_t alloc_size,
size_t tlab_used,
bool* take_sample,
size_t* temp_bytes_until_sample) {
size_t exhausted_size = alloc_size + tlab_used;
VLOG(heap) << "JHP:GetSampleOffset: exhausted_size = " << exhausted_size;
// Note bytes_until_sample is used as an offset from the start point
size_t bytes_until_sample = *GetBytesUntilSample();
ssize_t diff = bytes_until_sample - exhausted_size;
VLOG(heap) << "JHP:GetSampleOffset: diff = " << diff << " bytes_until_sample = "
<< bytes_until_sample;
if (diff <= 0) {
*take_sample = true;
// Compute a new bytes_until_sample
size_t sample_adj_bytes = -diff;
size_t next_bytes_until_sample = PickAndAdjustNextSample(sample_adj_bytes);
VLOG(heap) << "JHP:GetSampleOffset: Take sample, next_bytes_until_sample = "
<< next_bytes_until_sample;
next_bytes_until_sample += tlab_used;
VLOG(heap) << "JHP:GetSampleOffset:Next sample offset = "
<< (next_bytes_until_sample - tlab_used);
// This function is called before the actual allocation happens so we cannot update
// the bytes_until_sample till after the allocation happens, save it to temp which
// will be saved after the allocation by the calling function.
*temp_bytes_until_sample = next_bytes_until_sample;
return (next_bytes_until_sample - tlab_used);
// original bytes_until_sample, not offseted
} else {
*take_sample = false;
// The following 2 lines are used in the NonTlab case but have no effect on the
// Tlab case, because we will only use the temp_bytes_until_sample if the
// take_sample was true (after returning from this function in Tlab case in the
// SetBytesUntilSample).
size_t next_bytes_until_sample = bytes_until_sample - alloc_size;
*temp_bytes_until_sample = next_bytes_until_sample;
VLOG(heap) << "JHP:GetSampleOffset: No sample, next_bytes_until_sample= "
<< next_bytes_until_sample << " alloc= " << alloc_size;
return diff;
}
}
// We are tracking the location of samples from the start location of the Tlab
// We need to adjust how to calculate the sample position in cases where ResetTlab.
// Adjustment is the new reference position adjustment, usually the new pos-start.
void HeapSampler::AdjustSampleOffset(size_t adjustment) {
size_t* bytes_until_sample = GetBytesUntilSample();
size_t cur_bytes_until_sample = *bytes_until_sample;
if (cur_bytes_until_sample < adjustment) {
VLOG(heap) << "JHP:AdjustSampleOffset:No Adjustment";
return;
}
size_t next_bytes_until_sample = cur_bytes_until_sample - adjustment;
*bytes_until_sample = next_bytes_until_sample;
VLOG(heap) << "JHP:AdjustSampleOffset: adjustment = " << adjustment
<< " next_bytes_until_sample = " << next_bytes_until_sample;
}
bool HeapSampler::IsEnabled() {
return enabled_.load(std::memory_order_acquire);
}
int HeapSampler::GetSamplingInterval() {
return p_sampling_interval_.load(std::memory_order_acquire);
}
void HeapSampler::SetSamplingInterval(int sampling_interval) {
// Make sure that rng_ and geo_dist are thread safe by acquiring a lock to access.
art::MutexLock mu(art::Thread::Current(), geo_dist_rng_lock_);
p_sampling_interval_.store(sampling_interval, std::memory_order_release);
geo_dist_.param(std::geometric_distribution<size_t>::param_type(1.0/p_sampling_interval_));
}
} // namespace art
|