Rewrote the PRNG using an xorshift* algorithm and moved the files from test/ to base/.

Created a simple unit test for the new random number generator. (It mostly tests
that the generated numbers are consistent with the intended distribution, e.g. uniform.
It is not a comprehensive test of the quality of the random numbers.)

Several assertions in OveruseDetectorTest seem to depend on the exact sequence of random numbers. I updated those numbers to work with the new PRNG.

Compute the standard deviation of the expected result in TestReorderFilter instead of passing an uncertainty parameter.

BUG=webrtc:5177

Review URL: https://codereview.webrtc.org/1457023002

Cr-Commit-Position: refs/heads/master@{#10965}
This commit is contained in:
terelius 2015-12-10 01:50:55 -08:00 committed by Commit bot
parent 0b3d7eec07
commit 84e78f9102
18 changed files with 496 additions and 190 deletions

View File

@ -134,6 +134,8 @@ static_library("rtc_base_approved") {
"platform_thread.cc",
"platform_thread.h",
"platform_thread_types.h",
"random.cc",
"random.h",
"safe_conversions.h",
"safe_conversions_impl.h",
"scoped_ptr.h",

View File

@ -88,6 +88,8 @@
'platform_thread.cc',
'platform_thread.h',
'platform_thread_types.h',
'random.cc',
'random.h',
'ratetracker.cc',
'ratetracker.h',
'safe_conversions.h',

View File

@ -84,6 +84,7 @@
'profiler_unittest.cc',
'proxy_unittest.cc',
'proxydetect_unittest.cc',
'random_unittest.cc',
'ratelimiter_unittest.cc',
'ratetracker_unittest.cc',
'referencecountedsingletonfactory_unittest.cc',

86
webrtc/base/random.cc Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/base/random.h"
#include <math.h>
#include "webrtc/base/checks.h"
namespace webrtc {
Random::Random(uint64_t seed) {
RTC_DCHECK(seed != 0x0ull);
state_ = seed;
}
uint32_t Random::Rand(uint32_t t) {
// Casting the output to 32 bits will give an almost uniform number.
// Pr[x=0] = (2^32-1) / (2^64-1)
// Pr[x=k] = 2^32 / (2^64-1) for k!=0
// Uniform would be Pr[x=k] = 2^32 / 2^64 for all 32-bit integers k.
uint32_t x = NextOutput();
// If x / 2^32 is uniform on [0,1), then x / 2^32 * (t+1) is uniform on
// the interval [0,t+1), so the integer part is uniform on [0,t].
uint64_t result = x * (static_cast<uint64_t>(t) + 1);
result >>= 32;
return result;
}
uint32_t Random::Rand(uint32_t low, uint32_t high) {
RTC_DCHECK(low <= high);
return Rand(high - low) + low;
}
int32_t Random::Rand(int32_t low, int32_t high) {
RTC_DCHECK(low <= high);
// We rely on subtraction (and addition) to be the same for signed and
// unsigned numbers in two-complement representation. Thus, although
// high - low might be negative as an int, it is the correct difference
// when interpreted as an unsigned.
return Rand(high - low) + low;
}
template <>
float Random::Rand<float>() {
double result = NextOutput() - 1;
result = result / 0xFFFFFFFFFFFFFFFEull;
return static_cast<float>(result);
}
template <>
double Random::Rand<double>() {
double result = NextOutput() - 1;
result = result / 0xFFFFFFFFFFFFFFFEull;
return result;
}
template <>
bool Random::Rand<bool>() {
return Rand(0, 1) == 1;
}
double Random::Gaussian(double mean, double standard_deviation) {
// Creating a Normal distribution variable from two independent uniform
// variables based on the Box-Muller transform, which is defined on the
// interval (0, 1]. Note that we rely on NextOutput to generate integers
// in the range [1, 2^64-1]. Normally this behavior is a bit frustrating,
// but here it is exactly what we need.
const double kPi = 3.14159265358979323846;
double u1 = static_cast<double>(NextOutput()) / 0xFFFFFFFFFFFFFFFFull;
double u2 = static_cast<double>(NextOutput()) / 0xFFFFFFFFFFFFFFFFull;
return mean + standard_deviation * sqrt(-2 * log(u1)) * cos(2 * kPi * u2);
}
double Random::Exponential(double lambda) {
double uniform = Rand<double>();
return -log(uniform) / lambda;
}
} // namespace webrtc

View File

@ -8,23 +8,23 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_TEST_RANDOM_H_
#define WEBRTC_TEST_RANDOM_H_
#ifndef WEBRTC_BASE_RANDOM_H_
#define WEBRTC_BASE_RANDOM_H_
#include <limits>
#include "webrtc/typedefs.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/checks.h"
namespace webrtc {
namespace test {
class Random {
public:
explicit Random(uint32_t seed);
explicit Random(uint64_t seed);
// Return pseudo-random integer of the specified type.
// We need to limit the size to 32 bits to keep the output close to uniform.
template <typename T>
T Rand() {
static_assert(std::numeric_limits<T>::is_integer &&
@ -32,7 +32,7 @@ class Random {
std::numeric_limits<T>::digits <= 32,
"Rand is only supported for built-in integer types that are "
"32 bits or smaller.");
return static_cast<T>(Rand(std::numeric_limits<uint32_t>::max()));
return static_cast<T>(NextOutput());
}
// Uniformly distributed pseudo-random number in the interval [0, t].
@ -41,18 +41,26 @@ class Random {
// Uniformly distributed pseudo-random number in the interval [low, high].
uint32_t Rand(uint32_t low, uint32_t high);
// Uniformly distributed pseudo-random number in the interval [low, high].
int32_t Rand(int32_t low, int32_t high);
// Normal Distribution.
int Gaussian(int mean, int standard_deviation);
double Gaussian(double mean, double standard_deviation);
// Exponential Distribution.
int Exponential(float lambda);
// TODO(solenberg): Random from histogram.
// template<typename T> int Distribution(const std::vector<T> histogram) {
double Exponential(double lambda);
private:
uint32_t a_;
uint32_t b_;
// Outputs a nonzero 64-bit random number.
uint64_t NextOutput() {
state_ ^= state_ >> 12;
state_ ^= state_ << 25;
state_ ^= state_ >> 27;
RTC_DCHECK(state_ != 0x0ULL);
return state_ * 2685821657736338717ull;
}
uint64_t state_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Random);
};
@ -61,11 +69,14 @@ class Random {
template <>
float Random::Rand<float>();
// Return pseudo-random number in the interval [0.0, 1.0).
template <>
double Random::Rand<double>();
// Return pseudo-random boolean value.
template <>
bool Random::Rand<bool>();
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_RANDOM_H_
#endif // WEBRTC_BASE_RANDOM_H_

View File

@ -0,0 +1,302 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <math.h>
#include <limits>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/random.h"
namespace webrtc {
namespace {
// Computes the positive remainder of x/n.
template <typename T>
T fdiv_remainder(T x, T n) {
RTC_CHECK_GE(n, static_cast<T>(0));
T remainder = x % n;
if (remainder < 0)
remainder += n;
return remainder;
}
} // namespace
// Sample a number of random integers of type T. Divide them into buckets
// based on the remainder when dividing by bucket_count and check that each
// bucket gets roughly the expected number of elements.
template <typename T>
void UniformBucketTest(T bucket_count, int samples, Random* prng) {
std::vector<int> buckets(bucket_count, 0);
uint64_t total_values = 1ull << (std::numeric_limits<T>::digits +
std::numeric_limits<T>::is_signed);
T upper_limit =
std::numeric_limits<T>::max() -
static_cast<T>(total_values % static_cast<uint64_t>(bucket_count));
ASSERT_GT(upper_limit, std::numeric_limits<T>::max() / 2);
for (int i = 0; i < samples; i++) {
T sample;
do {
// We exclude a few numbers from the range so that it is divisible by
// the number of buckets. If we are unlucky and hit one of the excluded
// numbers we just resample. Note that if the number of buckets is a
// power of 2, then we don't have to exclude anything.
sample = prng->Rand<T>();
} while (sample > upper_limit);
buckets[fdiv_remainder(sample, bucket_count)]++;
}
for (T i = 0; i < bucket_count; i++) {
// Expect the result to be within 3 standard deviations of the mean.
EXPECT_NEAR(buckets[i], samples / bucket_count,
3 * sqrt(samples / bucket_count));
}
}
TEST(RandomNumberGeneratorTest, BucketTestSignedChar) {
Random prng(7297352569824ull);
UniformBucketTest<signed char>(64, 640000, &prng);
UniformBucketTest<signed char>(11, 440000, &prng);
UniformBucketTest<signed char>(3, 270000, &prng);
}
TEST(RandomNumberGeneratorTest, BucketTestUnsignedChar) {
Random prng(7297352569824ull);
UniformBucketTest<unsigned char>(64, 640000, &prng);
UniformBucketTest<unsigned char>(11, 440000, &prng);
UniformBucketTest<unsigned char>(3, 270000, &prng);
}
TEST(RandomNumberGeneratorTest, BucketTestSignedShort) {
Random prng(7297352569824ull);
UniformBucketTest<int16_t>(64, 640000, &prng);
UniformBucketTest<int16_t>(11, 440000, &prng);
UniformBucketTest<int16_t>(3, 270000, &prng);
}
TEST(RandomNumberGeneratorTest, BucketTestUnsignedShort) {
Random prng(7297352569824ull);
UniformBucketTest<uint16_t>(64, 640000, &prng);
UniformBucketTest<uint16_t>(11, 440000, &prng);
UniformBucketTest<uint16_t>(3, 270000, &prng);
}
TEST(RandomNumberGeneratorTest, BucketTestSignedInt) {
Random prng(7297352569824ull);
UniformBucketTest<signed int>(64, 640000, &prng);
UniformBucketTest<signed int>(11, 440000, &prng);
UniformBucketTest<signed int>(3, 270000, &prng);
}
TEST(RandomNumberGeneratorTest, BucketTestUnsignedInt) {
Random prng(7297352569824ull);
UniformBucketTest<unsigned int>(64, 640000, &prng);
UniformBucketTest<unsigned int>(11, 440000, &prng);
UniformBucketTest<unsigned int>(3, 270000, &prng);
}
// The range of the random numbers is divided into bucket_count intervals
// of consecutive numbers. Check that approximately equally many numbers
// from each inteval are generated.
void BucketTestSignedInterval(unsigned int bucket_count,
unsigned int samples,
int32_t low,
int32_t high,
int sigma_level,
Random* prng) {
std::vector<unsigned int> buckets(bucket_count, 0);
ASSERT_GE(high, low);
ASSERT_GE(bucket_count, 2u);
uint32_t interval = static_cast<uint32_t>(high - low + 1);
uint32_t numbers_per_bucket;
if (interval == 0) {
// The computation high - low + 1 should be 2^32 but overflowed
// Hence, bucket_count must be a power of 2
ASSERT_EQ(bucket_count & (bucket_count - 1), 0u);
numbers_per_bucket = (0x80000000u / bucket_count) * 2;
} else {
ASSERT_EQ(interval % bucket_count, 0u);
numbers_per_bucket = interval / bucket_count;
}
for (unsigned int i = 0; i < samples; i++) {
int32_t sample = prng->Rand(low, high);
EXPECT_LE(low, sample);
EXPECT_GE(high, sample);
buckets[static_cast<uint32_t>(sample - low) / numbers_per_bucket]++;
}
for (unsigned int i = 0; i < bucket_count; i++) {
// Expect the result to be within 3 standard deviations of the mean,
// or more generally, within sigma_level standard deviations of the mean.
double mean = static_cast<double>(samples) / bucket_count;
EXPECT_NEAR(buckets[i], mean, sigma_level * sqrt(mean));
}
}
// The range of the random numbers is divided into bucket_count intervals
// of consecutive numbers. Check that approximately equally many numbers
// from each inteval are generated.
void BucketTestUnsignedInterval(unsigned int bucket_count,
unsigned int samples,
uint32_t low,
uint32_t high,
int sigma_level,
Random* prng) {
std::vector<unsigned int> buckets(bucket_count, 0);
ASSERT_GE(high, low);
ASSERT_GE(bucket_count, 2u);
uint32_t interval = static_cast<uint32_t>(high - low + 1);
uint32_t numbers_per_bucket;
if (interval == 0) {
// The computation high - low + 1 should be 2^32 but overflowed
// Hence, bucket_count must be a power of 2
ASSERT_EQ(bucket_count & (bucket_count - 1), 0u);
numbers_per_bucket = (0x80000000u / bucket_count) * 2;
} else {
ASSERT_EQ(interval % bucket_count, 0u);
numbers_per_bucket = interval / bucket_count;
}
for (unsigned int i = 0; i < samples; i++) {
uint32_t sample = prng->Rand(low, high);
EXPECT_LE(low, sample);
EXPECT_GE(high, sample);
buckets[static_cast<uint32_t>(sample - low) / numbers_per_bucket]++;
}
for (unsigned int i = 0; i < bucket_count; i++) {
// Expect the result to be within 3 standard deviations of the mean,
// or more generally, within sigma_level standard deviations of the mean.
double mean = static_cast<double>(samples) / bucket_count;
EXPECT_NEAR(buckets[i], mean, sigma_level * sqrt(mean));
}
}
TEST(RandomNumberGeneratorTest, UniformUnsignedInterval) {
Random prng(299792458ull);
BucketTestUnsignedInterval(2, 100000, 0, 1, 3, &prng);
BucketTestUnsignedInterval(7, 100000, 1, 14, 3, &prng);
BucketTestUnsignedInterval(11, 100000, 1000, 1010, 3, &prng);
BucketTestUnsignedInterval(100, 100000, 0, 99, 3, &prng);
BucketTestUnsignedInterval(2, 100000, 0, 4294967295, 3, &prng);
BucketTestUnsignedInterval(17, 100000, 455, 2147484110, 3, &prng);
// 99.7% of all samples will be within 3 standard deviations of the mean,
// but since we test 1000 buckets we allow an interval of 4 sigma.
BucketTestUnsignedInterval(1000, 1000000, 0, 2147483999, 4, &prng);
}
TEST(RandomNumberGeneratorTest, UniformSignedInterval) {
Random prng(66260695729ull);
BucketTestSignedInterval(2, 100000, 0, 1, 3, &prng);
BucketTestSignedInterval(7, 100000, -2, 4, 3, &prng);
BucketTestSignedInterval(11, 100000, 1000, 1010, 3, &prng);
BucketTestSignedInterval(100, 100000, 0, 99, 3, &prng);
BucketTestSignedInterval(2, 100000, std::numeric_limits<int32_t>::min(),
std::numeric_limits<int32_t>::max(), 3, &prng);
BucketTestSignedInterval(17, 100000, -1073741826, 1073741829, 3, &prng);
// 99.7% of all samples will be within 3 standard deviations of the mean,
// but since we test 1000 buckets we allow an interval of 4 sigma.
BucketTestSignedInterval(1000, 1000000, -352, 2147483647, 4, &prng);
}
// The range of the random numbers is divided into bucket_count intervals
// of consecutive numbers. Check that approximately equally many numbers
// from each inteval are generated.
void BucketTestFloat(unsigned int bucket_count,
unsigned int samples,
int sigma_level,
Random* prng) {
ASSERT_GE(bucket_count, 2u);
std::vector<unsigned int> buckets(bucket_count, 0);
for (unsigned int i = 0; i < samples; i++) {
uint32_t sample = bucket_count * prng->Rand<float>();
EXPECT_LE(0u, sample);
EXPECT_GE(bucket_count - 1, sample);
buckets[sample]++;
}
for (unsigned int i = 0; i < bucket_count; i++) {
// Expect the result to be within 3 standard deviations of the mean,
// or more generally, within sigma_level standard deviations of the mean.
double mean = static_cast<double>(samples) / bucket_count;
EXPECT_NEAR(buckets[i], mean, sigma_level * sqrt(mean));
}
}
TEST(RandomNumberGeneratorTest, UniformFloatInterval) {
Random prng(1380648813ull);
BucketTestFloat(100, 100000, 3, &prng);
// 99.7% of all samples will be within 3 standard deviations of the mean,
// but since we test 1000 buckets we allow an interval of 4 sigma.
// BucketTestSignedInterval(1000, 1000000, -352, 2147483647, 4, &prng);
}
TEST(RandomNumberGeneratorTest, SignedHasSameBitPattern) {
Random prng_signed(66738480ull), prng_unsigned(66738480ull);
for (int i = 0; i < 1000; i++) {
signed int s = prng_signed.Rand<signed int>();
unsigned int u = prng_unsigned.Rand<unsigned int>();
EXPECT_EQ(u, static_cast<unsigned int>(s));
}
for (int i = 0; i < 1000; i++) {
int16_t s = prng_signed.Rand<int16_t>();
uint16_t u = prng_unsigned.Rand<uint16_t>();
EXPECT_EQ(u, static_cast<uint16_t>(s));
}
for (int i = 0; i < 1000; i++) {
signed char s = prng_signed.Rand<signed char>();
unsigned char u = prng_unsigned.Rand<unsigned char>();
EXPECT_EQ(u, static_cast<unsigned char>(s));
}
}
TEST(RandomNumberGeneratorTest, Gaussian) {
const int kN = 100000;
const int kBuckets = 100;
const double kMean = 49;
const double kStddev = 10;
Random prng(1256637061);
std::vector<unsigned int> buckets(kBuckets, 0);
for (int i = 0; i < kN; i++) {
int index = prng.Gaussian(kMean, kStddev) + 0.5;
if (index >= 0 && index < kBuckets) {
buckets[index]++;
}
}
const double kPi = 3.14159265358979323846;
const double kScale = 1 / (kStddev * sqrt(2.0 * kPi));
const double kDiv = -2.0 * kStddev * kStddev;
for (int n = 0; n < kBuckets; ++n) {
// Use Simpsons rule to estimate the probability that a random gaussian
// sample is in the interval [n-0.5, n+0.5].
double f_left = kScale * exp((n - kMean - 0.5) * (n - kMean - 0.5) / kDiv);
double f_mid = kScale * exp((n - kMean) * (n - kMean) / kDiv);
double f_right = kScale * exp((n - kMean + 0.5) * (n - kMean + 0.5) / kDiv);
double normal_dist = (f_left + 4 * f_mid + f_right) / 6;
// Expect the number of samples to be within 3 standard deviations
// (rounded up) of the expected number of samples in the bucket.
EXPECT_NEAR(buckets[n], kN * normal_dist, 3 * sqrt(kN * normal_dist) + 1);
}
}
} // namespace webrtc

View File

@ -17,6 +17,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/buffer.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/random.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/thread.h"
#include "webrtc/call.h"
@ -24,7 +25,6 @@
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/test/random.h"
#include "webrtc/test/test_suite.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/test/testsupport/gtest_disable.h"
@ -301,7 +301,7 @@ size_t GenerateRtpPacket(uint32_t extensions_bitvector,
uint32_t csrcs_count,
uint8_t* packet,
size_t packet_size,
test::Random* prng) {
Random* prng) {
RTC_CHECK_GE(packet_size, 16 + 4 * csrcs_count + 4 * kNumExtensions);
Clock* clock = Clock::GetRealTimeClock();
@ -349,7 +349,7 @@ size_t GenerateRtpPacket(uint32_t extensions_bitvector,
return header_size;
}
rtc::scoped_ptr<rtcp::RawPacket> GenerateRtcpPacket(test::Random* prng) {
rtc::scoped_ptr<rtcp::RawPacket> GenerateRtcpPacket(Random* prng) {
rtcp::ReportBlock report_block;
report_block.To(prng->Rand<uint32_t>()); // Remote SSRC.
report_block.WithFractionLost(prng->Rand(50));
@ -366,7 +366,7 @@ rtc::scoped_ptr<rtcp::RawPacket> GenerateRtcpPacket(test::Random* prng) {
void GenerateVideoReceiveConfig(uint32_t extensions_bitvector,
VideoReceiveStream::Config* config,
test::Random* prng) {
Random* prng) {
// Create a map from a payload type to an encoder name.
VideoReceiveStream::Decoder decoder;
decoder.payload_type = prng->Rand(0, 127);
@ -395,7 +395,7 @@ void GenerateVideoReceiveConfig(uint32_t extensions_bitvector,
void GenerateVideoSendConfig(uint32_t extensions_bitvector,
VideoSendStream::Config* config,
test::Random* prng) {
Random* prng) {
// Create a map from a payload type to an encoder name.
config->encoder_settings.payload_type = prng->Rand(0, 127);
config->encoder_settings.payload_name = (prng->Rand<bool>() ? "VP8" : "H264");
@ -434,7 +434,7 @@ void LogSessionAndReadBack(size_t rtp_count,
VideoReceiveStream::Config receiver_config(nullptr);
VideoSendStream::Config sender_config(nullptr);
test::Random prng(random_seed);
Random prng(random_seed);
// Create rtp_count RTP packets containing random data.
for (size_t i = 0; i < rtp_count; i++) {
@ -591,7 +591,7 @@ TEST(RtcEventLogTest, LogSessionAndReadBack) {
1 + csrcs_count, // Number of BWE loss events.
extensions, // Bit vector choosing extensions.
csrcs_count, // Number of contributing sources.
extensions + csrcs_count); // Random seed.
extensions * 3 + csrcs_count + 1); // Random seed.
}
}
}
@ -609,7 +609,7 @@ void DropOldEvents(uint32_t extensions_bitvector,
VideoReceiveStream::Config receiver_config(nullptr);
VideoSendStream::Config sender_config(nullptr);
test::Random prng(random_seed);
Random prng(random_seed);
// Create two RTP packets containing random data.
size_t packet_size = prng.Rand(1000, 1100);

View File

@ -18,11 +18,11 @@
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/event.h"
#include "webrtc/base/platform_thread.h"
#include "webrtc/base/random.h"
#include "webrtc/config.h"
#include "webrtc/modules/audio_processing/test/test_utils.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/system_wrappers/include/sleep.h"
#include "webrtc/test/random.h"
namespace webrtc {
@ -84,7 +84,7 @@ class RandomGenerator {
private:
rtc::CriticalSection crit_;
test::Random rand_gen_ GUARDED_BY(crit_);
Random rand_gen_ GUARDED_BY(crit_);
};
// Variables related to the audio data and formats.

View File

@ -36,7 +36,7 @@ class BweSimulation : public BweTest,
VerboseLogging(true);
}
test::Random random_;
Random random_;
private:
RTC_DISALLOW_COPY_AND_ASSIGN(BweSimulation);

View File

@ -14,6 +14,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/random.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/remote_bitrate_estimator/inter_arrival.h"
@ -21,7 +22,6 @@
#include "webrtc/modules/remote_bitrate_estimator/overuse_estimator.h"
#include "webrtc/modules/remote_bitrate_estimator/rate_statistics.h"
#include "webrtc/test/field_trial.h"
#include "webrtc/test/random.h"
#include "webrtc/test/testsupport/gtest_disable.h"
namespace webrtc {
@ -38,7 +38,7 @@ class OveruseDetectorTest : public ::testing::Test {
overuse_detector_(),
overuse_estimator_(new OveruseEstimator(options_)),
inter_arrival_(new InterArrival(5 * 90, kRtpTimestampToMs, true)),
random_(1234) {}
random_(123456789) {}
protected:
void SetUp() override {
@ -55,9 +55,10 @@ class OveruseDetectorTest : public ::testing::Test {
}
rtp_timestamp_ += mean_ms * 90;
now_ms_ += mean_ms;
receive_time_ms_ =
std::max(receive_time_ms_,
now_ms_ + random_.Gaussian(0, standard_deviation_ms));
receive_time_ms_ = std::max<int64_t>(
receive_time_ms_,
now_ms_ + static_cast<int64_t>(
random_.Gaussian(0, standard_deviation_ms) + 0.5));
if (kBwOverusing == overuse_detector_->State()) {
if (last_overuse + 1 != i) {
unique_overuse++;
@ -77,9 +78,10 @@ class OveruseDetectorTest : public ::testing::Test {
}
rtp_timestamp_ += mean_ms * 90;
now_ms_ += mean_ms + drift_per_frame_ms;
receive_time_ms_ =
std::max(receive_time_ms_,
now_ms_ + random_.Gaussian(0, standard_deviation_ms));
receive_time_ms_ = std::max<int64_t>(
receive_time_ms_,
now_ms_ + static_cast<int64_t>(
random_.Gaussian(0, standard_deviation_ms) + 0.5));
if (kBwOverusing == overuse_detector_->State()) {
return i + 1;
}
@ -114,7 +116,7 @@ class OveruseDetectorTest : public ::testing::Test {
rtc::scoped_ptr<OveruseDetector> overuse_detector_;
rtc::scoped_ptr<OveruseEstimator> overuse_estimator_;
rtc::scoped_ptr<InterArrival> inter_arrival_;
test::Random random_;
Random random_;
};
TEST_F(OveruseDetectorTest, GaussianRandom) {
@ -222,7 +224,7 @@ TEST_F(OveruseDetectorTest, DISABLED_OveruseWithHighVariance100Kbit10fps) {
UpdateDetector(rtp_timestamp, now_ms_, packet_size);
rtp_timestamp += frame_duration_ms * 90;
if (i % 2) {
offset = rand() % 50;
offset = random_.Rand(0, 49);
now_ms_ += frame_duration_ms - offset;
} else {
now_ms_ += frame_duration_ms + offset;
@ -254,7 +256,7 @@ TEST_F(OveruseDetectorTest, DISABLED_OveruseWithLowVariance100Kbit10fps) {
UpdateDetector(rtp_timestamp, now_ms_, packet_size);
rtp_timestamp += frame_duration_ms * 90;
if (i % 2) {
offset = rand() % 2;
offset = random_.Rand(0, 1);
now_ms_ += frame_duration_ms - offset;
} else {
now_ms_ += frame_duration_ms + offset;
@ -290,7 +292,7 @@ TEST_F(OveruseDetectorTest, OveruseWithLowVariance2000Kbit30fps) {
UpdateDetector(rtp_timestamp, now_ms_, packet_size);
rtp_timestamp += frame_duration_ms * 90;
if (i % 2) {
offset = rand() % 2;
offset = random_.Rand(0, 1);
now_ms_ += frame_duration_ms - offset;
} else {
now_ms_ += frame_duration_ms + offset;
@ -323,10 +325,10 @@ TEST_F(OveruseDetectorTest,
int sigma_ms = 3;
int unique_overuse = Run100000Samples(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms);
EXPECT_EQ(13, unique_overuse);
EXPECT_EQ(1, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(14, frames_until_overuse);
EXPECT_EQ(13, frames_until_overuse);
}
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift30Kbit3fps) {
@ -337,7 +339,7 @@ TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift30Kbit3fps) {
int sigma_ms = 3;
int unique_overuse = Run100000Samples(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms);
EXPECT_EQ(13, unique_overuse);
EXPECT_EQ(1, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(4, frames_until_overuse);
@ -351,10 +353,10 @@ TEST_F(OveruseDetectorTest, HighGaussianVariance30Kbit3fps) {
int sigma_ms = 10;
int unique_overuse = Run100000Samples(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms);
EXPECT_EQ(46, unique_overuse);
EXPECT_EQ(1, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(42, frames_until_overuse);
EXPECT_EQ(32, frames_until_overuse);
}
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift30Kbit3fps) {
@ -365,7 +367,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift30Kbit3fps) {
int sigma_ms = 10;
int unique_overuse = Run100000Samples(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms);
EXPECT_EQ(46, unique_overuse);
EXPECT_EQ(1, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(4, frames_until_overuse);
@ -380,10 +382,10 @@ TEST_F(OveruseDetectorTest,
int sigma_ms = 3;
int unique_overuse = Run100000Samples(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms);
EXPECT_EQ(12, unique_overuse);
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(12, frames_until_overuse);
EXPECT_EQ(13, frames_until_overuse);
}
TEST_F(OveruseDetectorTest,
@ -395,10 +397,10 @@ TEST_F(OveruseDetectorTest,
int sigma_ms = 10;
int unique_overuse = Run100000Samples(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms);
EXPECT_EQ(16, unique_overuse);
EXPECT_EQ(1, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(37, frames_until_overuse);
EXPECT_EQ(32, frames_until_overuse);
}
TEST_F(OveruseDetectorTest,
@ -410,10 +412,10 @@ TEST_F(OveruseDetectorTest,
int sigma_ms = 3;
int unique_overuse = Run100000Samples(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms);
EXPECT_EQ(12, unique_overuse);
EXPECT_EQ(1, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(12, frames_until_overuse);
EXPECT_EQ(13, frames_until_overuse);
}
TEST_F(OveruseDetectorTest,
@ -425,10 +427,10 @@ TEST_F(OveruseDetectorTest,
int sigma_ms = 10;
int unique_overuse = Run100000Samples(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms);
EXPECT_EQ(12, unique_overuse);
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(37, frames_until_overuse);
EXPECT_EQ(32, frames_until_overuse);
}
TEST_F(OveruseDetectorTest,
@ -443,7 +445,7 @@ TEST_F(OveruseDetectorTest,
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(14, frames_until_overuse);
EXPECT_EQ(15, frames_until_overuse);
}
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift300Kbit30fps) {
@ -471,7 +473,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVariance300Kbit30fps) {
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(49, frames_until_overuse);
EXPECT_EQ(41, frames_until_overuse);
}
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift300Kbit30fps) {
@ -485,7 +487,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift300Kbit30fps) {
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(8, frames_until_overuse);
EXPECT_EQ(10, frames_until_overuse);
}
TEST_F(OveruseDetectorTest,
@ -500,7 +502,7 @@ TEST_F(OveruseDetectorTest,
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(14, frames_until_overuse);
EXPECT_EQ(15, frames_until_overuse);
}
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift1000Kbit30fps) {
@ -528,7 +530,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVariance1000Kbit30fps) {
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(49, frames_until_overuse);
EXPECT_EQ(41, frames_until_overuse);
}
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift1000Kbit30fps) {
@ -542,7 +544,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift1000Kbit30fps) {
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(8, frames_until_overuse);
EXPECT_EQ(10, frames_until_overuse);
}
TEST_F(OveruseDetectorTest,
@ -557,7 +559,7 @@ TEST_F(OveruseDetectorTest,
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(14, frames_until_overuse);
EXPECT_EQ(15, frames_until_overuse);
}
TEST_F(OveruseDetectorTest, LowGaussianVarianceFastDrift2000Kbit30fps) {
@ -585,7 +587,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVariance2000Kbit30fps) {
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(49, frames_until_overuse);
EXPECT_EQ(41, frames_until_overuse);
}
TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift2000Kbit30fps) {
@ -599,7 +601,7 @@ TEST_F(OveruseDetectorTest, HighGaussianVarianceFastDrift2000Kbit30fps) {
EXPECT_EQ(0, unique_overuse);
int frames_until_overuse = RunUntilOveruse(packets_per_frame, packet_size,
frame_duration_ms, sigma_ms, drift_per_frame_ms);
EXPECT_EQ(8, frames_until_overuse);
EXPECT_EQ(10, frames_until_overuse);
}
class OveruseDetectorExperimentTest : public OveruseDetectorTest {

View File

@ -948,7 +948,7 @@ std::vector<int> BweTest::GetFileSizesBytes(int num_files) {
const int kMinKbytes = 100;
const int kMaxKbytes = 1000;
test::Random random(0x12345678);
Random random(0x12345678);
std::vector<int> tcp_file_sizes_bytes;
while (num_files-- > 0) {
@ -961,7 +961,7 @@ std::vector<int> BweTest::GetFileSizesBytes(int num_files) {
std::vector<int64_t> BweTest::GetStartingTimesMs(int num_files) {
// OFF state behaves as an exp. distribution with mean = 10 seconds.
const float kMeanMs = 10000.0f;
test::Random random(0x12345678);
Random random(0x12345678);
std::vector<int64_t> tcp_starting_times_ms;

View File

@ -391,7 +391,7 @@ void JitterFilter::SetMaxJitter(int64_t max_jitter_ms) {
}
namespace {
inline int64_t TruncatedNSigmaGaussian(test::Random* const random,
inline int64_t TruncatedNSigmaGaussian(Random* const random,
int64_t mean,
int64_t std_dev) {
int64_t gaussian_random = random->Gaussian(mean, std_dev);

View File

@ -22,6 +22,7 @@
#include <vector>
#include "webrtc/base/common.h"
#include "webrtc/base/random.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
#include "webrtc/modules/include/module_common_types.h"
@ -31,7 +32,6 @@
#include "webrtc/modules/remote_bitrate_estimator/test/packet.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/test/random.h"
namespace webrtc {
@ -265,7 +265,7 @@ class LossFilter : public PacketProcessor {
virtual void RunFor(int64_t time_ms, Packets* in_out);
private:
test::Random random_;
Random random_;
float loss_fraction_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(LossFilter);
@ -299,7 +299,7 @@ class JitterFilter : public PacketProcessor {
int64_t MeanUs();
private:
test::Random random_;
Random random_;
int64_t stddev_jitter_us_;
int64_t last_send_time_us_;
bool reordering_; // False by default.
@ -318,7 +318,7 @@ class ReorderFilter : public PacketProcessor {
virtual void RunFor(int64_t time_ms, Packets* in_out);
private:
test::Random random_;
Random random_;
float reorder_fraction_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ReorderFilter);

View File

@ -22,39 +22,6 @@ namespace webrtc {
namespace testing {
namespace bwe {
TEST(BweTestFramework_RandomTest, Gaussian) {
enum {
kN = 100000,
kBuckets = 100,
kMean = 49,
kStddev = 10
};
test::Random random(0x12345678);
int buckets[kBuckets] = {0};
for (int i = 0; i < kN; ++i) {
int index = random.Gaussian(kMean, kStddev);
if (index >= 0 && index < kBuckets) {
buckets[index]++;
}
}
const double kPi = 3.14159265358979323846;
const double kScale = kN / (kStddev * sqrt(2.0 * kPi));
const double kDiv = -2.0 * kStddev * kStddev;
double self_corr = 0.0;
double bucket_corr = 0.0;
for (int n = 0; n < kBuckets; ++n) {
double normal_dist = kScale * exp((n - kMean) * (n - kMean) / kDiv);
self_corr += normal_dist * normal_dist;
bucket_corr += normal_dist * buckets[n];
}
printf("Correlation: %f (random sample), %f (self), %f (quotient)\n",
bucket_corr, self_corr, bucket_corr / self_corr);
EXPECT_NEAR(1.0, bucket_corr / self_corr, 0.0004);
}
static bool IsSequenceNumberSorted(const Packets& packets) {
PacketsConstIt last_it = packets.begin();
for (PacketsConstIt it = last_it; it != packets.end(); ++it) {
@ -533,7 +500,7 @@ TEST(BweTestFramework_JitterFilterTest, Jitter1031) {
TestJitterFilter(1031);
}
static void TestReorderFilter(uint16_t reorder_percent, uint16_t near_value) {
static void TestReorderFilter(uint16_t reorder_percent) {
const uint16_t kPacketCount = 10000;
// Generate packets with 10 ms interval.
@ -559,16 +526,23 @@ static void TestReorderFilter(uint16_t reorder_percent, uint16_t near_value) {
for (auto* packet : packets) {
const MediaPacket* media_packet = static_cast<const MediaPacket*>(packet);
uint16_t sequence_number = media_packet->header().sequenceNumber;
// The expected position for sequence number s is in position s-1.
if (sequence_number < last_sequence_number) {
distance += last_sequence_number - sequence_number;
}
last_sequence_number = sequence_number;
}
// Because reordering is random, we allow a threshold when comparing. The
// maximum distance a packet can be moved is PacketCount - 1.
EXPECT_NEAR(
((kPacketCount - 1) * reorder_percent) / 100, distance, near_value);
// The probability that two elements are swapped is p = reorder_percent / 100.
double p = static_cast<double>(reorder_percent) / 100;
// The expected number of swaps we perform is p * (PacketCount - 1),
// and each swap increases the distance by one.
double mean = p * (kPacketCount - 1);
// If pair i is chosen to be swapped with probability p, the variance for that
// pair is p * (1 - p). Since there are (kPacketCount - 1) independent pairs,
// the variance for the number of swaps is (kPacketCount - 1) * p * (1 - p).
double std_deviation = sqrt((kPacketCount - 1) * p * (1 - p));
EXPECT_NEAR(mean, distance, 3 * std_deviation);
for (auto* packet : packets)
delete packet;
@ -576,23 +550,23 @@ static void TestReorderFilter(uint16_t reorder_percent, uint16_t near_value) {
TEST(BweTestFramework_ReorderFilterTest, Reorder0) {
// For 0% reordering, no packets should have been moved, so result is exact.
TestReorderFilter(0, 0);
TestReorderFilter(0);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder10) {
TestReorderFilter(10, 30);
TestReorderFilter(10);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder20) {
TestReorderFilter(20, 20);
TestReorderFilter(20);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder50) {
TestReorderFilter(50, 20);
TestReorderFilter(50);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder70) {
TestReorderFilter(70, 20);
TestReorderFilter(70);
}
TEST(BweTestFramework_ReorderFilterTest, Reorder100) {
@ -600,7 +574,7 @@ TEST(BweTestFramework_ReorderFilterTest, Reorder100) {
// adjacent packets, when the likelihood of a swap is 1.0, a swap will always
// occur, so the stream will be in order except for the first packet, which
// has been moved to the end. Therefore we expect the result to be exact here.
TestReorderFilter(100.0, 0);
TestReorderFilter(100.0);
}
class BweTestFramework_ChokeFilterTest : public ::testing::Test {

View File

@ -13,7 +13,7 @@
#include <limits>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/test/random.h"
#include "webrtc/base/random.h"
using webrtc::rtcp::ReportBlock;
@ -42,7 +42,7 @@ TEST(RtcpPacketReportBlockTest, ParseChecksLength) {
TEST(RtcpPacketReportBlockTest, ParseAnyData) {
uint8_t buffer[kBufferLength];
// Fill buffer with semi-random data.
test::Random generator(testing::FLAGS_gtest_random_seed);
Random generator(0x256F8A285EC829ull);
for (size_t i = 0; i < kBufferLength; ++i)
buffer[i] = static_cast<uint8_t>(generator.Rand(0, 0xff));

View File

@ -1,72 +0,0 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/test/random.h"
#include <math.h>
#include "webrtc/base/checks.h"
namespace webrtc {
namespace test {
Random::Random(uint32_t seed) : a_(0x531FDB97 ^ seed), b_(0x6420ECA8 + seed) {
}
uint32_t Random::Rand(uint32_t t) {
// If b / 2^32 is uniform on [0,1), then b / 2^32 * (t+1) is uniform on
// the interval [0,t+1), so the integer part is uniform on [0,t].
uint64_t result = b_ * (static_cast<uint64_t>(t) + 1);
result >>= 32;
a_ ^= b_;
b_ += a_;
return result;
}
uint32_t Random::Rand(uint32_t low, uint32_t high) {
RTC_DCHECK(low <= high);
return Rand(high - low) + low;
}
template <>
float Random::Rand<float>() {
const double kScale = 1.0f / (static_cast<uint64_t>(1) << 32);
double result = kScale * b_;
a_ ^= b_;
b_ += a_;
return static_cast<float>(result);
}
template <>
bool Random::Rand<bool>() {
return Rand(0, 1) == 1;
}
int Random::Gaussian(int mean, int standard_deviation) {
// Creating a Normal distribution variable from two independent uniform
// variables based on the Box-Muller transform, which is defined on the
// interval (0, 1], hence the mask+add below.
const double kPi = 3.14159265358979323846;
const double kScale = 1.0 / 0x80000000ul;
double u1 = kScale * ((a_ & 0x7ffffffful) + 1);
double u2 = kScale * ((b_ & 0x7ffffffful) + 1);
a_ ^= b_;
b_ += a_;
return static_cast<int>(
mean + standard_deviation * sqrt(-2 * log(u1)) * cos(2 * kPi * u2));
}
int Random::Exponential(float lambda) {
float uniform = Rand<float>();
return static_cast<int>(-log(uniform) / lambda);
}
} // namespace test
} // namespace webrtc

View File

@ -41,8 +41,6 @@
'mock_voice_engine.h',
'null_transport.cc',
'null_transport.h',
'random.cc',
'random.h',
'rtp_rtcp_observer.h',
'run_loop.cc',
'run_loop.h',

View File

@ -9,11 +9,11 @@
*/
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/random.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/system_wrappers/include/sleep.h"
#include "webrtc/test/channel_transport/channel_transport.h"
#include "webrtc/test/random.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/voice_engine/test/auto_test/voe_standard_test.h"
@ -27,7 +27,7 @@ const webrtc::CodecInst kCodecInst = {120, "opus", 48000, 960, 2, 64000};
namespace voetest {
using webrtc::test::Random;
using webrtc::Random;
using webrtc::test::VoiceChannelTransport;
// This test allows a check on the output signal in an end-to-end call.