blob: b7742c0f5ed2b9f7acc2cc075b733081039e9274 [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.
*/
#ifndef ART_RUNTIME_JAVAHEAPPROF_JAVAHEAPSAMPLER_H_
#define ART_RUNTIME_JAVAHEAPPROF_JAVAHEAPSAMPLER_H_
#include <random>
#include "base/locks.h"
#include "base/mutex.h"
#include "mirror/object.h"
namespace art HIDDEN {
class HeapSampler {
public:
HeapSampler() : rng_(/*seed=*/std::minstd_rand::default_seed),
geo_dist_(1.0 / /*expected value=4KB*/ 4096),
geo_dist_rng_lock_("Heap Sampler RNG Geometric Dist lock",
art::LockLevel::kGenericBottomLock) {}
// Set the bytes until sample.
void SetBytesUntilSample(size_t bytes) {
*GetBytesUntilSample() = bytes;
}
// Get the bytes until sample.
size_t* GetBytesUntilSample() {
// Initialization should happen only once the first time the function is called.
// However there will always be a slot allocated for it at thread creation.
thread_local size_t bytes_until_sample = 0;
return &bytes_until_sample;
}
void SetHeapID(uint32_t heap_id) {
perfetto_heap_id_ = heap_id;
}
void EnableHeapSampler() {
enabled_.store(true, std::memory_order_release);
}
void DisableHeapSampler() {
enabled_.store(false, std::memory_order_release);
}
// Report a sample to Perfetto.
void ReportSample(art::mirror::Object* obj, size_t allocation_size);
// Check whether we should take a sample or not at this allocation, and return the
// number of bytes from current pos to the next sample to use in the expand Tlab
// calculation.
// Update state of both take_sample and temp_bytes_until_sample.
// tlab_used = pos - start
// Note: we do not update bytes until sample here. It will be saved after the allocation
// happens. This function can be called before the actual allocation happens.
size_t GetSampleOffset(size_t alloc_size,
size_t tlab_used,
bool* take_sample,
size_t* temp_bytes_until_sample) REQUIRES(!geo_dist_rng_lock_);
// Adjust the sample offset value with the adjustment usually (pos - start)
// of new Tlab after Reset.
void AdjustSampleOffset(size_t adjustment);
// Is heap sampler enabled?
bool IsEnabled() { return enabled_.load(std::memory_order_acquire); }
// Set the sampling interval.
void SetSamplingInterval(int sampling_interval) REQUIRES(!geo_dist_rng_lock_);
// Return the sampling interval.
int GetSamplingInterval();
private:
size_t NextGeoDistRandSample() REQUIRES(!geo_dist_rng_lock_);
// Choose, save, and return the number of bytes until the next sample,
// possibly decreasing sample intervals by sample_adj_bytes.
size_t PickAndAdjustNextSample(size_t sample_adj_bytes = 0) REQUIRES(!geo_dist_rng_lock_);
std::atomic<bool> enabled_{false};
// Default sampling interval is 4kb.
// Writes guarded by geo_dist_rng_lock_.
std::atomic<int> p_sampling_interval_{4 * 1024};
uint32_t perfetto_heap_id_ = 0;
// std random number generator.
std::minstd_rand rng_ GUARDED_BY(geo_dist_rng_lock_); // Holds the state
// std geometric distribution
std::geometric_distribution</*result_type=*/size_t> geo_dist_ GUARDED_BY(geo_dist_rng_lock_);
// Multiple threads can access the geometric distribution and the random number
// generator concurrently and thus geo_dist_rng_lock_ is used for thread safety.
art::Mutex geo_dist_rng_lock_;
};
} // namespace art
#endif // ART_RUNTIME_JAVAHEAPPROF_JAVAHEAPSAMPLER_H_