dart-sdk/runtime/vm/random.cc
Ben Konyi 8caeaf7a6c [ VM ] Add support for heap sampling profiler
This CL introduces new embedding APIs for supporting heap sample
profiling. A registered sampling callback is invoked approximately every
N bytes based on an exponential distribution, providing information
about the isolate group the allocation occurred in, the user visible
name of the allocated object type, a weak persistent handle to the
allocated object, and the size of the allocation.

Sampling is triggered using artificial TLAB boundaries to cause
allocations to be sampled to take the allocation slow path where the
registered callback can be invoked with the allocation information.

Only new space allocations are currently traced, with old space
allocation support to be added in a future CL.

TEST=Dart_HeapSampling

Change-Id: I22bcdeec6e823bc1ab44898d4c596fbed7169fa1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/264520
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2022-11-22 18:05:24 +00:00

108 lines
2.8 KiB
C++

// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/random.h"
#include "vm/dart.h"
#include "vm/flags.h"
#include "vm/os.h"
namespace dart {
DEFINE_FLAG(uint64_t,
random_seed,
0,
"Override the random seed for debugging.");
Random::Random() {
uint64_t seed = FLAG_random_seed;
if (seed == 0) {
Dart_EntropySource callback = Dart::entropy_source_callback();
if (callback != NULL) {
if (!callback(reinterpret_cast<uint8_t*>(&seed), sizeof(seed))) {
// Callback failed. Reset the seed to 0.
seed = 0;
}
}
}
if (seed == 0) {
// We did not get a seed so far. As a fallback we do use the current time.
seed = OS::GetCurrentTimeMicros();
}
Initialize(seed);
}
void Random::Initialize(uint64_t seed) {
ASSERT(seed != 0);
// Crank the next state a couple of times.
_state = seed;
NextState();
NextState();
NextState();
NextState();
}
Random::Random(uint64_t seed) {
Initialize(seed);
}
Random::~Random() {
// Nothing to be done here.
}
// The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32.
// http://en.wikipedia.org/wiki/Multiply-with-carry
// The constant A is selected from "Numerical Recipes 3rd Edition" p.348 B1.
uint64_t Random::NextState() {
const uint64_t MASK_32 = 0xffffffff;
const uint64_t A = 0xffffda61;
uint64_t old_state = _state;
while (true) {
const uint64_t state_lo = old_state & MASK_32;
const uint64_t state_hi = (old_state >> 32) & MASK_32;
const uint64_t new_state = (A * state_lo) + state_hi;
if (_state.compare_exchange_weak(old_state, new_state,
std::memory_order_relaxed,
std::memory_order_relaxed)) {
return new_state;
}
}
}
uint32_t Random::NextUInt32() {
const uint64_t MASK_32 = 0xffffffff;
return static_cast<uint32_t>(NextState() & MASK_32);
}
static Random* global_random = nullptr;
static Mutex* global_random_mutex = nullptr;
void Random::Init() {
ASSERT(global_random_mutex == nullptr);
global_random_mutex = new Mutex(NOT_IN_PRODUCT("global_random_mutex"));
ASSERT(global_random == nullptr);
global_random = new Random();
}
void Random::Cleanup() {
delete global_random_mutex;
global_random_mutex = nullptr;
delete global_random;
global_random = nullptr;
}
uint64_t Random::GlobalNextUInt64() {
MutexLocker locker(global_random_mutex);
return global_random->NextUInt64();
}
double Random::NextDouble() {
uint64_t mantissa = NextUInt64() & 0xFFFFFFFFFFFFF;
// The exponent value 0 in biased form.
const uint64_t exp = 1023;
return bit_cast<double>(exp << 52 | mantissa) - 1.0;
}
} // namespace dart