1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker #ifndef ART_RUNTIME_JAVAHEAPPROF_JAVAHEAPSAMPLER_H_ 18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_JAVAHEAPPROF_JAVAHEAPSAMPLER_H_ 19*795d594fSAndroid Build Coastguard Worker 20*795d594fSAndroid Build Coastguard Worker #include <random> 21*795d594fSAndroid Build Coastguard Worker #include "base/locks.h" 22*795d594fSAndroid Build Coastguard Worker #include "base/mutex.h" 23*795d594fSAndroid Build Coastguard Worker #include "mirror/object.h" 24*795d594fSAndroid Build Coastguard Worker 25*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN { 26*795d594fSAndroid Build Coastguard Worker 27*795d594fSAndroid Build Coastguard Worker class HeapSampler { 28*795d594fSAndroid Build Coastguard Worker public: HeapSampler()29*795d594fSAndroid Build Coastguard Worker HeapSampler() : rng_(/*seed=*/std::minstd_rand::default_seed), 30*795d594fSAndroid Build Coastguard Worker geo_dist_(1.0 / /*expected value=4KB*/ 4096), 31*795d594fSAndroid Build Coastguard Worker geo_dist_rng_lock_("Heap Sampler RNG Geometric Dist lock", 32*795d594fSAndroid Build Coastguard Worker art::LockLevel::kGenericBottomLock) {} 33*795d594fSAndroid Build Coastguard Worker 34*795d594fSAndroid Build Coastguard Worker // Set the bytes until sample. SetBytesUntilSample(size_t bytes)35*795d594fSAndroid Build Coastguard Worker void SetBytesUntilSample(size_t bytes) { 36*795d594fSAndroid Build Coastguard Worker *GetBytesUntilSample() = bytes; 37*795d594fSAndroid Build Coastguard Worker } 38*795d594fSAndroid Build Coastguard Worker // Get the bytes until sample. GetBytesUntilSample()39*795d594fSAndroid Build Coastguard Worker size_t* GetBytesUntilSample() { 40*795d594fSAndroid Build Coastguard Worker // Initialization should happen only once the first time the function is called. 41*795d594fSAndroid Build Coastguard Worker // However there will always be a slot allocated for it at thread creation. 42*795d594fSAndroid Build Coastguard Worker thread_local size_t bytes_until_sample = 0; 43*795d594fSAndroid Build Coastguard Worker return &bytes_until_sample; 44*795d594fSAndroid Build Coastguard Worker } SetHeapID(uint32_t heap_id)45*795d594fSAndroid Build Coastguard Worker void SetHeapID(uint32_t heap_id) { 46*795d594fSAndroid Build Coastguard Worker perfetto_heap_id_ = heap_id; 47*795d594fSAndroid Build Coastguard Worker } EnableHeapSampler()48*795d594fSAndroid Build Coastguard Worker void EnableHeapSampler() { 49*795d594fSAndroid Build Coastguard Worker enabled_.store(true, std::memory_order_release); 50*795d594fSAndroid Build Coastguard Worker } DisableHeapSampler()51*795d594fSAndroid Build Coastguard Worker void DisableHeapSampler() { 52*795d594fSAndroid Build Coastguard Worker enabled_.store(false, std::memory_order_release); 53*795d594fSAndroid Build Coastguard Worker } 54*795d594fSAndroid Build Coastguard Worker // Report a sample to Perfetto. 55*795d594fSAndroid Build Coastguard Worker void ReportSample(art::mirror::Object* obj, size_t allocation_size); 56*795d594fSAndroid Build Coastguard Worker // Check whether we should take a sample or not at this allocation, and return the 57*795d594fSAndroid Build Coastguard Worker // number of bytes from current pos to the next sample to use in the expand Tlab 58*795d594fSAndroid Build Coastguard Worker // calculation. 59*795d594fSAndroid Build Coastguard Worker // Update state of both take_sample and temp_bytes_until_sample. 60*795d594fSAndroid Build Coastguard Worker // tlab_used = pos - start 61*795d594fSAndroid Build Coastguard Worker // Note: we do not update bytes until sample here. It will be saved after the allocation 62*795d594fSAndroid Build Coastguard Worker // happens. This function can be called before the actual allocation happens. 63*795d594fSAndroid Build Coastguard Worker size_t GetSampleOffset(size_t alloc_size, 64*795d594fSAndroid Build Coastguard Worker size_t tlab_used, 65*795d594fSAndroid Build Coastguard Worker bool* take_sample, 66*795d594fSAndroid Build Coastguard Worker size_t* temp_bytes_until_sample) REQUIRES(!geo_dist_rng_lock_); 67*795d594fSAndroid Build Coastguard Worker // Adjust the sample offset value with the adjustment usually (pos - start) 68*795d594fSAndroid Build Coastguard Worker // of new Tlab after Reset. 69*795d594fSAndroid Build Coastguard Worker void AdjustSampleOffset(size_t adjustment); 70*795d594fSAndroid Build Coastguard Worker // Is heap sampler enabled? IsEnabled()71*795d594fSAndroid Build Coastguard Worker bool IsEnabled() { return enabled_.load(std::memory_order_acquire); } 72*795d594fSAndroid Build Coastguard Worker // Set the sampling interval. 73*795d594fSAndroid Build Coastguard Worker void SetSamplingInterval(int sampling_interval) REQUIRES(!geo_dist_rng_lock_); 74*795d594fSAndroid Build Coastguard Worker // Return the sampling interval. 75*795d594fSAndroid Build Coastguard Worker int GetSamplingInterval(); 76*795d594fSAndroid Build Coastguard Worker 77*795d594fSAndroid Build Coastguard Worker private: 78*795d594fSAndroid Build Coastguard Worker size_t NextGeoDistRandSample() REQUIRES(!geo_dist_rng_lock_); 79*795d594fSAndroid Build Coastguard Worker // Choose, save, and return the number of bytes until the next sample, 80*795d594fSAndroid Build Coastguard Worker // possibly decreasing sample intervals by sample_adj_bytes. 81*795d594fSAndroid Build Coastguard Worker size_t PickAndAdjustNextSample(size_t sample_adj_bytes = 0) REQUIRES(!geo_dist_rng_lock_); 82*795d594fSAndroid Build Coastguard Worker 83*795d594fSAndroid Build Coastguard Worker std::atomic<bool> enabled_{false}; 84*795d594fSAndroid Build Coastguard Worker // Default sampling interval is 4kb. 85*795d594fSAndroid Build Coastguard Worker // Writes guarded by geo_dist_rng_lock_. 86*795d594fSAndroid Build Coastguard Worker std::atomic<int> p_sampling_interval_{4 * 1024}; 87*795d594fSAndroid Build Coastguard Worker uint32_t perfetto_heap_id_ = 0; 88*795d594fSAndroid Build Coastguard Worker // std random number generator. 89*795d594fSAndroid Build Coastguard Worker std::minstd_rand rng_ GUARDED_BY(geo_dist_rng_lock_); // Holds the state 90*795d594fSAndroid Build Coastguard Worker // std geometric distribution 91*795d594fSAndroid Build Coastguard Worker std::geometric_distribution</*result_type=*/size_t> geo_dist_ GUARDED_BY(geo_dist_rng_lock_); 92*795d594fSAndroid Build Coastguard Worker // Multiple threads can access the geometric distribution and the random number 93*795d594fSAndroid Build Coastguard Worker // generator concurrently and thus geo_dist_rng_lock_ is used for thread safety. 94*795d594fSAndroid Build Coastguard Worker art::Mutex geo_dist_rng_lock_; 95*795d594fSAndroid Build Coastguard Worker }; 96*795d594fSAndroid Build Coastguard Worker 97*795d594fSAndroid Build Coastguard Worker } // namespace art 98*795d594fSAndroid Build Coastguard Worker 99*795d594fSAndroid Build Coastguard Worker #endif // ART_RUNTIME_JAVAHEAPPROF_JAVAHEAPSAMPLER_H_ 100