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