| // Copyright (c) 2008, Google Inc. | 
 | // All rights reserved. | 
 | //  | 
 | // Redistribution and use in source and binary forms, with or without | 
 | // modification, are permitted provided that the following conditions are | 
 | // met: | 
 | //  | 
 | //     * Redistributions of source code must retain the above copyright | 
 | // notice, this list of conditions and the following disclaimer. | 
 | //     * Redistributions in binary form must reproduce the above | 
 | // copyright notice, this list of conditions and the following disclaimer | 
 | // in the documentation and/or other materials provided with the | 
 | // distribution. | 
 | //     * Neither the name of Google Inc. nor the names of its | 
 | // contributors may be used to endorse or promote products derived from | 
 | // this software without specific prior written permission. | 
 | //  | 
 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  | 
 | // --- | 
 | // All Rights Reserved. | 
 | // | 
 | // Author: Daniel Ford | 
 | // | 
 | // Checks basic properties of the sampler | 
 |  | 
 | #include "config_for_unittests.h" | 
 | #include <stdlib.h>        // defines posix_memalign | 
 | #include <stdio.h>         // for the printf at the end | 
 | #if defined HAVE_STDINT_H | 
 | #include <stdint.h>             // to get uintptr_t | 
 | #elif defined HAVE_INTTYPES_H | 
 | #include <inttypes.h>           // another place uintptr_t might be defined | 
 | #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"       // The Sampler class being tested | 
 |  | 
 | using std::sort; | 
 | using std::min; | 
 | using std::max; | 
 | using std::vector; | 
 | using std::abs; | 
 |  | 
 | vector<void (*)()> g_testlist;  // the tests to run | 
 |  | 
 | #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)();   // The test will error-exit if there's a problem. | 
 |   } | 
 |   fprintf(stderr, "\nPassed %d tests\n\nPASS\n", (int)g_testlist.size()); | 
 |   return 0; | 
 | } | 
 |  | 
 | #undef LOG   // defined in base/logging.h | 
 | // Ideally, we'd put the newline at the end, but this hack puts the | 
 | // newline at the end of the previous log message, which is good enough :-) | 
 | #define LOG(level)  std::cerr << "\n" | 
 |  | 
 | static std::string StringPrintf(const char* format, ...) { | 
 |   char buf[256];   // should be big enough for all logging | 
 |   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_; | 
 | }; | 
 | } | 
 |  | 
 | // Note that these tests are stochastic. | 
 | // This mean that the chance of correct code passing the test is, | 
 | // in the case of 5 standard deviations: | 
 | // kSigmas=5:    ~99.99994267% | 
 | // in the case of 4 standard deviations: | 
 | // kSigmas=4:    ~99.993666% | 
 | static const double kSigmas = 4; | 
 | static const size_t kSamplingInterval = 512*1024; | 
 |  | 
 | // Tests that GetSamplePeriod returns the expected value | 
 | // which is 1<<19 | 
 | TEST(Sampler, TestGetSamplePeriod) { | 
 |   tcmalloc::Sampler sampler; | 
 |   sampler.Init(1); | 
 |   uint64_t sample_period; | 
 |   sample_period = sampler.GetSamplePeriod(); | 
 |   CHECK_GT(sample_period, 0); | 
 | } | 
 |  | 
 | // Tests of the quality of the random numbers generated | 
 | // This uses the Anderson Darling test for uniformity. | 
 | // See "Evaluating the Anderson-Darling Distribution" by Marsaglia | 
 | // for details. | 
 |  | 
 | // Short cut version of ADinf(z), z>0 (from Marsaglia) | 
 | // This returns the p-value for Anderson Darling statistic in | 
 | // the limit as n-> infinity. For finite n, apply the error fix below. | 
 | 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)); | 
 | } | 
 |  | 
 | // Corrects the approximation error in AndersonDarlingInf for small values of n | 
 | // Add this to AndersonDarlingInf to get a better approximation | 
 | // (from Marsaglia) | 
 | 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; | 
 |   } | 
 | } | 
 |  | 
 | // Returns the AndersonDarling p-value given n and the value of the statistic | 
 | 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; | 
 | } | 
 |  | 
 | // Tests if the array of doubles is uniformly distributed. | 
 | // Returns the p-value of the Anderson Darling Statistic | 
 | // for the given set of sorted random doubles | 
 | // See "Evaluating the Anderson-Darling Distribution" by | 
 | // Marsaglia and Marsaglia for details. | 
 | 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; | 
 | } | 
 |  | 
 | // Test the AD Test. The value of the statistic should go to zero as n->infty | 
 | // Not run as part of regular tests | 
 | 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); | 
 | } | 
 |  | 
 | // Print the CDF of the distribution of the Anderson-Darling Statistic | 
 | // Used for checking the Anderson-Darling Test | 
 | // Not run as part of regular tests | 
 | 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); | 
 |   } | 
 | } | 
 |  | 
 | // Testing that NextRandom generates uniform | 
 | // random numbers. | 
 | // Applies the Anderson-Darling test for uniformity | 
 | void TestNextRandom(int n) { | 
 |   tcmalloc::Sampler sampler; | 
 |   sampler.Init(1); | 
 |   uint64_t x = 1; | 
 |   // This assumes that the prng returns 48 bit numbers | 
 |   uint64_t max_prng_value = static_cast<uint64_t>(1)<<48; | 
 |   // Initialize | 
 |   for (int i = 1; i <= 20; i++) {  // 20 mimics sampler.Init() | 
 |     x = sampler.NextRandom(x); | 
 |   } | 
 |   scoped_array<uint64_t> int_random_sample(new uint64_t[n]); | 
 |   // Collect samples | 
 |   for (int i = 0; i < n; i++) { | 
 |     int_random_sample[i] = x; | 
 |     x = sampler.NextRandom(x); | 
 |   } | 
 |   // First sort them... | 
 |   sort(int_random_sample.get(), int_random_sample.get() + n); | 
 |   scoped_array<double> random_sample(new double[n]); | 
 |   // Convert them to uniform randoms (in the range [0,1]) | 
 |   for (int i = 0; i < n; i++) { | 
 |     random_sample[i] = static_cast<double>(int_random_sample[i])/max_prng_value; | 
 |   } | 
 |   // Now compute the Anderson-Darling statistic | 
 |   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); | 
 |   //           << StringPrintf("prng is not uniform, %d\n", n); | 
 | } | 
 |  | 
 |  | 
 | TEST(Sampler, TestNextRandom_MultipleValues) { | 
 |   TestNextRandom(10);  // Check short-range correlation | 
 |   TestNextRandom(100); | 
 |   TestNextRandom(1000); | 
 |   TestNextRandom(10000);  // Make sure there's no systematic error | 
 | } | 
 |  | 
 | // Tests that PickNextSamplePeriod generates | 
 | // geometrically distributed random numbers. | 
 | // First converts to uniforms then applied the | 
 | // Anderson-Darling test for uniformity. | 
 | 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); // << " out of " << i << " samples."; | 
 |   } | 
 |   // First sort them... | 
 |   sort(int_random_sample.get(), int_random_sample.get() + n); | 
 |   scoped_array<double> random_sample(new double[n]); | 
 |   // Convert them to uniform random numbers | 
 |   // by applying the geometric CDF | 
 |   for (int i = 0; i < n; i++) { | 
 |     random_sample[i] = 1 - exp(-static_cast<double>(int_random_sample[i]) | 
 |                            / sample_period); | 
 |   } | 
 |   // Now compute the Anderson-Darling statistic | 
 |   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); | 
 |       //          << "PickNextSamplingPoint does not produce good " | 
 |       //             "geometric/exponential random numbers\n"; | 
 | } | 
 |  | 
 | TEST(Sampler, TestPickNextSample_MultipleValues) { | 
 |   TestPickNextSample(10);  // Make sure the first few are good (enough) | 
 |   TestPickNextSample(100); | 
 |   TestPickNextSample(1000); | 
 |   TestPickNextSample(10000);  // Make sure there's no systematic error | 
 | } | 
 |  | 
 |  | 
 | // This is superceeded by the Anderson-Darling Test | 
 | // and it not run now. | 
 | // Tests how fast nearby values are spread out with  LRand64 | 
 | // The purpose of this code is to determine how many | 
 | // steps to apply to the seed during initialization | 
 | 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 for Fastlog2 code | 
 | // We care about the percentage error because we're using this | 
 | // for choosing step sizes, so "close" is relative to the size of | 
 | // the step we would get if we used the built-in log function | 
 | 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);  // log_2(e) | 
 |     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); | 
 |         //        << StringPrintf("d = %f, e=%f, truelog = %f, fastlog= %f\n", | 
 |         //                        d, e, truelog, fastlog); | 
 |   } | 
 |   LOG(INFO) << StringPrintf("Fastlog2: max_ratio_error = %f\n", | 
 |                             max_ratio_error); | 
 | } | 
 |  | 
 | // Futher tests | 
 |  | 
 | 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); | 
 | } | 
 |  | 
 | // Prints a sequence so you can look at the distribution | 
 | 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; | 
 |   // Allocate in mixed chunks | 
 |   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; | 
 |       } | 
 |     } | 
 |   } | 
 |   // Now test that there are the right number of each | 
 |   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); | 
 | } | 
 |  | 
 | // Tests whether the mean is about right over 1000 samples | 
 | TEST(Sampler, IsMeanRight) { | 
 |   CHECK(CheckMean(kSamplingInterval, 1000)); | 
 | } | 
 |  | 
 | // This flag is for the OldSampler class to use | 
 | const int64 FLAGS_mock_tcmalloc_sample_parameter = 1<<19; | 
 |  | 
 | // A cut down and slightly refactored version of the old Sampler | 
 | class OldSampler { | 
 |  public: | 
 |   void Init(uint32_t seed); | 
 |   void Cleanup() {} | 
 |  | 
 |   // Record allocation of "k" bytes.  Return true iff allocation | 
 |   // should be sampled | 
 |   bool SampleAllocation(size_t k); | 
 |  | 
 |   // Generate a geometric with mean 1M (or FLAG value) | 
 |   void PickNextSample(size_t k); | 
 |  | 
 |   // Initialize the statics for the Sample class | 
 |   static void InitStatics() { | 
 |     sample_period = 1048583; | 
 |   } | 
 |   size_t bytes_until_sample_; | 
 |  | 
 |  private: | 
 |   uint32_t rnd_;                   // Cheap random number generator | 
 |   static uint64_t sample_period; | 
 |   // Should be a prime just above a power of 2: | 
 |   // 2, 5, 11, 17, 37, 67, 131, 257, | 
 |   // 521, 1031, 2053, 4099, 8209, 16411, | 
 |   // 32771, 65537, 131101, 262147, 524309, 1048583, | 
 |   // 2097169, 4194319, 8388617, 16777259, 33554467 | 
 | }; | 
 |  | 
 | // Statics for OldSampler | 
 | uint64_t OldSampler::sample_period; | 
 |  | 
 | void OldSampler::Init(uint32_t seed) { | 
 |   // Initialize PRNG -- run it for a bit to get to good values | 
 |   if (seed != 0) { | 
 |     rnd_ = seed; | 
 |   } else { | 
 |     rnd_ = 12345; | 
 |   } | 
 |   bytes_until_sample_ = 0; | 
 |   for (int i = 0; i < 100; i++) { | 
 |     PickNextSample(sample_period * 2); | 
 |   } | 
 | }; | 
 |  | 
 | // A cut-down version of the old PickNextSampleRoutine | 
 | void OldSampler::PickNextSample(size_t k) { | 
 |   // Make next "random" number | 
 |   // x^32+x^22+x^2+x^1+1 is a primitive polynomial for random numbers | 
 |   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); | 
 |  | 
 |   // Next point is "rnd_ % (sample_period)".  I.e., average | 
 |   // increment is "sample_period/2". | 
 |   const int flag_value = FLAGS_mock_tcmalloc_sample_parameter; | 
 |   static int last_flag_value = -1; | 
 |  | 
 |   if (flag_value != last_flag_value) { | 
 |     // There should be a spinlock here, but this code is | 
 |     // for benchmarking only. | 
 |     sample_period = 1048583; | 
 |     last_flag_value = flag_value; | 
 |   } | 
 |  | 
 |   bytes_until_sample_ += rnd_ % sample_period; | 
 |  | 
 |   if (k > (static_cast<size_t>(-1) >> 2)) { | 
 |     // If the user has asked for a huge allocation then it is possible | 
 |     // for the code below to loop infinitely.  Just return (note that | 
 |     // this throws off the sampling accuracy somewhat, but a user who | 
 |     // is allocating more than 1G of memory at a time can live with a | 
 |     // minor inaccuracy in profiling of small allocations, and also | 
 |     // would rather not wait for the loop below to terminate). | 
 |     return; | 
 |   } | 
 |  | 
 |   while (bytes_until_sample_ < k) { | 
 |     // Increase bytes_until_sample_ by enough average sampling periods | 
 |     // (sample_period >> 1) to allow us to sample past the current | 
 |     // allocation. | 
 |     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; | 
 |   } | 
 | } | 
 |  | 
 | // This checks that the stated maximum value for the | 
 | // tcmalloc_sample_parameter flag never overflows bytes_until_sample_ | 
 | TEST(Sampler, bytes_until_sample_Overflow_Underflow) { | 
 |   tcmalloc::Sampler sampler; | 
 |   sampler.Init(1); | 
 |   uint64_t one = 1; | 
 |   // sample_parameter = 0;  // To test the edge case | 
 |   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; | 
 |     // Take the top 26 bits as the random number | 
 |     // (This plus the 1<<26 sampling bound give a max step possible of | 
 |     // 1209424308 bytes.) | 
 |     const uint64_t prng_mod_power = 48;  // Number of bits in prng | 
 |  | 
 |     // First, check the largest_prng value | 
 |     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)); | 
 |     // Replace min(sampler.FastLog2(q) - 26, 0.0) with | 
 |     // (sampler.FastLog2(q) - 26.000705) when using that optimization | 
 |     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; | 
 |     // This checks that the answer is "small" and positive | 
 |     CHECK_LE(smallest_sample_step, cutoff); | 
 |  | 
 |     // Next, check with the smallest prng value | 
 |     uint64_t smallest_prng_value = 0; | 
 |     q = (smallest_prng_value >> (prng_mod_power - 26)) + 1.0; | 
 |     LOG(INFO) << StringPrintf("q = %f\n", q); | 
 |     // Replace min(sampler.FastLog2(q) - 26, 0.0) with | 
 |     // (sampler.FastLog2(q) - 26.000705) when using that optimization | 
 |     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 that NextRand is in the right range.  Unfortunately, this is a | 
 | // stochastic test which could miss problems. | 
 | TEST(Sampler, NextRand_range) { | 
 |   tcmalloc::Sampler sampler; | 
 |   sampler.Init(1); | 
 |   uint64_t one = 1; | 
 |   // The next number should be (one << 48) - 1 | 
 |   uint64_t max_value = (one << 48) - 1; | 
 |   uint64_t x = (one << 55); | 
 |   int n = 22;  // 27; | 
 |   LOG(INFO) << "Running sampler.NextRandom 1<<" << n << " times"; | 
 |   for (int i = 1; i <= (1<<n); i++) {  // 20 mimics sampler.Init() | 
 |     x = sampler.NextRandom(x); | 
 |     CHECK_LE(x, max_value); | 
 |   } | 
 | } | 
 |  | 
 | // Tests certain arithmetic operations to make sure they compute what we | 
 | // expect them too (for testing across different platforms) | 
 | TEST(Sampler, arithmetic_1) { | 
 |   tcmalloc::Sampler sampler; | 
 |   sampler.Init(1); | 
 |   uint64_t rnd;  // our 48 bit random number, which we don't trust | 
 |   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++) {  // 20 mimics sampler.Init() | 
 |     rnd = sampler.NextRandom(rnd); | 
 |     CHECK_LE(rnd, max_value); | 
 |     double q = (rnd >> (prng_mod_power - 26)) + 1.0; | 
 |     CHECK_GE(q, 0); // << rnd << "  " << prng_mod_power; | 
 |   } | 
 |   // Test some potentially out of bounds value for rnd | 
 |   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); | 
 |     //        << " rnd=" << rnd << "  i=" << i << " prng_mod_power" << prng_mod_power; | 
 |   } | 
 | } | 
 |  | 
 | void test_arithmetic(uint64_t rnd) { | 
 |   const uint64_t prng_mod_power = 48;  // Number of bits in prng | 
 |   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); | 
 |       //      << " rnd=" << rnd << "  srnd=" << shifted_rnd; | 
 |   CHECK_GE(static_cast<double>(shifted_rnd), 0); | 
 |       //      << " rnd=" << rnd << "  srnd=" << shifted_rnd; | 
 |   double q = static_cast<double>(shifted_rnd) + 1.0; | 
 |   CHECK_GT(q, 0); | 
 | } | 
 |  | 
 | // Tests certain arithmetic operations to make sure they compute what we | 
 | // expect them too (for testing across different platforms) | 
 | // know bad values under with -c dbg --cpu piii for _some_ binaries: | 
 | // rnd=227453640600554 | 
 | // shifted_rnd=54229173 | 
 | // (hard to reproduce) | 
 | TEST(Sampler, arithmetic_2) { | 
 |   uint64_t rnd = 227453640600554LL; | 
 |   test_arithmetic(rnd); | 
 | } | 
 |  | 
 |  | 
 | // It's not really a test, but it's good to know | 
 | 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); | 
 | } | 
 |  | 
 | // Make sure sampling is enabled, or the tests won't work right. | 
 | 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(); | 
 | } |