blob: 9fc55773d72e044d2fd59f6ca13c4b643f7d73eb [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2011 The Chromium Authors
[email protected]05f9b682008-09-29 22:18:012// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/rand_util.h"
6
avi9b6f42932015-12-26 22:15:147#include <limits.h>
[email protected]05f9b682008-09-29 22:18:018#include <math.h>
tfarina32089922015-05-18 22:14:099#include <stdint.h>
[email protected]94a0f312008-09-30 14:26:3310
John Chen87cc25c2018-04-20 22:49:4911#include <algorithm>
Olivier Li Shing Tat-Dupuis9e5e7d92024-02-13 14:42:1012#include <atomic>
John Chen87cc25c2018-04-20 22:49:4913#include <limits>
14
Anand Ravib793ffb32025-02-25 22:56:5415#include "base/check.h"
Hans Wennborgc3cffa62020-04-27 10:09:1216#include "base/check_op.h"
Peter Kastinga253f752025-01-31 18:57:2617#include "base/containers/span.h"
Peter Kastingf18c8ca2023-10-04 16:31:5118#include "base/time/time.h"
[email protected]05f9b682008-09-29 22:18:0119
[email protected]05f9b682008-09-29 22:18:0120namespace base {
21
François Doray87e35a82023-05-05 14:44:2822namespace {
23
Olivier Li Shing Tat-Dupuis9e5e7d92024-02-13 14:42:1024// A MetricSubsampler instance is not thread-safe. However, the global
25// sampling state may be read concurrently with writing it via testing
26// scopers, hence the need to use atomics. All operations use
27// memory_order_relaxed because there are no dependent memory accesses.
28std::atomic<bool> g_subsampling_always_sample = false;
29std::atomic<bool> g_subsampling_never_sample = false;
François Doray87e35a82023-05-05 14:44:2830
Anthony Vallée-Duboisecfdb382025-02-04 20:07:4031MetricsSubSampler* GetSharedSubsampler() {
32 static thread_local MetricsSubSampler g_shared_subsampler;
33 return &g_shared_subsampler;
34}
35
François Doray87e35a82023-05-05 14:44:2836} // namespace
37
John Mellorafab972d2017-09-26 16:28:1938uint64_t RandUint64() {
39 uint64_t number;
danakj95305d272024-05-09 20:38:4440 RandBytes(base::byte_span_from_ref(number));
John Mellorafab972d2017-09-26 16:28:1941 return number;
42}
43
[email protected]05f9b682008-09-29 22:18:0144int RandInt(int min, int max) {
[email protected]d7a93ad2011-04-22 13:13:0745 DCHECK_LE(min, max);
[email protected]05f9b682008-09-29 22:18:0146
Peter Kasting28b51cf2022-06-28 15:02:4347 uint64_t range = static_cast<uint64_t>(max) - static_cast<uint64_t>(min) + 1;
John Chen87cc25c2018-04-20 22:49:4948 // |range| is at most UINT_MAX + 1, so the result of RandGenerator(range)
49 // is at most UINT_MAX. Hence it's safe to cast it from uint64_t to int64_t.
50 int result =
51 static_cast<int>(min + static_cast<int64_t>(base::RandGenerator(range)));
[email protected]e1be56d2011-05-04 01:29:3852 DCHECK_GE(result, min);
53 DCHECK_LE(result, max);
[email protected]05f9b682008-09-29 22:18:0154 return result;
55}
56
57double RandDouble() {
[email protected]edafd4c2011-05-10 17:18:5358 return BitsToOpenEndedUnitInterval(base::RandUint64());
59}
60
Avery Musbacheff342b2022-10-06 18:36:0761float RandFloat() {
62 return BitsToOpenEndedUnitIntervalF(base::RandUint64());
63}
64
Peter Kastingb2dc55042025-01-16 16:30:5465bool RandBool() {
66 uint8_t number;
67 RandBytes(span_from_ref(number));
68 return number & 1;
69}
70
Peter Kastingf18c8ca2023-10-04 16:31:5171TimeDelta RandTimeDelta(TimeDelta start, TimeDelta limit) {
72 // We must have a finite, non-empty, non-reversed interval.
73 CHECK_LT(start, limit);
74 CHECK(!start.is_min());
75 CHECK(!limit.is_max());
76
77 const int64_t range = (limit - start).InMicroseconds();
78 // Because of the `CHECK_LT()` above, range > 0, so this cast is safe.
79 const uint64_t delta_us = base::RandGenerator(static_cast<uint64_t>(range));
80 // ...and because `range` fit in an `int64_t`, so will `delta_us`.
81 return start + Microseconds(static_cast<int64_t>(delta_us));
82}
83
84TimeDelta RandTimeDeltaUpTo(TimeDelta limit) {
85 return RandTimeDelta(TimeDelta(), limit);
86}
87
Nico Weber0a3852a72015-10-29 20:42:5888double BitsToOpenEndedUnitInterval(uint64_t bits) {
[email protected]94a0f312008-09-30 14:26:3389 // We try to get maximum precision by masking out as many bits as will fit
90 // in the target type's mantissa, and raising it to an appropriate power to
91 // produce output in the range [0, 1). For IEEE 754 doubles, the mantissa
Avery Musbach92a30e382022-09-08 23:30:4192 // is expected to accommodate 53 bits (including the implied bit).
avi4ec0dff2015-11-24 14:26:2493 static_assert(std::numeric_limits<double>::radix == 2,
94 "otherwise use scalbn");
Avery Musbach92a30e382022-09-08 23:30:4195 constexpr int kBits = std::numeric_limits<double>::digits;
96 return ldexp(bits & ((UINT64_C(1) << kBits) - 1u), -kBits);
[email protected]05f9b682008-09-29 22:18:0197}
98
Avery Musbacheff342b2022-10-06 18:36:0799float BitsToOpenEndedUnitIntervalF(uint64_t bits) {
100 // We try to get maximum precision by masking out as many bits as will fit
101 // in the target type's mantissa, and raising it to an appropriate power to
102 // produce output in the range [0, 1). For IEEE 754 floats, the mantissa is
103 // expected to accommodate 12 bits (including the implied bit).
104 static_assert(std::numeric_limits<float>::radix == 2, "otherwise use scalbn");
105 constexpr int kBits = std::numeric_limits<float>::digits;
106 return ldexpf(bits & ((UINT64_C(1) << kBits) - 1u), -kBits);
107}
108
Nico Weber0a3852a72015-10-29 20:42:58109uint64_t RandGenerator(uint64_t range) {
[email protected]0173b962011-08-24 19:58:36110 DCHECK_GT(range, 0u);
[email protected]af2e192b2011-05-30 17:39:09111 // We must discard random results above this number, as they would
112 // make the random generator non-uniform (consider e.g. if
[email protected]0173b962011-08-24 19:58:36113 // MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice
114 // as likely as a result of 3 or 4).
Nico Weber0a3852a72015-10-29 20:42:58115 uint64_t max_acceptable_value =
116 (std::numeric_limits<uint64_t>::max() / range) * range - 1;
[email protected]af2e192b2011-05-30 17:39:09117
Nico Weber0a3852a72015-10-29 20:42:58118 uint64_t value;
[email protected]af2e192b2011-05-30 17:39:09119 do {
120 value = base::RandUint64();
[email protected]0173b962011-08-24 19:58:36121 } while (value > max_acceptable_value);
[email protected]af2e192b2011-05-30 17:39:09122
[email protected]0173b962011-08-24 19:58:36123 return value % range;
[email protected]a74dcae2010-08-30 21:07:05124}
125
[email protected]51a01812011-05-05 08:46:11126std::string RandBytesAsString(size_t length) {
Daniel Cheng589602312024-02-09 17:50:51127 std::string result(length, '\0');
danakj95305d272024-05-09 20:38:44128 RandBytes(as_writable_byte_span(result));
[email protected]29548d82011-04-29 21:03:54129 return result;
130}
131
Tom Sepez230a75c62023-11-13 23:27:16132std::vector<uint8_t> RandBytesAsVector(size_t length) {
133 std::vector<uint8_t> result(length);
danakj95305d272024-05-09 20:38:44134 RandBytes(result);
Tom Sepez230a75c62023-11-13 23:27:16135 return result;
136}
137
Benoit Lize7532d4af2021-08-24 11:34:04138InsecureRandomGenerator::InsecureRandomGenerator() {
Benoit Lize73de21b2021-07-02 08:17:56139 a_ = base::RandUint64();
140 b_ = base::RandUint64();
Benoit Lize73de21b2021-07-02 08:17:56141}
142
Benoit Lize7532d4af2021-08-24 11:34:04143void InsecureRandomGenerator::ReseedForTesting(uint64_t seed) {
Benoit Lize73de21b2021-07-02 08:17:56144 a_ = seed;
145 b_ = seed;
Benoit Lize73de21b2021-07-02 08:17:56146}
147
Anthony Vallée-Dubois13bd8f62025-01-21 17:10:32148uint64_t InsecureRandomGenerator::RandUint64() const {
Benoit Lize73de21b2021-07-02 08:17:56149 // Using XorShift128+, which is simple and widely used. See
150 // https://en.wikipedia.org/wiki/Xorshift#xorshift+ for details.
151 uint64_t t = a_;
152 const uint64_t s = b_;
153
154 a_ = s;
155 t ^= t << 23;
156 t ^= t >> 17;
157 t ^= s ^ (s >> 26);
158 b_ = t;
159
160 return t + s;
161}
162
Anthony Vallée-Dubois13bd8f62025-01-21 17:10:32163uint32_t InsecureRandomGenerator::RandUint32() const {
Benoit Lize73de21b2021-07-02 08:17:56164 // The generator usually returns an uint64_t, truncate it.
165 //
166 // It is noted in this paper (https://arxiv.org/abs/1810.05313) that the
167 // lowest 32 bits fail some statistical tests from the Big Crush
168 // suite. Use the higher ones instead.
169 return this->RandUint64() >> 32;
170}
171
Anthony Vallée-Dubois13bd8f62025-01-21 17:10:32172double InsecureRandomGenerator::RandDouble() const {
Benoit Lized6377142021-07-05 10:17:16173 uint64_t x = RandUint64();
174 // From https://vigna.di.unimi.it/xorshift/.
175 // 53 bits of mantissa, hence the "hexadecimal exponent" 1p-53.
176 return (x >> 11) * 0x1.0p-53;
177}
178
Benoit Lizeee4fe1e42022-06-29 19:13:48179MetricsSubSampler::MetricsSubSampler() = default;
Anthony Vallée-Dubois13bd8f62025-01-21 17:10:32180bool MetricsSubSampler::ShouldSample(double probability) const {
Olivier Li Shing Tat-Dupuis9e5e7d92024-02-13 14:42:10181 if (g_subsampling_always_sample.load(std::memory_order_relaxed)) {
Olivier Lief2b23c2024-01-29 20:58:56182 return true;
183 }
Olivier Li Shing Tat-Dupuis9e5e7d92024-02-13 14:42:10184 if (g_subsampling_never_sample.load(std::memory_order_relaxed)) {
Olivier Lief2b23c2024-01-29 20:58:56185 return false;
186 }
187
Anand Ravib793ffb32025-02-25 22:56:54188 DCHECK(probability >= 0 && probability <= 1);
Olivier Lief2b23c2024-01-29 20:58:56189 return generator_.RandDouble() < probability;
François Doray87e35a82023-05-05 14:44:28190}
191
Anthony Vallée-Duboisecfdb382025-02-04 20:07:40192void MetricsSubSampler::Reseed() {
193 generator_ = InsecureRandomGenerator();
194}
195
Olivier Lief2b23c2024-01-29 20:58:56196MetricsSubSampler::ScopedAlwaysSampleForTesting::
197 ScopedAlwaysSampleForTesting() {
Olivier Li Shing Tat-Dupuis9e5e7d92024-02-13 14:42:10198 DCHECK(!g_subsampling_always_sample.load(std::memory_order_relaxed));
199 DCHECK(!g_subsampling_never_sample.load(std::memory_order_relaxed));
200 g_subsampling_always_sample.store(true, std::memory_order_relaxed);
François Doray87e35a82023-05-05 14:44:28201}
202
Olivier Lief2b23c2024-01-29 20:58:56203MetricsSubSampler::ScopedAlwaysSampleForTesting::
204 ~ScopedAlwaysSampleForTesting() {
Olivier Li Shing Tat-Dupuis9e5e7d92024-02-13 14:42:10205 DCHECK(g_subsampling_always_sample.load(std::memory_order_relaxed));
206 DCHECK(!g_subsampling_never_sample.load(std::memory_order_relaxed));
207 g_subsampling_always_sample.store(false, std::memory_order_relaxed);
Olivier Lief2b23c2024-01-29 20:58:56208}
209
210MetricsSubSampler::ScopedNeverSampleForTesting::ScopedNeverSampleForTesting() {
Olivier Li Shing Tat-Dupuis9e5e7d92024-02-13 14:42:10211 DCHECK(!g_subsampling_always_sample.load(std::memory_order_relaxed));
212 DCHECK(!g_subsampling_never_sample.load(std::memory_order_relaxed));
213 g_subsampling_never_sample.store(true, std::memory_order_relaxed);
Olivier Lief2b23c2024-01-29 20:58:56214}
215
216MetricsSubSampler::ScopedNeverSampleForTesting::~ScopedNeverSampleForTesting() {
217 DCHECK(!g_subsampling_always_sample);
218 DCHECK(g_subsampling_never_sample);
Olivier Li Shing Tat-Dupuis9e5e7d92024-02-13 14:42:10219 g_subsampling_never_sample.store(false, std::memory_order_relaxed);
Benoit Lizeee4fe1e42022-06-29 19:13:48220}
221
Anthony Vallée-Duboisecfdb382025-02-04 20:07:40222bool ShouldRecordSubsampledMetric(double probability) {
223 return GetSharedSubsampler()->ShouldSample(probability);
224}
225
226void ReseedSharedMetricsSubsampler() {
227 GetSharedSubsampler()->Reseed();
228}
229
[email protected]05f9b682008-09-29 22:18:01230} // namespace base