This source file includes following definitions.
- RUN_ALL_TESTS
- StringPrintf
- get
- get
- TEST
- AndersonDarlingInf
- AndersonDarlingErrFix
- AndersonDarlingPValue
- AndersonDarlingStatistic
- AndersonDarlingTest
- ADTestTest
- ADCDF
- TestNextRandom
- TEST
- TestPickNextSample
- TEST
- TestLRand64Spread
- TEST
- CheckMean
- OutputSequence
- StandardDeviationsErrorInSample
- TEST
- TEST
- Cleanup
- InitStatics
- Init
- PickNextSample
- SampleAllocation
- TEST
- TEST
- TEST
- test_arithmetic
- TEST
- TEST
- main
#include "config_for_unittests.h"
#include <stdlib.h>
#include <stdio.h>
#if defined HAVE_STDINT_H
#include <stdint.h>
#elif defined HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include <sys/types.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cmath>
#include "base/logging.h"
#include "base/commandlineflags.h"
#include "sampler.h"
using std::sort;
using std::min;
using std::max;
using std::vector;
using std::abs;
vector<void (*)()> g_testlist;
#define TEST(a, b) \
struct Test_##a##_##b { \
Test_##a##_##b() { g_testlist.push_back(&Run); } \
static void Run(); \
}; \
static Test_##a##_##b g_test_##a##_##b; \
void Test_##a##_##b::Run()
static int RUN_ALL_TESTS() {
vector<void (*)()>::const_iterator it;
for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
(*it)();
}
fprintf(stderr, "\nPassed %d tests\n\nPASS\n", (int)g_testlist.size());
return 0;
}
#undef LOG
#define LOG(level) std::cerr << "\n"
static std::string StringPrintf(const char* format, ...) {
char buf[256];
va_list ap;
va_start(ap, format);
perftools_vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
return buf;
}
namespace {
template<typename T> class scoped_array {
public:
scoped_array(T* p) : p_(p) { }
~scoped_array() { delete[] p_; }
const T* get() const { return p_; }
T* get() { return p_; }
T& operator[](int i) { return p_[i]; }
private:
T* p_;
};
}
static const double kSigmas = 4;
static const size_t kSamplingInterval = 512*1024;
TEST(Sampler, TestGetSamplePeriod) {
tcmalloc::Sampler sampler;
sampler.Init(1);
uint64_t sample_period;
sample_period = sampler.GetSamplePeriod();
CHECK_GT(sample_period, 0);
}
double AndersonDarlingInf(double z) {
if (z < 2) {
return exp(-1.2337141 / z) / sqrt(z) * (2.00012 + (0.247105 -
(0.0649821 - (0.0347962 - (0.011672 - 0.00168691
* z) * z) * z) * z) * z);
}
return exp( - exp(1.0776 - (2.30695 - (0.43424 - (0.082433 -
(0.008056 - 0.0003146 * z) * z) * z) * z) * z));
}
double AndersonDarlingErrFix(int n, double x) {
if (x > 0.8) {
return (-130.2137 + (745.2337 - (1705.091 - (1950.646 -
(1116.360 - 255.7844 * x) * x) * x) * x) * x) / n;
}
double cutoff = 0.01265 + 0.1757 / n;
double t;
if (x < cutoff) {
t = x / cutoff;
t = sqrt(t) * (1 - t) * (49 * t - 102);
return t * (0.0037 / (n * n) + 0.00078 / n + 0.00006) / n;
} else {
t = (x - cutoff) / (0.8 - cutoff);
t = -0.00022633 + (6.54034 - (14.6538 - (14.458 - (8.259 - 1.91864
* t) * t) * t) * t) * t;
return t * (0.04213 + 0.01365 / n) / n;
}
}
double AndersonDarlingPValue(int n, double z) {
double ad = AndersonDarlingInf(z);
double errfix = AndersonDarlingErrFix(n, ad);
return ad + errfix;
}
double AndersonDarlingStatistic(int n, double* random_sample) {
double ad_sum = 0;
for (int i = 0; i < n; i++) {
ad_sum += (2*i + 1) * log(random_sample[i] * (1 - random_sample[n-1-i]));
}
double ad_statistic = - n - 1/static_cast<double>(n) * ad_sum;
return ad_statistic;
}
double AndersonDarlingTest(int n, double* random_sample) {
double ad_statistic = AndersonDarlingStatistic(n, random_sample);
LOG(INFO) << StringPrintf("AD stat = %f, n=%d\n", ad_statistic, n);
double p = AndersonDarlingPValue(n, ad_statistic);
return p;
}
void ADTestTest(int n) {
scoped_array<double> random_sample(new double[n]);
for (int i = 0; i < n; i++) {
random_sample[i] = (i+0.01)/n;
}
sort(random_sample.get(), random_sample.get() + n);
double ad_stat = AndersonDarlingStatistic(n, random_sample.get());
LOG(INFO) << StringPrintf("Testing the AD test. n=%d, ad_stat = %f",
n, ad_stat);
}
void ADCDF() {
for (int i = 1; i < 40; i++) {
double x = i/10.0;
LOG(INFO) << "x= " << x << " adpv= "
<< AndersonDarlingPValue(100, x) << ", "
<< AndersonDarlingPValue(1000, x);
}
}
void TestNextRandom(int n) {
tcmalloc::Sampler sampler;
sampler.Init(1);
uint64_t x = 1;
uint64_t max_prng_value = static_cast<uint64_t>(1)<<48;
for (int i = 1; i <= 20; i++) {
x = sampler.NextRandom(x);
}
scoped_array<uint64_t> int_random_sample(new uint64_t[n]);
for (int i = 0; i < n; i++) {
int_random_sample[i] = x;
x = sampler.NextRandom(x);
}
sort(int_random_sample.get(), int_random_sample.get() + n);
scoped_array<double> random_sample(new double[n]);
for (int i = 0; i < n; i++) {
random_sample[i] = static_cast<double>(int_random_sample[i])/max_prng_value;
}
double ad_pvalue = AndersonDarlingTest(n, random_sample.get());
LOG(INFO) << StringPrintf("pvalue for AndersonDarlingTest "
"with n= %d is p= %f\n", n, ad_pvalue);
CHECK_GT(min(ad_pvalue, 1 - ad_pvalue), 0.0001);
}
TEST(Sampler, TestNextRandom_MultipleValues) {
TestNextRandom(10);
TestNextRandom(100);
TestNextRandom(1000);
TestNextRandom(10000);
}
void TestPickNextSample(int n) {
tcmalloc::Sampler sampler;
sampler.Init(1);
scoped_array<uint64_t> int_random_sample(new uint64_t[n]);
int sample_period = sampler.GetSamplePeriod();
int ones_count = 0;
for (int i = 0; i < n; i++) {
int_random_sample[i] = sampler.PickNextSamplingPoint();
CHECK_GE(int_random_sample[i], 1);
if (int_random_sample[i] == 1) {
ones_count += 1;
}
CHECK_LT(ones_count, 4);
}
sort(int_random_sample.get(), int_random_sample.get() + n);
scoped_array<double> random_sample(new double[n]);
for (int i = 0; i < n; i++) {
random_sample[i] = 1 - exp(-static_cast<double>(int_random_sample[i])
/ sample_period);
}
double geom_ad_pvalue = AndersonDarlingTest(n, random_sample.get());
LOG(INFO) << StringPrintf("pvalue for geometric AndersonDarlingTest "
"with n= %d is p= %f\n", n, geom_ad_pvalue);
CHECK_GT(min(geom_ad_pvalue, 1 - geom_ad_pvalue), 0.0001);
}
TEST(Sampler, TestPickNextSample_MultipleValues) {
TestPickNextSample(10);
TestPickNextSample(100);
TestPickNextSample(1000);
TestPickNextSample(10000);
}
void TestLRand64Spread() {
tcmalloc::Sampler sampler;
sampler.Init(1);
uint64_t current_value;
printf("Testing LRand64 Spread\n");
for (int i = 1; i < 10; i++) {
printf("%d ", i);
current_value = i;
for (int j = 1; j < 100; j++) {
current_value = sampler.NextRandom(current_value);
}
LOG(INFO) << current_value;
}
}
TEST(Sampler, FastLog2) {
tcmalloc::Sampler sampler;
sampler.Init(1);
double max_ratio_error = 0;
for (double d = -1021.9; d < 1; d+= 0.13124235) {
double e = pow(2.0, d);
double truelog = log(e) / log(2.0);
double fastlog = sampler.FastLog2(e);
max_ratio_error = max(max_ratio_error,
max(truelog/fastlog-1, fastlog/truelog-1));
CHECK_LE(max_ratio_error, 0.01);
}
LOG(INFO) << StringPrintf("Fastlog2: max_ratio_error = %f\n",
max_ratio_error);
}
bool CheckMean(size_t mean, int num_samples) {
tcmalloc::Sampler sampler;
sampler.Init(1);
size_t total = 0;
for (int i = 0; i < num_samples; i++) {
total += sampler.PickNextSamplingPoint();
}
double empirical_mean = total / static_cast<double>(num_samples);
double expected_sd = mean / pow(num_samples * 1.0, 0.5);
return(fabs(mean-empirical_mean) < expected_sd * kSigmas);
}
void OutputSequence(int sequence_length) {
tcmalloc::Sampler sampler;
sampler.Init(1);
size_t next_step;
for (int i = 0; i< sequence_length; i++) {
next_step = sampler.PickNextSamplingPoint();
LOG(INFO) << next_step;
}
}
double StandardDeviationsErrorInSample(
int total_samples, int picked_samples,
int alloc_size, int sampling_interval) {
double p = 1 - exp(-(static_cast<double>(alloc_size) / sampling_interval));
double expected_samples = total_samples * p;
double sd = pow(p*(1-p)*total_samples, 0.5);
return((picked_samples - expected_samples) / sd);
}
TEST(Sampler, LargeAndSmallAllocs_CombinedTest) {
tcmalloc::Sampler sampler;
sampler.Init(1);
int counter_big = 0;
int counter_small = 0;
int size_big = 129*8*1024+1;
int size_small = 1024*8;
int num_iters = 128*4*8;
for (int i = 0; i < num_iters; i++) {
if (sampler.SampleAllocation(size_big)) {
counter_big += 1;
}
for (int i = 0; i < 129; i++) {
if (sampler.SampleAllocation(size_small)) {
counter_small += 1;
}
}
}
double large_allocs_sds =
StandardDeviationsErrorInSample(num_iters, counter_big,
size_big, kSamplingInterval);
double small_allocs_sds =
StandardDeviationsErrorInSample(num_iters*129, counter_small,
size_small, kSamplingInterval);
LOG(INFO) << StringPrintf("large_allocs_sds = %f\n", large_allocs_sds);
LOG(INFO) << StringPrintf("small_allocs_sds = %f\n", small_allocs_sds);
CHECK_LE(fabs(large_allocs_sds), kSigmas);
CHECK_LE(fabs(small_allocs_sds), kSigmas);
}
TEST(Sampler, IsMeanRight) {
CHECK(CheckMean(kSamplingInterval, 1000));
}
const int64 FLAGS_mock_tcmalloc_sample_parameter = 1<<19;
class OldSampler {
public:
void Init(uint32_t seed);
void Cleanup() {}
bool SampleAllocation(size_t k);
void PickNextSample(size_t k);
static void InitStatics() {
sample_period = 1048583;
}
size_t bytes_until_sample_;
private:
uint32_t rnd_;
static uint64_t sample_period;
};
uint64_t OldSampler::sample_period;
void OldSampler::Init(uint32_t seed) {
if (seed != 0) {
rnd_ = seed;
} else {
rnd_ = 12345;
}
bytes_until_sample_ = 0;
for (int i = 0; i < 100; i++) {
PickNextSample(sample_period * 2);
}
};
void OldSampler::PickNextSample(size_t k) {
static const uint32_t kPoly = (1 << 22) | (1 << 2) | (1 << 1) | (1 << 0);
uint32_t r = rnd_;
rnd_ = (r << 1) ^ ((static_cast<int32_t>(r) >> 31) & kPoly);
const int flag_value = FLAGS_mock_tcmalloc_sample_parameter;
static int last_flag_value = -1;
if (flag_value != last_flag_value) {
sample_period = 1048583;
last_flag_value = flag_value;
}
bytes_until_sample_ += rnd_ % sample_period;
if (k > (static_cast<size_t>(-1) >> 2)) {
return;
}
while (bytes_until_sample_ < k) {
bytes_until_sample_ += (sample_period >> 1);
}
bytes_until_sample_ -= k;
}
inline bool OldSampler::SampleAllocation(size_t k) {
if (bytes_until_sample_ < k) {
PickNextSample(k);
return true;
} else {
bytes_until_sample_ -= k;
return false;
}
}
TEST(Sampler, bytes_until_sample_Overflow_Underflow) {
tcmalloc::Sampler sampler;
sampler.Init(1);
uint64_t one = 1;
uint64_t sample_parameter_array[4] = {0, 1, one<<19, one<<58};
for (int i = 0; i < 4; i++) {
uint64_t sample_parameter = sample_parameter_array[i];
LOG(INFO) << "sample_parameter = " << sample_parameter;
double sample_scaling = - log(2.0) * sample_parameter;
const uint64_t prng_mod_power = 48;
uint64_t largest_prng_value = (static_cast<uint64_t>(1)<<48) - 1;
double q = (largest_prng_value >> (prng_mod_power - 26)) + 1.0;
LOG(INFO) << StringPrintf("q = %f\n", q);
LOG(INFO) << StringPrintf("FastLog2(q) = %f\n", sampler.FastLog2(q));
LOG(INFO) << StringPrintf("log2(q) = %f\n", log(q)/log(2.0));
uint64_t smallest_sample_step
= static_cast<uint64_t>(min(sampler.FastLog2(q) - 26, 0.0)
* sample_scaling + 1);
LOG(INFO) << "Smallest sample step is " << smallest_sample_step;
uint64_t cutoff = static_cast<uint64_t>(10)
* (sample_parameter/(one<<24) + 1);
LOG(INFO) << "Acceptable value is < " << cutoff;
CHECK_LE(smallest_sample_step, cutoff);
uint64_t smallest_prng_value = 0;
q = (smallest_prng_value >> (prng_mod_power - 26)) + 1.0;
LOG(INFO) << StringPrintf("q = %f\n", q);
uint64_t largest_sample_step
= static_cast<uint64_t>(min(sampler.FastLog2(q) - 26, 0.0)
* sample_scaling + 1);
LOG(INFO) << "Largest sample step is " << largest_sample_step;
CHECK_LE(largest_sample_step, one<<63);
CHECK_GE(largest_sample_step, smallest_sample_step);
}
}
TEST(Sampler, NextRand_range) {
tcmalloc::Sampler sampler;
sampler.Init(1);
uint64_t one = 1;
uint64_t max_value = (one << 48) - 1;
uint64_t x = (one << 55);
int n = 22;
LOG(INFO) << "Running sampler.NextRandom 1<<" << n << " times";
for (int i = 1; i <= (1<<n); i++) {
x = sampler.NextRandom(x);
CHECK_LE(x, max_value);
}
}
TEST(Sampler, arithmetic_1) {
tcmalloc::Sampler sampler;
sampler.Init(1);
uint64_t rnd;
const uint64_t prng_mod_power = 48;
uint64_t one = 1;
rnd = one;
uint64_t max_value = (one << 48) - 1;
for (int i = 1; i <= (1>>27); i++) {
rnd = sampler.NextRandom(rnd);
CHECK_LE(rnd, max_value);
double q = (rnd >> (prng_mod_power - 26)) + 1.0;
CHECK_GE(q, 0);
}
for (int i = 1; i <= 66; i++) {
rnd = one << i;
double q = (rnd >> (prng_mod_power - 26)) + 1.0;
LOG(INFO) << "rnd = " << rnd << " i=" << i << " q=" << q;
CHECK_GE(q, 0);
}
}
void test_arithmetic(uint64_t rnd) {
const uint64_t prng_mod_power = 48;
uint64_t shifted_rnd = rnd >> (prng_mod_power - 26);
CHECK_GE(shifted_rnd, 0);
CHECK_LT(shifted_rnd, (1<<26));
LOG(INFO) << shifted_rnd;
LOG(INFO) << static_cast<double>(shifted_rnd);
CHECK_GE(static_cast<double>(static_cast<uint32_t>(shifted_rnd)), 0);
CHECK_GE(static_cast<double>(shifted_rnd), 0);
double q = static_cast<double>(shifted_rnd) + 1.0;
CHECK_GT(q, 0);
}
TEST(Sampler, arithmetic_2) {
uint64_t rnd = 227453640600554LL;
test_arithmetic(rnd);
}
TEST(Sample, size_of_class) {
tcmalloc::Sampler sampler;
sampler.Init(1);
LOG(INFO) << "Size of Sampler class is: " << sizeof(tcmalloc::Sampler);
LOG(INFO) << "Size of Sampler object is: " << sizeof(sampler);
}
DECLARE_int64(tcmalloc_sample_parameter);
int main(int argc, char **argv) {
if (FLAGS_tcmalloc_sample_parameter == 0)
FLAGS_tcmalloc_sample_parameter = 524288;
return RUN_ALL_TESTS();
}