blob: a1c58d891220fdf80470423469e8a2386fa294d1 [file] [log] [blame]
Wessam Hassaneinb5a10be2020-11-11 16:42:52 -08001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "base/atomic.h"
18#include "base/locks.h"
19#include "gc/heap.h"
20#include "javaheapprof/javaheapsampler.h"
21#include "runtime.h"
22
23namespace art {
24
25size_t HeapSampler::NextGeoDistRandSample() {
26 // Make sure that rng_ and geo_dist are thread safe by acquiring a lock to access.
27 art::MutexLock mu(art::Thread::Current(), geo_dist_rng_lock_);
28 size_t nsample = geo_dist_(rng_);
29 if (nsample == 0) {
30 // Geometric distribution results in +ve values but could have zero.
31 // In the zero case, return 1.
32 nsample = 1;
33 }
34 return nsample;
35}
36
37size_t HeapSampler::PickAndAdjustNextSample(size_t sample_adjust_bytes) {
38 size_t bytes_until_sample;
39 if (GetSamplingInterval() == 1) {
40 bytes_until_sample = 1;
41 return bytes_until_sample;
42 }
43 bytes_until_sample = NextGeoDistRandSample();
44 VLOG(heap) << "JHP:PickAndAdjustNextSample, sample_adjust_bytes: "
45 << sample_adjust_bytes
46 << " bytes_until_sample: " << bytes_until_sample;
47 // Adjust the sample bytes
48 if (sample_adjust_bytes > 0 && bytes_until_sample > sample_adjust_bytes) {
49 bytes_until_sample -= sample_adjust_bytes;
50 VLOG(heap) << "JHP:PickAndAdjustNextSample, final bytes_until_sample: "
51 << bytes_until_sample;
52 }
53 return bytes_until_sample;
54}
55
56// Report to Perfetto an allocation sample.
57// Samples can only be reported after the allocation is done.
58// Also bytes_until_sample can only be updated after the allocation and reporting is done.
59// Thus next bytes_until_sample is previously calculated (before allocation) to be able to
60// get the next tlab_size, but only saved/updated here.
Nicolas Geoffray22914392021-03-09 08:59:55 +000061void HeapSampler::ReportSample(art::mirror::Object* obj ATTRIBUTE_UNUSED, size_t allocation_size) {
Wessam Hassaneinb5a10be2020-11-11 16:42:52 -080062 VLOG(heap) << "JHP:***Report Perfetto Allocation: alloc_size: " << allocation_size;
63}
64
65// Check whether we should take a sample or not at this allocation and calculate the sample
66// offset to use in the expand Tlab calculation. Thus the offset from current pos to the next
67// sample.
68// tlab_used = pos - start
69size_t HeapSampler::GetSampleOffset(size_t alloc_size,
70 size_t tlab_used,
71 bool* take_sample,
72 size_t* temp_bytes_until_sample) {
73 size_t exhausted_size = alloc_size + tlab_used;
74 VLOG(heap) << "JHP:GetSampleOffset: exhausted_size = " << exhausted_size;
75 // Note bytes_until_sample is used as an offset from the start point
76 size_t bytes_until_sample = *GetBytesUntilSample();
77 ssize_t diff = bytes_until_sample - exhausted_size;
78 VLOG(heap) << "JHP:GetSampleOffset: diff = " << diff << " bytes_until_sample = "
79 << bytes_until_sample;
80 if (diff <= 0) {
81 *take_sample = true;
82 // Compute a new bytes_until_sample
83 size_t sample_adj_bytes = -diff;
84 size_t next_bytes_until_sample = PickAndAdjustNextSample(sample_adj_bytes);
85 VLOG(heap) << "JHP:GetSampleOffset: Take sample, next_bytes_until_sample = "
86 << next_bytes_until_sample;
87 next_bytes_until_sample += tlab_used;
88 VLOG(heap) << "JHP:GetSampleOffset:Next sample offset = "
89 << (next_bytes_until_sample - tlab_used);
90 // This function is called before the actual allocation happens so we cannot update
91 // the bytes_until_sample till after the allocation happens, save it to temp which
92 // will be saved after the allocation by the calling function.
93 *temp_bytes_until_sample = next_bytes_until_sample;
94 return (next_bytes_until_sample - tlab_used);
95 // original bytes_until_sample, not offseted
96 } else {
97 *take_sample = false;
98 // The following 2 lines are used in the NonTlab case but have no effect on the
99 // Tlab case, because we will only use the temp_bytes_until_sample if the
100 // take_sample was true (after returning from this function in Tlab case in the
101 // SetBytesUntilSample).
102 size_t next_bytes_until_sample = bytes_until_sample - alloc_size;
103 *temp_bytes_until_sample = next_bytes_until_sample;
104 VLOG(heap) << "JHP:GetSampleOffset: No sample, next_bytes_until_sample= "
105 << next_bytes_until_sample << " alloc= " << alloc_size;
106 return diff;
107 }
108}
109
110// We are tracking the location of samples from the start location of the Tlab
111// We need to adjust how to calculate the sample position in cases where ResetTlab.
112// Adjustment is the new reference position adjustment, usually the new pos-start.
113void HeapSampler::AdjustSampleOffset(size_t adjustment) {
114 size_t* bytes_until_sample = GetBytesUntilSample();
115 size_t cur_bytes_until_sample = *bytes_until_sample;
116 if (cur_bytes_until_sample < adjustment) {
117 VLOG(heap) << "JHP:AdjustSampleOffset:No Adjustment";
118 return;
119 }
120 size_t next_bytes_until_sample = cur_bytes_until_sample - adjustment;
121 *bytes_until_sample = next_bytes_until_sample;
122 VLOG(heap) << "JHP:AdjustSampleOffset: adjustment = " << adjustment
123 << " next_bytes_until_sample = " << next_bytes_until_sample;
124}
125
Nicolas Geoffray22914392021-03-09 08:59:55 +0000126// Enable the heap sampler and initialize/set the sampling interval.
127void HeapSampler::EnableHeapSampler(void* enable_ptr ATTRIBUTE_UNUSED,
128 const void* enable_info_ptr ATTRIBUTE_UNUSED) {
129 uint64_t interval = 4 * 1024;
130 // Set the ART profiler sampling interval to the value from AHeapProfileSessionInfo
131 // Set interval to sampling interval from AHeapProfileSessionInfo
132 if (interval > 0) {
133 // Make sure that rng_ and geo_dist are thread safe by acquiring a lock to access.
134 art::MutexLock mu(art::Thread::Current(), geo_dist_rng_lock_);
135 SetSamplingInterval(interval);
136 }
137 // Else default is 4K sampling interval. However, default case shouldn't happen for Perfetto API.
138 // AHeapProfileEnableCallbackInfo_getSamplingInterval should always give the requested
139 // (non-negative) sampling interval. It is a uint64_t and gets checked for != 0
140 // Do not call heap->GetPerfettoJavaHeapProfHeapID() as a temp here, it will build but test run
141 // will silently fail. Heap is not fully constructed yet.
142 // heap_id will be set through the Perfetto API.
143 perfetto_heap_id_ = 1; // To be set by Perfetto API
144 enabled_.store(true, std::memory_order_release);
145}
146
Wessam Hassaneinb5a10be2020-11-11 16:42:52 -0800147bool HeapSampler::IsEnabled() {
148 return enabled_.load(std::memory_order_acquire);
149}
150
Nicolas Geoffray22914392021-03-09 08:59:55 +0000151void HeapSampler::DisableHeapSampler(void* disable_ptr ATTRIBUTE_UNUSED,
152 const void* disable_info_ptr ATTRIBUTE_UNUSED) {
153 enabled_.store(false, std::memory_order_release);
154}
155
Wessam Hassaneinb5a10be2020-11-11 16:42:52 -0800156int HeapSampler::GetSamplingInterval() {
157 return p_sampling_interval_.load(std::memory_order_acquire);
158}
159
160void HeapSampler::SetSamplingInterval(int sampling_interval) {
161 p_sampling_interval_.store(sampling_interval, std::memory_order_release);
162 geo_dist_.param(std::geometric_distribution<size_t>::param_type(1.0/p_sampling_interval_));
163}
164
Nicolas Geoffray22914392021-03-09 08:59:55 +0000165void HeapSampler::SetSessionInfo(void* info) {
166 perfetto_session_info_ = info;
167}
168
169void* HeapSampler::GetSessionInfo() {
170 return perfetto_session_info_;
171}
172
Wessam Hassaneinb5a10be2020-11-11 16:42:52 -0800173} // namespace art