mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Upgrade gperftools to 2.9 for GCP/GMC/GMP/GMD. (#2247)
This commit is contained in:
parent
63da0dca92
commit
44e9dc83e9
346 changed files with 169666 additions and 78 deletions
174
trunk/3rdparty/gperftools-2-fit/src/tests/addressmap_unittest.cc
vendored
Normal file
174
trunk/3rdparty/gperftools-2-fit/src/tests/addressmap_unittest.cc
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2005, 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.
|
||||
|
||||
// ---
|
||||
// Author: Sanjay Ghemawat
|
||||
|
||||
#include <stdlib.h> // for rand()
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include "addressmap-inl.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/commandlineflags.h"
|
||||
|
||||
DEFINE_int32(iters, 20, "Number of test iterations");
|
||||
DEFINE_int32(N, 100000, "Number of elements to test per iteration");
|
||||
|
||||
using std::pair;
|
||||
using std::make_pair;
|
||||
using std::vector;
|
||||
using std::set;
|
||||
using std::shuffle;
|
||||
|
||||
struct UniformRandomNumberGenerator {
|
||||
size_t Uniform(size_t max_size) {
|
||||
if (max_size == 0)
|
||||
return 0;
|
||||
return rand() % max_size; // not a great random-number fn, but portable
|
||||
}
|
||||
};
|
||||
static UniformRandomNumberGenerator rnd;
|
||||
|
||||
|
||||
// pair of associated value and object size
|
||||
typedef pair<int, size_t> ValueT;
|
||||
|
||||
struct PtrAndSize {
|
||||
char* ptr;
|
||||
size_t size;
|
||||
PtrAndSize(char* p, size_t s) : ptr(p), size(s) {}
|
||||
};
|
||||
|
||||
size_t SizeFunc(const ValueT& v) { return v.second; }
|
||||
|
||||
static void SetCheckCallback(const void* ptr, ValueT* val,
|
||||
set<pair<const void*, int> >* check_set) {
|
||||
check_set->insert(make_pair(ptr, val->first));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Get a bunch of pointers
|
||||
const int N = FLAGS_N;
|
||||
static const int kMaxRealSize = 49;
|
||||
// 100Mb to stress not finding previous object (AddressMap's cluster is 1Mb):
|
||||
static const size_t kMaxSize = 100*1000*1000;
|
||||
vector<PtrAndSize> ptrs_and_sizes;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
size_t s = rnd.Uniform(kMaxRealSize);
|
||||
ptrs_and_sizes.push_back(PtrAndSize(new char[s], s));
|
||||
}
|
||||
|
||||
for (int x = 0; x < FLAGS_iters; ++x) {
|
||||
RAW_LOG(INFO, "Iteration %d/%d...\n", x, FLAGS_iters);
|
||||
|
||||
// Permute pointers to get rid of allocation order issues
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
shuffle(ptrs_and_sizes.begin(), ptrs_and_sizes.end(), g);
|
||||
|
||||
AddressMap<ValueT> map(malloc, free);
|
||||
const ValueT* result;
|
||||
const void* res_p;
|
||||
|
||||
// Insert a bunch of entries
|
||||
for (int i = 0; i < N; ++i) {
|
||||
char* p = ptrs_and_sizes[i].ptr;
|
||||
CHECK(!map.Find(p));
|
||||
int offs = rnd.Uniform(ptrs_and_sizes[i].size);
|
||||
CHECK(!map.FindInside(&SizeFunc, kMaxSize, p + offs, &res_p));
|
||||
map.Insert(p, make_pair(i, ptrs_and_sizes[i].size));
|
||||
CHECK(result = map.Find(p));
|
||||
CHECK_EQ(result->first, i);
|
||||
CHECK(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p));
|
||||
CHECK_EQ(res_p, p);
|
||||
CHECK_EQ(result->first, i);
|
||||
map.Insert(p, make_pair(i + N, ptrs_and_sizes[i].size));
|
||||
CHECK(result = map.Find(p));
|
||||
CHECK_EQ(result->first, i + N);
|
||||
}
|
||||
|
||||
// Delete the even entries
|
||||
for (int i = 0; i < N; i += 2) {
|
||||
void* p = ptrs_and_sizes[i].ptr;
|
||||
ValueT removed;
|
||||
CHECK(map.FindAndRemove(p, &removed));
|
||||
CHECK_EQ(removed.first, i + N);
|
||||
}
|
||||
|
||||
// Lookup the odd entries and adjust them
|
||||
for (int i = 1; i < N; i += 2) {
|
||||
char* p = ptrs_and_sizes[i].ptr;
|
||||
CHECK(result = map.Find(p));
|
||||
CHECK_EQ(result->first, i + N);
|
||||
int offs = rnd.Uniform(ptrs_and_sizes[i].size);
|
||||
CHECK(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p));
|
||||
CHECK_EQ(res_p, p);
|
||||
CHECK_EQ(result->first, i + N);
|
||||
map.Insert(p, make_pair(i + 2*N, ptrs_and_sizes[i].size));
|
||||
CHECK(result = map.Find(p));
|
||||
CHECK_EQ(result->first, i + 2*N);
|
||||
}
|
||||
|
||||
// Insert even entries back
|
||||
for (int i = 0; i < N; i += 2) {
|
||||
char* p = ptrs_and_sizes[i].ptr;
|
||||
int offs = rnd.Uniform(ptrs_and_sizes[i].size);
|
||||
CHECK(!map.FindInside(&SizeFunc, kMaxSize, p + offs, &res_p));
|
||||
map.Insert(p, make_pair(i + 2*N, ptrs_and_sizes[i].size));
|
||||
CHECK(result = map.Find(p));
|
||||
CHECK_EQ(result->first, i + 2*N);
|
||||
CHECK(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p));
|
||||
CHECK_EQ(res_p, p);
|
||||
CHECK_EQ(result->first, i + 2*N);
|
||||
}
|
||||
|
||||
// Check all entries
|
||||
set<pair<const void*, int> > check_set;
|
||||
map.Iterate(SetCheckCallback, &check_set);
|
||||
CHECK_EQ(check_set.size(), N);
|
||||
for (int i = 0; i < N; ++i) {
|
||||
void* p = ptrs_and_sizes[i].ptr;
|
||||
check_set.erase(make_pair(p, i + 2*N));
|
||||
CHECK(result = map.Find(p));
|
||||
CHECK_EQ(result->first, i + 2*N);
|
||||
}
|
||||
CHECK_EQ(check_set.size(), 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
delete[] ptrs_and_sizes[i].ptr;
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
152
trunk/3rdparty/gperftools-2-fit/src/tests/atomicops_unittest.cc
vendored
Normal file
152
trunk/3rdparty/gperftools-2-fit/src/tests/atomicops_unittest.cc
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2006, 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.
|
||||
*
|
||||
* ---
|
||||
* Author: Sanjay Ghemawat
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "base/logging.h"
|
||||
#include "base/atomicops.h"
|
||||
|
||||
#define GG_ULONGLONG(x) static_cast<uint64>(x)
|
||||
|
||||
|
||||
#define NUM_BITS(T) (sizeof(T) * 8)
|
||||
|
||||
|
||||
template <class AtomicType>
|
||||
static void TestCompareAndSwap(AtomicType (*compare_and_swap_func)
|
||||
(volatile AtomicType*, AtomicType, AtomicType)) {
|
||||
AtomicType value = 0;
|
||||
AtomicType prev = (*compare_and_swap_func)(&value, 0, 1);
|
||||
ASSERT_EQ(1, value);
|
||||
ASSERT_EQ(0, prev);
|
||||
|
||||
// Use test value that has non-zero bits in both halves, more for testing
|
||||
// 64-bit implementation on 32-bit platforms.
|
||||
const AtomicType k_test_val = (GG_ULONGLONG(1) <<
|
||||
(NUM_BITS(AtomicType) - 2)) + 11;
|
||||
value = k_test_val;
|
||||
prev = (*compare_and_swap_func)(&value, 0, 5);
|
||||
ASSERT_EQ(k_test_val, value);
|
||||
ASSERT_EQ(k_test_val, prev);
|
||||
|
||||
value = k_test_val;
|
||||
prev = (*compare_and_swap_func)(&value, k_test_val, 5);
|
||||
ASSERT_EQ(5, value);
|
||||
ASSERT_EQ(k_test_val, prev);
|
||||
}
|
||||
|
||||
|
||||
template <class AtomicType>
|
||||
static void TestAtomicExchange(AtomicType (*atomic_exchange_func)
|
||||
(volatile AtomicType*, AtomicType)) {
|
||||
AtomicType value = 0;
|
||||
AtomicType new_value = (*atomic_exchange_func)(&value, 1);
|
||||
ASSERT_EQ(1, value);
|
||||
ASSERT_EQ(0, new_value);
|
||||
|
||||
// Use test value that has non-zero bits in both halves, more for testing
|
||||
// 64-bit implementation on 32-bit platforms.
|
||||
const AtomicType k_test_val = (GG_ULONGLONG(1) <<
|
||||
(NUM_BITS(AtomicType) - 2)) + 11;
|
||||
value = k_test_val;
|
||||
new_value = (*atomic_exchange_func)(&value, k_test_val);
|
||||
ASSERT_EQ(k_test_val, value);
|
||||
ASSERT_EQ(k_test_val, new_value);
|
||||
|
||||
value = k_test_val;
|
||||
new_value = (*atomic_exchange_func)(&value, 5);
|
||||
ASSERT_EQ(5, value);
|
||||
ASSERT_EQ(k_test_val, new_value);
|
||||
}
|
||||
|
||||
|
||||
// This is a simple sanity check that values are correct. Not testing
|
||||
// atomicity
|
||||
template <class AtomicType>
|
||||
static void TestStore() {
|
||||
const AtomicType kVal1 = static_cast<AtomicType>(0xa5a5a5a5a5a5a5a5LL);
|
||||
const AtomicType kVal2 = static_cast<AtomicType>(-1);
|
||||
|
||||
AtomicType value;
|
||||
|
||||
base::subtle::NoBarrier_Store(&value, kVal1);
|
||||
ASSERT_EQ(kVal1, value);
|
||||
base::subtle::NoBarrier_Store(&value, kVal2);
|
||||
ASSERT_EQ(kVal2, value);
|
||||
|
||||
base::subtle::Release_Store(&value, kVal1);
|
||||
ASSERT_EQ(kVal1, value);
|
||||
base::subtle::Release_Store(&value, kVal2);
|
||||
ASSERT_EQ(kVal2, value);
|
||||
}
|
||||
|
||||
// This is a simple sanity check that values are correct. Not testing
|
||||
// atomicity
|
||||
template <class AtomicType>
|
||||
static void TestLoad() {
|
||||
const AtomicType kVal1 = static_cast<AtomicType>(0xa5a5a5a5a5a5a5a5LL);
|
||||
const AtomicType kVal2 = static_cast<AtomicType>(-1);
|
||||
|
||||
AtomicType value;
|
||||
|
||||
value = kVal1;
|
||||
ASSERT_EQ(kVal1, base::subtle::NoBarrier_Load(&value));
|
||||
value = kVal2;
|
||||
ASSERT_EQ(kVal2, base::subtle::NoBarrier_Load(&value));
|
||||
|
||||
value = kVal1;
|
||||
ASSERT_EQ(kVal1, base::subtle::Acquire_Load(&value));
|
||||
value = kVal2;
|
||||
ASSERT_EQ(kVal2, base::subtle::Acquire_Load(&value));
|
||||
}
|
||||
|
||||
template <class AtomicType>
|
||||
static void TestAtomicOps() {
|
||||
TestCompareAndSwap<AtomicType>(base::subtle::NoBarrier_CompareAndSwap);
|
||||
TestCompareAndSwap<AtomicType>(base::subtle::Acquire_CompareAndSwap);
|
||||
TestCompareAndSwap<AtomicType>(base::subtle::Release_CompareAndSwap);
|
||||
|
||||
TestAtomicExchange<AtomicType>(base::subtle::NoBarrier_AtomicExchange);
|
||||
TestAtomicExchange<AtomicType>(base::subtle::Acquire_AtomicExchange);
|
||||
TestAtomicExchange<AtomicType>(base::subtle::Release_AtomicExchange);
|
||||
|
||||
TestStore<AtomicType>();
|
||||
TestLoad<AtomicType>();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
TestAtomicOps<AtomicWord>();
|
||||
TestAtomicOps<Atomic32>();
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
64
trunk/3rdparty/gperftools-2-fit/src/tests/current_allocated_bytes_test.cc
vendored
Normal file
64
trunk/3rdparty/gperftools-2-fit/src/tests/current_allocated_bytes_test.cc
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2011, 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.
|
||||
// ---
|
||||
//
|
||||
// Author: Craig Silverstein
|
||||
|
||||
// This tests the accounting done by tcmalloc. When we allocate and
|
||||
// free a small buffer, the number of bytes used by the application
|
||||
// before the alloc+free should match the number of bytes used after.
|
||||
// However, the internal data structures used by tcmalloc will be
|
||||
// quite different -- new spans will have been allocated, etc. This
|
||||
// is, thus, a simple test that we account properly for the internal
|
||||
// data structures, so that we report the actual application-used
|
||||
// bytes properly.
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <gperftools/malloc_extension.h>
|
||||
#include "base/logging.h"
|
||||
|
||||
int main() {
|
||||
// We don't do accounting right when using debugallocation.cc, so
|
||||
// turn off the test then. TODO(csilvers): get this working too.
|
||||
#ifdef NDEBUG
|
||||
static const char kCurrent[] = "generic.current_allocated_bytes";
|
||||
|
||||
size_t before_bytes, after_bytes;
|
||||
MallocExtension::instance()->GetNumericProperty(kCurrent, &before_bytes);
|
||||
free(malloc(200));
|
||||
MallocExtension::instance()->GetNumericProperty(kCurrent, &after_bytes);
|
||||
|
||||
CHECK_EQ(before_bytes, after_bytes);
|
||||
#endif
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
333
trunk/3rdparty/gperftools-2-fit/src/tests/debugallocation_test.cc
vendored
Normal file
333
trunk/3rdparty/gperftools-2-fit/src/tests/debugallocation_test.cc
vendored
Normal file
|
@ -0,0 +1,333 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2007, 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.
|
||||
|
||||
// ---
|
||||
// Author: Fred Akalin
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> // for memcmp
|
||||
#include <vector>
|
||||
#include "gperftools/malloc_extension.h"
|
||||
#include "gperftools/tcmalloc.h"
|
||||
#include "base/logging.h"
|
||||
#include "tests/testutil.h"
|
||||
|
||||
using std::vector;
|
||||
|
||||
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",
|
||||
static_cast<int>(g_testlist.size()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The death tests are meant to be run from a shell-script driver, which
|
||||
// passes in an integer saying which death test to run. We store that
|
||||
// test-to-run here, and in the macro use a counter to see when we get
|
||||
// to that test, so we can run it.
|
||||
static int test_to_run = 0; // set in main() based on argv
|
||||
static int test_counter = 0; // incremented every time the macro is called
|
||||
#define IF_DEBUG_EXPECT_DEATH(statement, regex) do { \
|
||||
if (test_counter++ == test_to_run) { \
|
||||
fprintf(stderr, "Expected regex:%s\n", regex); \
|
||||
statement; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
// This flag won't be compiled in in opt mode.
|
||||
DECLARE_int32(max_free_queue_size);
|
||||
|
||||
// Test match as well as mismatch rules. But do not test on OS X; on
|
||||
// OS X the OS converts new/new[] to malloc before it gets to us, so
|
||||
// we are unable to catch these mismatch errors.
|
||||
#ifndef __APPLE__
|
||||
TEST(DebugAllocationTest, DeallocMismatch) {
|
||||
// malloc can be matched only by free
|
||||
// new can be matched only by delete and delete(nothrow)
|
||||
// new[] can be matched only by delete[] and delete[](nothrow)
|
||||
// new(nothrow) can be matched only by delete and delete(nothrow)
|
||||
// new(nothrow)[] can be matched only by delete[] and delete[](nothrow)
|
||||
|
||||
// Allocate with malloc.
|
||||
{
|
||||
int* x = static_cast<int*>(noopt(malloc(sizeof(*x))));
|
||||
IF_DEBUG_EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete");
|
||||
IF_DEBUG_EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]");
|
||||
// Should work fine.
|
||||
free(x);
|
||||
}
|
||||
|
||||
// Allocate with new.
|
||||
{
|
||||
int* x = noopt(new int);
|
||||
int* y = noopt(new int);
|
||||
IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
|
||||
IF_DEBUG_EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]");
|
||||
delete x;
|
||||
::operator delete(y, std::nothrow);
|
||||
}
|
||||
|
||||
// Allocate with new[].
|
||||
{
|
||||
int* x = noopt(new int[1]);
|
||||
int* y = noopt(new int[1]);
|
||||
IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
|
||||
IF_DEBUG_EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete");
|
||||
delete [] x;
|
||||
::operator delete[](y, std::nothrow);
|
||||
}
|
||||
|
||||
// Allocate with new(nothrow).
|
||||
{
|
||||
int* x = noopt(new (std::nothrow) int);
|
||||
int* y = noopt(new (std::nothrow) int);
|
||||
IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
|
||||
IF_DEBUG_EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]");
|
||||
delete x;
|
||||
::operator delete(y, std::nothrow);
|
||||
}
|
||||
|
||||
// Allocate with new(nothrow)[].
|
||||
{
|
||||
int* x = noopt(new (std::nothrow) int[1]);
|
||||
int* y = noopt(new (std::nothrow) int[1]);
|
||||
IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
|
||||
IF_DEBUG_EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete");
|
||||
delete [] x;
|
||||
::operator delete[](y, std::nothrow);
|
||||
}
|
||||
}
|
||||
#endif // #ifdef OS_MACOSX
|
||||
|
||||
TEST(DebugAllocationTest, DoubleFree) {
|
||||
int* pint = noopt(new int);
|
||||
delete pint;
|
||||
IF_DEBUG_EXPECT_DEATH(delete pint, "has been already deallocated");
|
||||
}
|
||||
|
||||
TEST(DebugAllocationTest, StompBefore) {
|
||||
int* pint = noopt(new int);
|
||||
#ifndef NDEBUG // don't stomp memory if we're not in a position to detect it
|
||||
pint[-1] = 5;
|
||||
IF_DEBUG_EXPECT_DEATH(delete pint, "a word before object");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(DebugAllocationTest, StompAfter) {
|
||||
int* pint = noopt(new int);
|
||||
#ifndef NDEBUG // don't stomp memory if we're not in a position to detect it
|
||||
pint[1] = 5;
|
||||
IF_DEBUG_EXPECT_DEATH(delete pint, "a word after object");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(DebugAllocationTest, FreeQueueTest) {
|
||||
// Verify that the allocator doesn't return blocks that were recently freed.
|
||||
int* x = noopt(new int);
|
||||
int* old_x = x;
|
||||
delete x;
|
||||
x = noopt(new int);
|
||||
#if 1
|
||||
// This check should not be read as a universal guarantee of behavior. If
|
||||
// other threads are executing, it would be theoretically possible for this
|
||||
// check to fail despite the efforts of debugallocation.cc to the contrary.
|
||||
// It should always hold under the controlled conditions of this unittest,
|
||||
// however.
|
||||
EXPECT_NE(x, old_x); // Allocator shouldn't return recently freed blocks
|
||||
#else
|
||||
// The below check passes, but since it isn't *required* to pass, I've left
|
||||
// it commented out.
|
||||
// EXPECT_EQ(x, old_x);
|
||||
#endif
|
||||
old_x = NULL; // avoid breaking opt build with an unused variable warning.
|
||||
delete x;
|
||||
}
|
||||
|
||||
TEST(DebugAllocationTest, DanglingPointerWriteTest) {
|
||||
// This test can only be run if debugging.
|
||||
//
|
||||
// If not debugging, the 'new' following the dangling write might not be
|
||||
// safe. When debugging, we expect the (trashed) deleted block to be on the
|
||||
// list of recently-freed blocks, so the following 'new' will be safe.
|
||||
#if 1
|
||||
int* x = noopt(new int);
|
||||
delete x;
|
||||
int poisoned_x_value = *x;
|
||||
*x = 1; // a dangling write.
|
||||
|
||||
char* s = noopt(new char[FLAGS_max_free_queue_size]);
|
||||
// When we delete s, we push the storage that was previously allocated to x
|
||||
// off the end of the free queue. At that point, the write to that memory
|
||||
// will be detected.
|
||||
IF_DEBUG_EXPECT_DEATH(delete [] s, "Memory was written to after being freed.");
|
||||
|
||||
// restore the poisoned value of x so that we can delete s without causing a
|
||||
// crash.
|
||||
*x = poisoned_x_value;
|
||||
delete [] s;
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(DebugAllocationTest, DanglingWriteAtExitTest) {
|
||||
int *x = noopt(new int);
|
||||
delete x;
|
||||
int old_x_value = *x;
|
||||
*x = 1;
|
||||
// verify that dangling writes are caught at program termination if the
|
||||
// corrupted block never got pushed off of the end of the free queue.
|
||||
IF_DEBUG_EXPECT_DEATH(exit(0), "Memory was written to after being freed.");
|
||||
*x = old_x_value; // restore x so that the test can exit successfully.
|
||||
}
|
||||
|
||||
TEST(DebugAllocationTest, StackTraceWithDanglingWriteAtExitTest) {
|
||||
int *x = noopt(new int);
|
||||
delete x;
|
||||
int old_x_value = *x;
|
||||
*x = 1;
|
||||
// verify that we also get a stack trace when we have a dangling write.
|
||||
// The " @ " is part of the stack trace output.
|
||||
IF_DEBUG_EXPECT_DEATH(exit(0), " @ .*main");
|
||||
*x = old_x_value; // restore x so that the test can exit successfully.
|
||||
}
|
||||
|
||||
static size_t CurrentlyAllocatedBytes() {
|
||||
size_t value;
|
||||
CHECK(MallocExtension::instance()->GetNumericProperty(
|
||||
"generic.current_allocated_bytes", &value));
|
||||
return value;
|
||||
}
|
||||
|
||||
TEST(DebugAllocationTest, CurrentlyAllocated) {
|
||||
// Clear the free queue
|
||||
#if 1
|
||||
FLAGS_max_free_queue_size = 0;
|
||||
// Force a round-trip through the queue management code so that the
|
||||
// new size is seen and the queue of recently-freed blocks is flushed.
|
||||
free(noopt(malloc(1)));
|
||||
FLAGS_max_free_queue_size = 1048576;
|
||||
#endif
|
||||
|
||||
// Free something and check that it disappears from allocated bytes
|
||||
// immediately.
|
||||
char* p = noopt(new char[1000]);
|
||||
size_t after_malloc = CurrentlyAllocatedBytes();
|
||||
delete[] p;
|
||||
size_t after_free = CurrentlyAllocatedBytes();
|
||||
EXPECT_LE(after_free, after_malloc - 1000);
|
||||
}
|
||||
|
||||
TEST(DebugAllocationTest, GetAllocatedSizeTest) {
|
||||
#if 1
|
||||
// When debug_allocation is in effect, GetAllocatedSize should return
|
||||
// exactly requested size, since debug_allocation doesn't allow users
|
||||
// to write more than that.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
void *p = noopt(malloc(i));
|
||||
EXPECT_EQ(i, MallocExtension::instance()->GetAllocatedSize(p));
|
||||
free(p);
|
||||
}
|
||||
#endif
|
||||
void* a = noopt(malloc(1000));
|
||||
EXPECT_GE(MallocExtension::instance()->GetAllocatedSize(a), 1000);
|
||||
// This is just a sanity check. If we allocated too much, alloc is broken
|
||||
EXPECT_LE(MallocExtension::instance()->GetAllocatedSize(a), 5000);
|
||||
EXPECT_GE(MallocExtension::instance()->GetEstimatedAllocatedSize(1000), 1000);
|
||||
free(a);
|
||||
}
|
||||
|
||||
TEST(DebugAllocationTest, HugeAlloc) {
|
||||
// This must not be a const variable so it doesn't form an
|
||||
// integral-constant-expression which can be *statically* rejected by the
|
||||
// compiler as too large for the allocation.
|
||||
size_t kTooBig = ~static_cast<size_t>(0);
|
||||
void* a = NULL;
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
a = noopt(malloc(noopt(kTooBig)));
|
||||
EXPECT_EQ(NULL, a);
|
||||
|
||||
// kAlsoTooBig is small enough not to get caught by debugallocation's check,
|
||||
// but will still fall through to tcmalloc's check. This must also be
|
||||
// a non-const variable. See kTooBig for more details.
|
||||
size_t kAlsoTooBig = kTooBig - 1024;
|
||||
|
||||
a = noopt(malloc(noopt(kAlsoTooBig)));
|
||||
EXPECT_EQ(NULL, a);
|
||||
#endif
|
||||
}
|
||||
|
||||
// based on test program contributed by mikesart@gmail.com aka
|
||||
// mikesart@valvesoftware.com. See issue-464.
|
||||
TEST(DebugAllocationTest, ReallocAfterMemalign) {
|
||||
char stuff[50];
|
||||
memset(stuff, 0x11, sizeof(stuff));
|
||||
void *p = tc_memalign(16, sizeof(stuff));
|
||||
EXPECT_NE(p, NULL);
|
||||
memcpy(stuff, p, sizeof(stuff));
|
||||
|
||||
p = noopt(realloc(p, sizeof(stuff) + 10));
|
||||
EXPECT_NE(p, NULL);
|
||||
|
||||
int rv = memcmp(stuff, p, sizeof(stuff));
|
||||
EXPECT_EQ(rv, 0);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// If you run without args, we run the non-death parts of the test.
|
||||
// Otherwise, argv[1] should be a number saying which death-test
|
||||
// to run. We will output a regexp we expect the death-message
|
||||
// to include, and then run the given death test (which hopefully
|
||||
// will produce that error message). If argv[1] > the number of
|
||||
// death tests, we will run only the non-death parts. One way to
|
||||
// tell when you are done with all tests is when no 'expected
|
||||
// regexp' message is printed for a given argv[1].
|
||||
if (argc < 2) {
|
||||
test_to_run = -1; // will never match
|
||||
} else {
|
||||
test_to_run = atoi(argv[1]);
|
||||
}
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
98
trunk/3rdparty/gperftools-2-fit/src/tests/debugallocation_test.sh
vendored
Executable file
98
trunk/3rdparty/gperftools-2-fit/src/tests/debugallocation_test.sh
vendored
Executable file
|
@ -0,0 +1,98 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2009, 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.
|
||||
#
|
||||
# ---
|
||||
# Author: Craig Silverstein
|
||||
|
||||
BINDIR="${BINDIR:-.}"
|
||||
# We expect PPROF_PATH to be set in the environment.
|
||||
# If not, we set it to some reasonable value
|
||||
export PPROF_PATH="${PPROF_PATH:-$BINDIR/src/pprof}"
|
||||
|
||||
if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then
|
||||
echo "USAGE: $0 [unittest dir]"
|
||||
echo " By default, unittest_dir=$BINDIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DEBUGALLOCATION_TEST="${1:-$BINDIR/debugallocation_test}"
|
||||
|
||||
num_failures=0
|
||||
|
||||
# Run the i-th death test and make sure the test has the expected
|
||||
# regexp. We can depend on the first line of the output being
|
||||
# Expected regex:<regex>
|
||||
# Evaluates to "done" if we are not actually a death-test (so $1 is
|
||||
# too big a number, and we can stop). Evaluates to "" otherwise.
|
||||
# Increments num_failures if the death test does not succeed.
|
||||
OneDeathTest() {
|
||||
"$DEBUGALLOCATION_TEST" "$1" 2>&1 | {
|
||||
regex_line='dummy'
|
||||
# Normally the regex_line is the first line of output, but not
|
||||
# always (if tcmalloc itself does any logging to stderr).
|
||||
while test -n "$regex_line"; do
|
||||
read regex_line
|
||||
regex=`expr "$regex_line" : "Expected regex:\(.*\)"`
|
||||
test -n "$regex" && break # found the regex line
|
||||
done
|
||||
test -z "$regex" && echo "done" || grep "$regex" 2>&1
|
||||
}
|
||||
}
|
||||
|
||||
death_test_num=0 # which death test to run
|
||||
while :; do # same as 'while true', but more portable
|
||||
echo -n "Running death test $death_test_num..."
|
||||
output="`OneDeathTest $death_test_num`"
|
||||
case $output in
|
||||
# Empty string means grep didn't find anything.
|
||||
"") echo "FAILED"; num_failures=`expr $num_failures + 1`;;
|
||||
"done"*) echo "done with death tests"; break;;
|
||||
# Any other string means grep found something, like it ought to.
|
||||
*) echo "OK";;
|
||||
esac
|
||||
death_test_num=`expr $death_test_num + 1`
|
||||
done
|
||||
|
||||
# Test the non-death parts of the test too
|
||||
echo -n "Running non-death tests..."
|
||||
if "$DEBUGALLOCATION_TEST"; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "FAILED"
|
||||
num_failures=`expr $num_failures + 1`
|
||||
fi
|
||||
|
||||
if [ "$num_failures" = 0 ]; then
|
||||
echo "PASS"
|
||||
else
|
||||
echo "Failed with $num_failures failures"
|
||||
fi
|
||||
exit $num_failures
|
133
trunk/3rdparty/gperftools-2-fit/src/tests/frag_unittest.cc
vendored
Normal file
133
trunk/3rdparty/gperftools-2-fit/src/tests/frag_unittest.cc
vendored
Normal file
|
@ -0,0 +1,133 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2003, 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.
|
||||
|
||||
// ---
|
||||
// Author: Sanjay Ghemawat
|
||||
//
|
||||
// Test speed of handling fragmented heap
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/time.h> // for struct timeval
|
||||
#include <sys/resource.h> // for getrusage
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <windows.h> // for GetTickCount()
|
||||
#endif
|
||||
#include <vector>
|
||||
#include "base/logging.h"
|
||||
#include "common.h"
|
||||
#include <gperftools/malloc_extension.h>
|
||||
|
||||
using std::vector;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Make kAllocSize one page larger than the maximum small object size.
|
||||
static const int kAllocSize = kMaxSize + kPageSize;
|
||||
// Allocate 400MB in total.
|
||||
static const int kTotalAlloc = 400 << 20;
|
||||
static const int kAllocIterations = kTotalAlloc / kAllocSize;
|
||||
|
||||
// Allocate lots of objects
|
||||
vector<char*> saved(kAllocIterations);
|
||||
for (int i = 0; i < kAllocIterations; i++) {
|
||||
saved[i] = new char[kAllocSize];
|
||||
}
|
||||
|
||||
// Check the current "slack".
|
||||
size_t slack_before;
|
||||
MallocExtension::instance()->GetNumericProperty("tcmalloc.slack_bytes",
|
||||
&slack_before);
|
||||
|
||||
// Free alternating ones to fragment heap
|
||||
size_t free_bytes = 0;
|
||||
for (int i = 0; i < saved.size(); i += 2) {
|
||||
delete[] saved[i];
|
||||
free_bytes += kAllocSize;
|
||||
}
|
||||
|
||||
// Check that slack delta is within 10% of expected.
|
||||
size_t slack_after;
|
||||
MallocExtension::instance()->GetNumericProperty("tcmalloc.slack_bytes",
|
||||
&slack_after);
|
||||
CHECK_GE(slack_after, slack_before);
|
||||
size_t slack = slack_after - slack_before;
|
||||
|
||||
CHECK_GT(double(slack), 0.9*free_bytes);
|
||||
CHECK_LT(double(slack), 1.1*free_bytes);
|
||||
|
||||
// Dump malloc stats
|
||||
static const int kBufSize = 1<<20;
|
||||
char* buffer = new char[kBufSize];
|
||||
MallocExtension::instance()->GetStats(buffer, kBufSize);
|
||||
VLOG(1, "%s", buffer);
|
||||
delete[] buffer;
|
||||
|
||||
// Now do timing tests
|
||||
for (int i = 0; i < 5; i++) {
|
||||
static const int kIterations = 100000;
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
struct rusage r;
|
||||
getrusage(RUSAGE_SELF, &r); // figure out user-time spent on this
|
||||
struct timeval tv_start = r.ru_utime;
|
||||
#elif defined(_WIN32)
|
||||
long long int tv_start = GetTickCount();
|
||||
#else
|
||||
# error No way to calculate time on your system
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < kIterations; i++) {
|
||||
size_t s;
|
||||
MallocExtension::instance()->GetNumericProperty("tcmalloc.slack_bytes",
|
||||
&s);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
getrusage(RUSAGE_SELF, &r);
|
||||
struct timeval tv_end = r.ru_utime;
|
||||
int64 sumsec = static_cast<int64>(tv_end.tv_sec) - tv_start.tv_sec;
|
||||
int64 sumusec = static_cast<int64>(tv_end.tv_usec) - tv_start.tv_usec;
|
||||
#elif defined(_WIN32)
|
||||
long long int tv_end = GetTickCount();
|
||||
int64 sumsec = (tv_end - tv_start) / 1000;
|
||||
// Resolution in windows is only to the millisecond, alas
|
||||
int64 sumusec = ((tv_end - tv_start) % 1000) * 1000;
|
||||
#else
|
||||
# error No way to calculate time on your system
|
||||
#endif
|
||||
fprintf(stderr, "getproperty: %6.1f ns/call\n",
|
||||
(sumsec * 1e9 + sumusec * 1e3) / kIterations);
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
123
trunk/3rdparty/gperftools-2-fit/src/tests/getpc_test.cc
vendored
Normal file
123
trunk/3rdparty/gperftools-2-fit/src/tests/getpc_test.cc
vendored
Normal file
|
@ -0,0 +1,123 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2005, 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.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// This verifies that GetPC works correctly. This test uses a minimum
|
||||
// of Google infrastructure, to make it very easy to port to various
|
||||
// O/Ses and CPUs and test that GetPC is working.
|
||||
|
||||
#include "config.h"
|
||||
#include "getpc.h" // should be first to get the _GNU_SOURCE dfn
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h> // for setitimer
|
||||
|
||||
// Needs to be volatile so compiler doesn't try to optimize it away
|
||||
static volatile void* getpc_retval = NULL; // what GetPC returns
|
||||
static volatile bool prof_handler_called = false;
|
||||
|
||||
static void prof_handler(int sig, siginfo_t*, void* signal_ucontext) {
|
||||
if (!prof_handler_called)
|
||||
getpc_retval = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
|
||||
prof_handler_called = true; // only store the retval once
|
||||
}
|
||||
|
||||
static void RoutineCallingTheSignal() {
|
||||
struct sigaction sa;
|
||||
sa.sa_sigaction = prof_handler;
|
||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
if (sigaction(SIGPROF, &sa, NULL) != 0) {
|
||||
perror("sigaction");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct itimerval timer;
|
||||
timer.it_interval.tv_sec = 0;
|
||||
timer.it_interval.tv_usec = 1000;
|
||||
timer.it_value = timer.it_interval;
|
||||
setitimer(ITIMER_PROF, &timer, 0);
|
||||
|
||||
// Now we need to do some work for a while, that doesn't call any
|
||||
// other functions, so we can be guaranteed that when the SIGPROF
|
||||
// fires, we're the routine executing.
|
||||
int r = 0;
|
||||
for (int i = 0; !prof_handler_called; ++i) {
|
||||
for (int j = 0; j < i; j++) {
|
||||
r ^= i;
|
||||
r <<= 1;
|
||||
r ^= j;
|
||||
r >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now make sure the above loop doesn't get optimized out
|
||||
srand(r);
|
||||
}
|
||||
|
||||
// This is an upper bound of how many bytes the instructions for
|
||||
// RoutineCallingTheSignal might be. There's probably a more
|
||||
// principled way to do this, but I don't know how portable it would be.
|
||||
// (The function is 372 bytes when compiled with -g on Mac OS X 10.4.
|
||||
// I can imagine it would be even bigger in 64-bit architectures.)
|
||||
const int kRoutineSize = 512 * sizeof(void*)/4; // allow 1024 for 64-bit
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
RoutineCallingTheSignal();
|
||||
|
||||
// Annoyingly, C++ disallows casting pointer-to-function to
|
||||
// pointer-to-object, so we use a C-style cast instead.
|
||||
char* expected = (char*)&RoutineCallingTheSignal;
|
||||
char* actual = (char*)getpc_retval;
|
||||
|
||||
// For ia64, ppc64v1, and parisc64, the function pointer is actually
|
||||
// a struct. For instance, ia64's dl-fptr.h:
|
||||
// struct fdesc { /* An FDESC is a function descriptor. */
|
||||
// ElfW(Addr) ip; /* code entry point */
|
||||
// ElfW(Addr) gp; /* global pointer */
|
||||
// };
|
||||
// We want the code entry point.
|
||||
// NOTE: ppc64 ELFv2 (Little Endian) does not have function pointers
|
||||
#if defined(__ia64) || \
|
||||
(defined(__powerpc64__) && _CALL_ELF != 2)
|
||||
expected = ((char**)expected)[0]; // this is "ip"
|
||||
#endif
|
||||
|
||||
if (actual < expected || actual > expected + kRoutineSize) {
|
||||
printf("Test FAILED: actual PC: %p, expected PC: %p\n", actual, expected);
|
||||
return 1;
|
||||
} else {
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
176
trunk/3rdparty/gperftools-2-fit/src/tests/heap-checker-death_unittest.sh
vendored
Executable file
176
trunk/3rdparty/gperftools-2-fit/src/tests/heap-checker-death_unittest.sh
vendored
Executable file
|
@ -0,0 +1,176 @@
|
|||
#!/bin/sh
|
||||
# Copyright (c) 2005, 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.
|
||||
|
||||
# ---
|
||||
# Author: Maxim Lifantsev
|
||||
#
|
||||
# Run the heap checker unittest in a mode where it is supposed to crash and
|
||||
# return an error if it doesn't.
|
||||
|
||||
# We expect BINDIR to be set in the environment.
|
||||
# If not, we set it to some reasonable value.
|
||||
BINDIR="${BINDIR:-.}"
|
||||
|
||||
if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then
|
||||
echo "USAGE: $0 [unittest dir]"
|
||||
echo " By default, unittest_dir=$BINDIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
EXE="${1:-$BINDIR/heap-checker_unittest}"
|
||||
TMPDIR="/tmp/heap_check_death_info"
|
||||
|
||||
ALARM() {
|
||||
# You need perl to run pprof, so I assume it's installed
|
||||
perl -e '
|
||||
$timeout=$ARGV[0]; shift;
|
||||
$retval = 255; # the default retval, for the case where we timed out
|
||||
eval { # need to run in an eval-block to trigger during system()
|
||||
local $SIG{ALRM} = sub { die "alarm\n" }; # \n is required!
|
||||
alarm $timeout;
|
||||
$retval = system(@ARGV);
|
||||
# Make retval bash-style: exit status, or 128+n if terminated by signal n
|
||||
$retval = ($retval & 127) ? (128 + $retval) : ($retval >> 8);
|
||||
alarm 0;
|
||||
};
|
||||
exit $retval; # return system()-retval, or 255 if system() never returned
|
||||
' "$@"
|
||||
}
|
||||
|
||||
# $1: timeout for alarm;
|
||||
# $2: regexp of expected exit code(s);
|
||||
# $3: regexp to match a line in the output;
|
||||
# $4: regexp to not match a line in the output;
|
||||
# $5+ args to pass to $EXE
|
||||
Test() {
|
||||
# Note: make sure these varnames don't conflict with any vars outside Test()!
|
||||
timeout="$1"
|
||||
shift
|
||||
expected_ec="$1"
|
||||
shift
|
||||
expected_regexp="$1"
|
||||
shift
|
||||
unexpected_regexp="$1"
|
||||
shift
|
||||
|
||||
echo -n "Testing $EXE with $@ ... "
|
||||
output="$TMPDIR/output"
|
||||
ALARM $timeout env "$@" $EXE > "$output" 2>&1
|
||||
actual_ec=$?
|
||||
ec_ok=`expr "$actual_ec" : "$expected_ec$" >/dev/null || echo false`
|
||||
matches_ok=`test -z "$expected_regexp" || \
|
||||
grep "$expected_regexp" "$output" >/dev/null 2>&1 || echo false`
|
||||
negmatches_ok=`test -z "$unexpected_regexp" || \
|
||||
! grep "$unexpected_regexp" "$output" >/dev/null 2>&1 || echo false`
|
||||
if $ec_ok && $matches_ok && $negmatches_ok; then
|
||||
echo "PASS"
|
||||
return 0 # 0: success
|
||||
fi
|
||||
# If we get here, we failed. Now we just need to report why
|
||||
echo "FAIL"
|
||||
if [ $actual_ec -eq 255 ]; then # 255 == SIGTERM due to $ALARM
|
||||
echo "Test was taking unexpectedly long time to run and so we aborted it."
|
||||
echo "Try the test case manually or raise the timeout from $timeout"
|
||||
echo "to distinguish test slowness from a real problem."
|
||||
else
|
||||
$ec_ok || \
|
||||
echo "Wrong exit code: expected: '$expected_ec'; actual: $actual_ec"
|
||||
$matches_ok || \
|
||||
echo "Output did not match '$expected_regexp'"
|
||||
$negmatches_ok || \
|
||||
echo "Output unexpectedly matched '$unexpected_regexp'"
|
||||
fi
|
||||
echo "Output from failed run:"
|
||||
echo "---"
|
||||
cat "$output"
|
||||
echo "---"
|
||||
return 1 # 1: failure
|
||||
}
|
||||
|
||||
TMPDIR=/tmp/heap_check_death_info
|
||||
rm -rf $TMPDIR || exit 1
|
||||
mkdir $TMPDIR || exit 2
|
||||
|
||||
export HEAPCHECK=strict # default mode
|
||||
|
||||
# These invocations should pass (0 == PASS):
|
||||
|
||||
# This tests that turning leak-checker off dynamically works fine
|
||||
Test 120 0 "^PASS$" "" HEAPCHECK="" || exit 1
|
||||
|
||||
# This disables threads so we can cause leaks reliably and test finding them
|
||||
Test 120 0 "^PASS$" "" HEAP_CHECKER_TEST_NO_THREADS=1 || exit 2
|
||||
|
||||
# Test that --test_cancel_global_check works
|
||||
Test 20 0 "Canceling .* whole-program .* leak check$" "" \
|
||||
HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_TEST_CANCEL_GLOBAL_CHECK=1 || exit 3
|
||||
Test 20 0 "Canceling .* whole-program .* leak check$" "" \
|
||||
HEAP_CHECKER_TEST_TEST_LOOP_LEAK=1 HEAP_CHECKER_TEST_TEST_CANCEL_GLOBAL_CHECK=1 || exit 4
|
||||
|
||||
# Test that very early log messages are present and controllable:
|
||||
EARLY_MSG="Starting tracking the heap$"
|
||||
|
||||
Test 60 0 "$EARLY_MSG" "" \
|
||||
HEAPCHECK="" HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 \
|
||||
PERFTOOLS_VERBOSE=10 || exit 5
|
||||
Test 60 0 "MemoryRegionMap Init$" "" \
|
||||
HEAPCHECK="" HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 \
|
||||
PERFTOOLS_VERBOSE=11 || exit 6
|
||||
Test 60 0 "" "$EARLY_MSG" \
|
||||
HEAPCHECK="" HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 \
|
||||
PERFTOOLS_VERBOSE=-11 || exit 7
|
||||
|
||||
# These invocations should fail with very high probability,
|
||||
# rather than return 0 or hang (1 == exit(1), 134 == abort(), 139 = SIGSEGV):
|
||||
|
||||
Test 60 1 "Exiting .* because of .* leaks$" "" \
|
||||
HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 || exit 8
|
||||
Test 60 1 "Exiting .* because of .* leaks$" "" \
|
||||
HEAP_CHECKER_TEST_TEST_LOOP_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 || exit 9
|
||||
|
||||
# Test that we produce a reasonable textual leak report.
|
||||
Test 60 1 "MakeALeak" "" \
|
||||
HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 \
|
||||
|| exit 10
|
||||
|
||||
# Test that very early log messages are present and controllable:
|
||||
Test 60 1 "Starting tracking the heap$" "" \
|
||||
HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 PERFTOOLS_VERBOSE=10 \
|
||||
|| exit 11
|
||||
Test 60 1 "" "Starting tracking the heap" \
|
||||
HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 PERFTOOLS_VERBOSE=-10 \
|
||||
|| exit 12
|
||||
|
||||
cd / # so we're not in TMPDIR when we delete it
|
||||
rm -rf $TMPDIR
|
||||
|
||||
echo "PASS"
|
||||
|
||||
exit 0
|
1538
trunk/3rdparty/gperftools-2-fit/src/tests/heap-checker_unittest.cc
vendored
Normal file
1538
trunk/3rdparty/gperftools-2-fit/src/tests/heap-checker_unittest.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
89
trunk/3rdparty/gperftools-2-fit/src/tests/heap-checker_unittest.sh
vendored
Executable file
89
trunk/3rdparty/gperftools-2-fit/src/tests/heap-checker_unittest.sh
vendored
Executable file
|
@ -0,0 +1,89 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2005, 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.
|
||||
|
||||
# ---
|
||||
# Author: Craig Silverstein
|
||||
#
|
||||
# Runs the heap-checker unittest with various environment variables.
|
||||
# This is necessary because we turn on features like the heap profiler
|
||||
# and heap checker via environment variables. This test makes sure
|
||||
# they all play well together.
|
||||
|
||||
# We expect BINDIR and PPROF_PATH to be set in the environment.
|
||||
# If not, we set them to some reasonable values
|
||||
BINDIR="${BINDIR:-.}"
|
||||
PPROF_PATH="${PPROF_PATH:-$BINDIR/src/pprof}"
|
||||
|
||||
if [ "x$1" = "x-h" -o "$1" = "x--help" ]; then
|
||||
echo "USAGE: $0 [unittest dir] [path to pprof]"
|
||||
echo " By default, unittest_dir=$BINDIR, pprof_path=$PPROF_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
HEAP_CHECKER="${1:-$BINDIR/heap-checker_unittest}"
|
||||
PPROF_PATH="${2:-$PPROF_PATH}"
|
||||
|
||||
TMPDIR=/tmp/heap_check_info
|
||||
rm -rf $TMPDIR || exit 2
|
||||
mkdir $TMPDIR || exit 3
|
||||
|
||||
# $1: value of heap-check env. var.
|
||||
run_check() {
|
||||
export PPROF_PATH="$PPROF_PATH"
|
||||
[ -n "$1" ] && export HEAPCHECK="$1" || unset HEAPPROFILE
|
||||
|
||||
echo -n "Testing $HEAP_CHECKER with HEAPCHECK=$1 ... "
|
||||
if $HEAP_CHECKER > $TMPDIR/output 2>&1; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "FAILED"
|
||||
echo "Output from the failed run:"
|
||||
echo "----"
|
||||
cat $TMPDIR/output
|
||||
echo "----"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
# If we set HEAPPROFILE, then we expect it to actually have emitted
|
||||
# a profile. Check that it did.
|
||||
if [ -n "$HEAPPROFILE" ]; then
|
||||
[ -e "$HEAPPROFILE.0001.heap" ] || exit 5
|
||||
fi
|
||||
}
|
||||
|
||||
run_check ""
|
||||
run_check "local"
|
||||
run_check "normal"
|
||||
run_check "strict"
|
||||
|
||||
rm -rf $TMPDIR # clean up
|
||||
|
||||
echo "PASS"
|
168
trunk/3rdparty/gperftools-2-fit/src/tests/heap-profiler_unittest.cc
vendored
Normal file
168
trunk/3rdparty/gperftools-2-fit/src/tests/heap-profiler_unittest.cc
vendored
Normal file
|
@ -0,0 +1,168 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2005, 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.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// A small program that just exercises our heap profiler by allocating
|
||||
// memory and letting the heap-profiler emit a profile. We don't test
|
||||
// threads (TODO). By itself, this unittest tests that the heap-profiler
|
||||
// doesn't crash on simple programs, but its output can be analyzed by
|
||||
// another testing script to actually verify correctness. See, eg,
|
||||
// heap-profiler_unittest.sh.
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h> // for mkdir()
|
||||
#include <sys/stat.h> // for mkdir() on freebsd and os x
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> // for fork()
|
||||
#endif
|
||||
#include <sys/wait.h> // for wait()
|
||||
#include <string>
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include <gperftools/heap-profiler.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
static const int kMaxCount = 100000;
|
||||
int* g_array[kMaxCount]; // an array of int-vectors
|
||||
|
||||
static ATTRIBUTE_NOINLINE void Allocate(int start, int end, int size) {
|
||||
// NOTE: we're using this to prevent gcc 5 from merging otherwise
|
||||
// identical Allocate & Allocate2 functions.
|
||||
VLOG(10, "Allocate");
|
||||
for (int i = start; i < end; ++i) {
|
||||
if (i < kMaxCount)
|
||||
g_array[i] = new int[size];
|
||||
}
|
||||
}
|
||||
|
||||
static ATTRIBUTE_NOINLINE void Allocate2(int start, int end, int size) {
|
||||
VLOG(10, "Allocate2");
|
||||
for (int i = start; i < end; ++i) {
|
||||
if (i < kMaxCount)
|
||||
g_array[i] = new int[size];
|
||||
}
|
||||
}
|
||||
|
||||
static void Deallocate(int start, int end) {
|
||||
for (int i = start; i < end; ++i) {
|
||||
delete[] g_array[i];
|
||||
g_array[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void TestHeapProfilerStartStopIsRunning() {
|
||||
// If you run this with whole-program heap-profiling on, than
|
||||
// IsHeapProfilerRunning should return true.
|
||||
if (!IsHeapProfilerRunning()) {
|
||||
const char* tmpdir = getenv("TMPDIR");
|
||||
if (tmpdir == NULL)
|
||||
tmpdir = "/tmp";
|
||||
mkdir(tmpdir, 0755); // if necessary
|
||||
HeapProfilerStart((string(tmpdir) + "/start_stop").c_str());
|
||||
CHECK(IsHeapProfilerRunning());
|
||||
|
||||
Allocate(0, 40, 100);
|
||||
Deallocate(0, 40);
|
||||
|
||||
HeapProfilerStop();
|
||||
CHECK(!IsHeapProfilerRunning());
|
||||
}
|
||||
}
|
||||
|
||||
static void TestDumpHeapProfiler() {
|
||||
// If you run this with whole-program heap-profiling on, than
|
||||
// IsHeapProfilerRunning should return true.
|
||||
if (!IsHeapProfilerRunning()) {
|
||||
const char* tmpdir = getenv("TMPDIR");
|
||||
if (tmpdir == NULL)
|
||||
tmpdir = "/tmp";
|
||||
mkdir(tmpdir, 0755); // if necessary
|
||||
HeapProfilerStart((string(tmpdir) + "/dump").c_str());
|
||||
CHECK(IsHeapProfilerRunning());
|
||||
|
||||
Allocate(0, 40, 100);
|
||||
Deallocate(0, 40);
|
||||
|
||||
char* output = GetHeapProfile();
|
||||
free(output);
|
||||
HeapProfilerStop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc > 2 || (argc == 2 && argv[1][0] == '-')) {
|
||||
printf("USAGE: %s [number of children to fork]\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
int num_forks = 0;
|
||||
if (argc == 2) {
|
||||
num_forks = atoi(argv[1]);
|
||||
}
|
||||
|
||||
TestHeapProfilerStartStopIsRunning();
|
||||
TestDumpHeapProfiler();
|
||||
|
||||
Allocate(0, 40, 100);
|
||||
Deallocate(0, 40);
|
||||
|
||||
Allocate(0, 40, 100);
|
||||
Allocate(0, 40, 100);
|
||||
Allocate2(40, 400, 1000);
|
||||
Allocate2(400, 1000, 10000);
|
||||
Deallocate(0, 1000);
|
||||
|
||||
Allocate(0, 100, 100000);
|
||||
Deallocate(0, 10);
|
||||
Deallocate(10, 20);
|
||||
Deallocate(90, 100);
|
||||
Deallocate(20, 90);
|
||||
|
||||
while (num_forks-- > 0) {
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
printf("FORK failed!\n");
|
||||
return 1;
|
||||
case 0: // child
|
||||
return execl(argv[0], argv[0], NULL); // run child with no args
|
||||
default:
|
||||
wait(NULL); // we'll let the kids run one at a time
|
||||
}
|
||||
}
|
||||
|
||||
printf("DONE.\n");
|
||||
|
||||
return 0;
|
||||
}
|
147
trunk/3rdparty/gperftools-2-fit/src/tests/heap-profiler_unittest.sh
vendored
Executable file
147
trunk/3rdparty/gperftools-2-fit/src/tests/heap-profiler_unittest.sh
vendored
Executable file
|
@ -0,0 +1,147 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2005, 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.
|
||||
|
||||
# ---
|
||||
# Author: Craig Silverstein
|
||||
#
|
||||
# Runs the heap-profiler unittest and makes sure the profile looks appropriate.
|
||||
#
|
||||
# We run under the assumption that if $HEAP_PROFILER is run with --help,
|
||||
# it prints a usage line of the form
|
||||
# USAGE: <actual executable being run> [...]
|
||||
#
|
||||
# This is because libtool sometimes turns the 'executable' into a
|
||||
# shell script which runs an actual binary somewhere else.
|
||||
|
||||
# We expect BINDIR and PPROF_PATH to be set in the environment.
|
||||
# If not, we set them to some reasonable values
|
||||
BINDIR="${BINDIR:-.}"
|
||||
PPROF_PATH="${PPROF_PATH:-$BINDIR/src/pprof}"
|
||||
|
||||
if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then
|
||||
echo "USAGE: $0 [unittest dir] [path to pprof]"
|
||||
echo " By default, unittest_dir=$BINDIR, pprof_path=$PPROF_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
HEAP_PROFILER="${1:-$BINDIR/heap-profiler_unittest}"
|
||||
PPROF="${2:-$PPROF_PATH}"
|
||||
TEST_TMPDIR=`mktemp -d /tmp/heap-profiler_unittest.XXXXXX`
|
||||
|
||||
# It's meaningful to the profiler, so make sure we know its state
|
||||
unset HEAPPROFILE
|
||||
|
||||
num_failures=0
|
||||
|
||||
# Given one profile (to check the contents of that profile) or two
|
||||
# profiles (to check the diff between the profiles), and a function
|
||||
# name, verify that the function name takes up at least 90% of the
|
||||
# allocated memory. The function name is actually specified first.
|
||||
VerifyMemFunction() {
|
||||
function="$1"
|
||||
shift
|
||||
|
||||
# get program name. Note we have to unset HEAPPROFILE so running
|
||||
# help doesn't overwrite existing profiles.
|
||||
exec=`unset HEAPPROFILE; $HEAP_PROFILER --help | awk '{print $2; exit;}'`
|
||||
|
||||
if [ $# = 2 ]; then
|
||||
[ -f "$1" ] || { echo "Profile not found: $1"; exit 1; }
|
||||
[ -f "$2" ] || { echo "Profile not found: $2"; exit 1; }
|
||||
$PPROF --base="$1" $exec "$2" >"$TEST_TMPDIR/output.pprof" 2>&1
|
||||
else
|
||||
[ -f "$1" ] || { echo "Profile not found: $1"; exit 1; }
|
||||
$PPROF $exec "$1" >"$TEST_TMPDIR/output.pprof" 2>&1
|
||||
fi
|
||||
|
||||
cat "$TEST_TMPDIR/output.pprof" \
|
||||
| tr -d % | awk '$6 ~ /^'$function'$/ && $2 > 90 {exit 1;}'
|
||||
if [ $? != 1 ]; then
|
||||
echo
|
||||
echo "--- Test failed for $function: didn't account for 90% of executable memory"
|
||||
echo "--- Program output:"
|
||||
cat "$TEST_TMPDIR/output"
|
||||
echo "--- pprof output:"
|
||||
cat "$TEST_TMPDIR/output.pprof"
|
||||
echo "---"
|
||||
num_failures=`expr $num_failures + 1`
|
||||
fi
|
||||
}
|
||||
|
||||
VerifyOutputContains() {
|
||||
text="$1"
|
||||
|
||||
if ! grep "$text" "$TEST_TMPDIR/output" >/dev/null 2>&1; then
|
||||
echo "--- Test failed: output does not contain '$text'"
|
||||
echo "--- Program output:"
|
||||
cat "$TEST_TMPDIR/output"
|
||||
echo "---"
|
||||
num_failures=`expr $num_failures + 1`
|
||||
fi
|
||||
}
|
||||
|
||||
HEAPPROFILE="$TEST_TMPDIR/test"
|
||||
HEAP_PROFILE_INUSE_INTERVAL="10240" # need this to be 10Kb
|
||||
HEAP_PROFILE_ALLOCATION_INTERVAL="$HEAP_PROFILE_INUSE_INTERVAL"
|
||||
HEAP_PROFILE_DEALLOCATION_INTERVAL="$HEAP_PROFILE_INUSE_INTERVAL"
|
||||
export HEAPPROFILE
|
||||
export HEAP_PROFILE_INUSE_INTERVAL
|
||||
export HEAP_PROFILE_ALLOCATION_INTERVAL
|
||||
export HEAP_PROFILE_DEALLOCATION_INTERVAL
|
||||
|
||||
# We make the unittest run a child process, to test that the child
|
||||
# process doesn't try to write a heap profile as well and step on the
|
||||
# parent's toes. If it does, we expect the parent-test to fail.
|
||||
$HEAP_PROFILER 1 >$TEST_TMPDIR/output 2>&1 # run program, with 1 child proc
|
||||
|
||||
VerifyMemFunction Allocate2 "$HEAPPROFILE.1329.heap"
|
||||
VerifyMemFunction Allocate "$HEAPPROFILE.1448.heap" "$HEAPPROFILE.1548.heap"
|
||||
|
||||
# Check the child process got to emit its own profile as well.
|
||||
VerifyMemFunction Allocate2 "$HEAPPROFILE"_*.1329.heap
|
||||
VerifyMemFunction Allocate "$HEAPPROFILE"_*.1448.heap "$HEAPPROFILE"_*.1548.heap
|
||||
|
||||
# Make sure we logged both about allocating and deallocating memory
|
||||
VerifyOutputContains "62 MB allocated"
|
||||
VerifyOutputContains "62 MB freed"
|
||||
|
||||
# Now try running without --heap_profile specified, to allow
|
||||
# testing of the HeapProfileStart/Stop functionality.
|
||||
$HEAP_PROFILER >"$TEST_TMPDIR/output2" 2>&1
|
||||
|
||||
rm -rf $TEST_TMPDIR # clean up
|
||||
|
||||
if [ $num_failures = 0 ]; then
|
||||
echo "PASS"
|
||||
else
|
||||
echo "Tests finished with $num_failures failures"
|
||||
fi
|
||||
exit $num_failures
|
62
trunk/3rdparty/gperftools-2-fit/src/tests/large_heap_fragmentation_unittest.cc
vendored
Normal file
62
trunk/3rdparty/gperftools-2-fit/src/tests/large_heap_fragmentation_unittest.cc
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// 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.
|
||||
|
||||
// This is a unit test for exercising fragmentation of large (over 1
|
||||
// meg) page spans. It makes sure that allocations/releases of
|
||||
// increasing memory chunks do not blowup memory
|
||||
// usage. See also https://code.google.com/p/gperftools/issues/detail?id=368
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "common.h"
|
||||
#include <gperftools/malloc_extension.h>
|
||||
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
for (int pass = 1; pass <= 3; pass++) {
|
||||
size_t size = 100*1024*1024;
|
||||
while (size < 500*1024*1024) {
|
||||
void *ptr = malloc(size);
|
||||
free(ptr);
|
||||
size += 20000;
|
||||
|
||||
size_t heap_size = static_cast<size_t>(-1);
|
||||
MallocExtension::instance()->GetNumericProperty("generic.heap_size",
|
||||
&heap_size);
|
||||
|
||||
|
||||
CHECK_LT(heap_size, 1*1024*1024*1024);
|
||||
}
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
197
trunk/3rdparty/gperftools-2-fit/src/tests/low_level_alloc_unittest.cc
vendored
Normal file
197
trunk/3rdparty/gperftools-2-fit/src/tests/low_level_alloc_unittest.cc
vendored
Normal file
|
@ -0,0 +1,197 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2006, 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.
|
||||
*/
|
||||
|
||||
// A test for low_level_alloc.cc
|
||||
|
||||
#include <stdio.h>
|
||||
#include <map>
|
||||
#include "base/low_level_alloc.h"
|
||||
#include "base/logging.h"
|
||||
#include <gperftools/malloc_hook.h>
|
||||
|
||||
using std::map;
|
||||
|
||||
// a block of memory obtained from the allocator
|
||||
struct BlockDesc {
|
||||
char *ptr; // pointer to memory
|
||||
int len; // number of bytes
|
||||
int fill; // filled with data starting with this
|
||||
};
|
||||
|
||||
// Check that the pattern placed in the block d
|
||||
// by RandomizeBlockDesc is still there.
|
||||
static void CheckBlockDesc(const BlockDesc &d) {
|
||||
for (int i = 0; i != d.len; i++) {
|
||||
CHECK((d.ptr[i] & 0xff) == ((d.fill + i) & 0xff));
|
||||
}
|
||||
}
|
||||
|
||||
// Fill the block "*d" with a pattern
|
||||
// starting with a random byte.
|
||||
static void RandomizeBlockDesc(BlockDesc *d) {
|
||||
d->fill = rand() & 0xff;
|
||||
for (int i = 0; i != d->len; i++) {
|
||||
d->ptr[i] = (d->fill + i) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
// Use to indicate to the malloc hooks that
|
||||
// this calls is from LowLevelAlloc.
|
||||
static bool using_low_level_alloc = false;
|
||||
|
||||
// n times, toss a coin, and based on the outcome
|
||||
// either allocate a new block or deallocate an old block.
|
||||
// New blocks are placed in a map with a random key
|
||||
// and initialized with RandomizeBlockDesc().
|
||||
// If keys conflict, the older block is freed.
|
||||
// Old blocks are always checked with CheckBlockDesc()
|
||||
// before being freed. At the end of the run,
|
||||
// all remaining allocated blocks are freed.
|
||||
// If use_new_arena is true, use a fresh arena, and then delete it.
|
||||
// If call_malloc_hook is true and user_arena is true,
|
||||
// allocations and deallocations are reported via the MallocHook
|
||||
// interface.
|
||||
static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
|
||||
typedef map<int, BlockDesc> AllocMap;
|
||||
AllocMap allocated;
|
||||
AllocMap::iterator it;
|
||||
BlockDesc block_desc;
|
||||
int rnd;
|
||||
LowLevelAlloc::Arena *arena = 0;
|
||||
if (use_new_arena) {
|
||||
int32 flags = call_malloc_hook? LowLevelAlloc::kCallMallocHook : 0;
|
||||
arena = LowLevelAlloc::NewArena(flags, LowLevelAlloc::DefaultArena());
|
||||
}
|
||||
for (int i = 0; i != n; i++) {
|
||||
if (i != 0 && i % 10000 == 0) {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
switch(rand() & 1) { // toss a coin
|
||||
case 0: // coin came up heads: add a block
|
||||
using_low_level_alloc = true;
|
||||
block_desc.len = rand() & 0x3fff;
|
||||
block_desc.ptr =
|
||||
reinterpret_cast<char *>(
|
||||
arena == 0
|
||||
? LowLevelAlloc::Alloc(block_desc.len)
|
||||
: LowLevelAlloc::AllocWithArena(block_desc.len, arena));
|
||||
using_low_level_alloc = false;
|
||||
RandomizeBlockDesc(&block_desc);
|
||||
rnd = rand();
|
||||
it = allocated.find(rnd);
|
||||
if (it != allocated.end()) {
|
||||
CheckBlockDesc(it->second);
|
||||
using_low_level_alloc = true;
|
||||
LowLevelAlloc::Free(it->second.ptr);
|
||||
using_low_level_alloc = false;
|
||||
it->second = block_desc;
|
||||
} else {
|
||||
allocated[rnd] = block_desc;
|
||||
}
|
||||
break;
|
||||
case 1: // coin came up tails: remove a block
|
||||
it = allocated.begin();
|
||||
if (it != allocated.end()) {
|
||||
CheckBlockDesc(it->second);
|
||||
using_low_level_alloc = true;
|
||||
LowLevelAlloc::Free(it->second.ptr);
|
||||
using_low_level_alloc = false;
|
||||
allocated.erase(it);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// remove all remaniing blocks
|
||||
while ((it = allocated.begin()) != allocated.end()) {
|
||||
CheckBlockDesc(it->second);
|
||||
using_low_level_alloc = true;
|
||||
LowLevelAlloc::Free(it->second.ptr);
|
||||
using_low_level_alloc = false;
|
||||
allocated.erase(it);
|
||||
}
|
||||
if (use_new_arena) {
|
||||
CHECK(LowLevelAlloc::DeleteArena(arena));
|
||||
}
|
||||
}
|
||||
|
||||
// used for counting allocates and frees
|
||||
static int32 allocates;
|
||||
static int32 frees;
|
||||
|
||||
// called on each alloc if kCallMallocHook specified
|
||||
static void AllocHook(const void *p, size_t size) {
|
||||
if (using_low_level_alloc) {
|
||||
allocates++;
|
||||
}
|
||||
}
|
||||
|
||||
// called on each free if kCallMallocHook specified
|
||||
static void FreeHook(const void *p) {
|
||||
if (using_low_level_alloc) {
|
||||
frees++;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// This is needed by maybe_threads_unittest.sh, which parses argv[0]
|
||||
// to figure out what directory low_level_alloc_unittest is in.
|
||||
if (argc != 1) {
|
||||
fprintf(stderr, "USAGE: %s\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
CHECK(MallocHook::AddNewHook(&AllocHook));
|
||||
CHECK(MallocHook::AddDeleteHook(&FreeHook));
|
||||
CHECK_EQ(allocates, 0);
|
||||
CHECK_EQ(frees, 0);
|
||||
Test(false, false, 50000);
|
||||
CHECK_NE(allocates, 0); // default arena calls hooks
|
||||
CHECK_NE(frees, 0);
|
||||
for (int i = 0; i != 16; i++) {
|
||||
bool call_hooks = ((i & 1) == 1);
|
||||
allocates = 0;
|
||||
frees = 0;
|
||||
Test(true, call_hooks, 15000);
|
||||
if (call_hooks) {
|
||||
CHECK_GT(allocates, 5000); // arena calls hooks
|
||||
CHECK_GT(frees, 5000);
|
||||
} else {
|
||||
CHECK_EQ(allocates, 0); // arena doesn't call hooks
|
||||
CHECK_EQ(frees, 0);
|
||||
}
|
||||
}
|
||||
printf("\nPASS\n");
|
||||
CHECK(MallocHook::RemoveNewHook(&AllocHook));
|
||||
CHECK(MallocHook::RemoveDeleteHook(&FreeHook));
|
||||
return 0;
|
||||
}
|
182
trunk/3rdparty/gperftools-2-fit/src/tests/malloc_extension_c_test.c
vendored
Normal file
182
trunk/3rdparty/gperftools-2-fit/src/tests/malloc_extension_c_test.c
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
/* Copyright (c) 2009, 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.
|
||||
*
|
||||
* ---
|
||||
* Author: Craig Silverstein
|
||||
*
|
||||
* This tests the c shims: malloc_extension_c.h and malloc_hook_c.h.
|
||||
* Mostly, we'll just care that these shims compile under gcc
|
||||
* (*not* g++!)
|
||||
*
|
||||
* NOTE: this is C code, not C++ code!
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h> /* for size_t */
|
||||
#include <gperftools/malloc_extension_c.h>
|
||||
#include <gperftools/malloc_hook_c.h>
|
||||
|
||||
#define FAIL(msg) do { \
|
||||
fprintf(stderr, "FATAL ERROR: %s\n", msg); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
static int g_new_hook_calls = 0;
|
||||
static int g_delete_hook_calls = 0;
|
||||
|
||||
void TestNewHook(const void* ptr, size_t size) {
|
||||
g_new_hook_calls++;
|
||||
}
|
||||
|
||||
void TestDeleteHook(const void* ptr) {
|
||||
g_delete_hook_calls++;
|
||||
}
|
||||
|
||||
static
|
||||
void *forced_malloc(size_t size)
|
||||
{
|
||||
extern void *tc_malloc(size_t);
|
||||
void *rv = tc_malloc(size);
|
||||
if (!rv) {
|
||||
FAIL("malloc is not supposed to fail here");
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void TestMallocHook(void) {
|
||||
/* TODO(csilvers): figure out why we get:
|
||||
* E0100 00:00:00.000000 7383 malloc_hook.cc:244] RAW: google_malloc section is missing, thus InHookCaller is broken!
|
||||
*/
|
||||
#if 0
|
||||
void* result[5];
|
||||
|
||||
if (MallocHook_GetCallerStackTrace(result, sizeof(result)/sizeof(*result),
|
||||
0) < 2) { /* should have this and main */
|
||||
FAIL("GetCallerStackTrace failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!MallocHook_AddNewHook(&TestNewHook)) {
|
||||
FAIL("Failed to add new hook");
|
||||
}
|
||||
if (!MallocHook_AddDeleteHook(&TestDeleteHook)) {
|
||||
FAIL("Failed to add delete hook");
|
||||
}
|
||||
|
||||
free(forced_malloc(10));
|
||||
free(forced_malloc(20));
|
||||
if (g_new_hook_calls != 2) {
|
||||
FAIL("Wrong number of calls to the new hook");
|
||||
}
|
||||
if (g_delete_hook_calls != 2) {
|
||||
FAIL("Wrong number of calls to the delete hook");
|
||||
}
|
||||
if (!MallocHook_RemoveNewHook(&TestNewHook)) {
|
||||
FAIL("Failed to remove new hook");
|
||||
}
|
||||
if (!MallocHook_RemoveDeleteHook(&TestDeleteHook)) {
|
||||
FAIL("Failed to remove delete hook");
|
||||
}
|
||||
|
||||
free(forced_malloc(10));
|
||||
free(forced_malloc(20));
|
||||
if (g_new_hook_calls != 2) {
|
||||
FAIL("Wrong number of calls to the new hook");
|
||||
}
|
||||
|
||||
MallocHook_SetNewHook(&TestNewHook);
|
||||
MallocHook_SetDeleteHook(&TestDeleteHook);
|
||||
|
||||
free(forced_malloc(10));
|
||||
free(forced_malloc(20));
|
||||
if (g_new_hook_calls != 4) {
|
||||
FAIL("Wrong number of calls to the singular new hook");
|
||||
}
|
||||
|
||||
if (MallocHook_SetNewHook(NULL) == NULL) {
|
||||
FAIL("Failed to set new hook");
|
||||
}
|
||||
if (MallocHook_SetDeleteHook(NULL) == NULL) {
|
||||
FAIL("Failed to set delete hook");
|
||||
}
|
||||
}
|
||||
|
||||
void TestMallocExtension(void) {
|
||||
int blocks;
|
||||
size_t total;
|
||||
int hist[64];
|
||||
char buffer[200];
|
||||
char* x = (char*)malloc(10);
|
||||
|
||||
MallocExtension_VerifyAllMemory();
|
||||
MallocExtension_VerifyMallocMemory(x);
|
||||
MallocExtension_MallocMemoryStats(&blocks, &total, hist);
|
||||
MallocExtension_GetStats(buffer, sizeof(buffer));
|
||||
if (!MallocExtension_GetNumericProperty("generic.current_allocated_bytes",
|
||||
&total)) {
|
||||
FAIL("GetNumericProperty failed for generic.current_allocated_bytes");
|
||||
}
|
||||
if (total < 10) {
|
||||
FAIL("GetNumericProperty had bad return for generic.current_allocated_bytes");
|
||||
}
|
||||
if (!MallocExtension_GetNumericProperty("generic.current_allocated_bytes",
|
||||
&total)) {
|
||||
FAIL("GetNumericProperty failed for generic.current_allocated_bytes");
|
||||
}
|
||||
MallocExtension_MarkThreadIdle();
|
||||
MallocExtension_MarkThreadBusy();
|
||||
MallocExtension_ReleaseToSystem(1);
|
||||
MallocExtension_ReleaseFreeMemory();
|
||||
if (MallocExtension_GetEstimatedAllocatedSize(10) < 10) {
|
||||
FAIL("GetEstimatedAllocatedSize returned a bad value (too small)");
|
||||
}
|
||||
if (MallocExtension_GetAllocatedSize(x) < 10) {
|
||||
FAIL("GetEstimatedAllocatedSize returned a bad value (too small)");
|
||||
}
|
||||
if (MallocExtension_GetOwnership(x) != MallocExtension_kOwned) {
|
||||
FAIL("DidAllocatePtr returned a bad value (kNotOwned)");
|
||||
}
|
||||
/* TODO(csilvers): this relies on undocumented behavior that
|
||||
GetOwnership works on stack-allocated variables. Use a better test. */
|
||||
if (MallocExtension_GetOwnership(hist) != MallocExtension_kNotOwned) {
|
||||
FAIL("DidAllocatePtr returned a bad value (kOwned)");
|
||||
}
|
||||
|
||||
free(x);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
TestMallocHook();
|
||||
TestMallocExtension();
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
98
trunk/3rdparty/gperftools-2-fit/src/tests/malloc_extension_test.cc
vendored
Normal file
98
trunk/3rdparty/gperftools-2-fit/src/tests/malloc_extension_test.cc
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// 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.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// Simple test of malloc_extension. Includes test of C shims.
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "base/logging.h"
|
||||
#include <gperftools/malloc_extension.h>
|
||||
#include <gperftools/malloc_extension_c.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
void* a = malloc(1000);
|
||||
|
||||
size_t cxx_bytes_used, c_bytes_used;
|
||||
ASSERT_TRUE(MallocExtension::instance()->GetNumericProperty(
|
||||
"generic.current_allocated_bytes", &cxx_bytes_used));
|
||||
ASSERT_TRUE(MallocExtension_GetNumericProperty(
|
||||
"generic.current_allocated_bytes", &c_bytes_used));
|
||||
ASSERT_GT(cxx_bytes_used, 1000);
|
||||
ASSERT_EQ(cxx_bytes_used, c_bytes_used);
|
||||
|
||||
ASSERT_TRUE(MallocExtension::instance()->VerifyAllMemory());
|
||||
ASSERT_TRUE(MallocExtension_VerifyAllMemory());
|
||||
|
||||
ASSERT_EQ(MallocExtension::kOwned,
|
||||
MallocExtension::instance()->GetOwnership(a));
|
||||
// TODO(csilvers): this relies on undocumented behavior that
|
||||
// GetOwnership works on stack-allocated variables. Use a better test.
|
||||
ASSERT_EQ(MallocExtension::kNotOwned,
|
||||
MallocExtension::instance()->GetOwnership(&cxx_bytes_used));
|
||||
ASSERT_EQ(MallocExtension::kNotOwned,
|
||||
MallocExtension::instance()->GetOwnership(NULL));
|
||||
ASSERT_GE(MallocExtension::instance()->GetAllocatedSize(a), 1000);
|
||||
// This is just a sanity check. If we allocated too much, tcmalloc is broken
|
||||
ASSERT_LE(MallocExtension::instance()->GetAllocatedSize(a), 5000);
|
||||
ASSERT_GE(MallocExtension::instance()->GetEstimatedAllocatedSize(1000), 1000);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
void *p = malloc(i);
|
||||
ASSERT_GE(MallocExtension::instance()->GetAllocatedSize(p),
|
||||
MallocExtension::instance()->GetEstimatedAllocatedSize(i));
|
||||
free(p);
|
||||
}
|
||||
|
||||
// Check the c-shim version too.
|
||||
ASSERT_EQ(MallocExtension_kOwned, MallocExtension_GetOwnership(a));
|
||||
ASSERT_EQ(MallocExtension_kNotOwned,
|
||||
MallocExtension_GetOwnership(&cxx_bytes_used));
|
||||
ASSERT_EQ(MallocExtension_kNotOwned, MallocExtension_GetOwnership(NULL));
|
||||
ASSERT_GE(MallocExtension_GetAllocatedSize(a), 1000);
|
||||
ASSERT_LE(MallocExtension_GetAllocatedSize(a), 5000);
|
||||
ASSERT_GE(MallocExtension_GetEstimatedAllocatedSize(1000), 1000);
|
||||
|
||||
free(a);
|
||||
|
||||
// Verify that the .cc file and .h file have the same enum values.
|
||||
ASSERT_EQ(static_cast<int>(MallocExtension::kUnknownOwnership),
|
||||
static_cast<int>(MallocExtension_kUnknownOwnership));
|
||||
ASSERT_EQ(static_cast<int>(MallocExtension::kOwned),
|
||||
static_cast<int>(MallocExtension_kOwned));
|
||||
ASSERT_EQ(static_cast<int>(MallocExtension::kNotOwned),
|
||||
static_cast<int>(MallocExtension_kNotOwned));
|
||||
|
||||
printf("DONE\n");
|
||||
return 0;
|
||||
}
|
367
trunk/3rdparty/gperftools-2-fit/src/tests/malloc_hook_test.cc
vendored
Normal file
367
trunk/3rdparty/gperftools-2-fit/src/tests/malloc_hook_test.cc
vendored
Normal file
|
@ -0,0 +1,367 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2011, 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.
|
||||
|
||||
// ----
|
||||
// Author: llib@google.com (Bill Clarke)
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_MMAP
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> // for sleep()
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <gperftools/malloc_hook.h>
|
||||
#include "malloc_hook-inl.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/simple_mutex.h"
|
||||
#include "base/sysinfo.h"
|
||||
#include "tests/testutil.h"
|
||||
|
||||
// On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
|
||||
// form of the name instead.
|
||||
#ifndef MAP_ANONYMOUS
|
||||
# define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
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",
|
||||
static_cast<int>(g_testlist.size()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sleep(int seconds) {
|
||||
#ifdef _MSC_VER
|
||||
_sleep(seconds * 1000); // Windows's _sleep takes milliseconds argument
|
||||
#else
|
||||
sleep(seconds);
|
||||
#endif
|
||||
}
|
||||
|
||||
using std::min;
|
||||
using base::internal::kHookListMaxValues;
|
||||
|
||||
// Since HookList is a template and is defined in malloc_hook.cc, we can only
|
||||
// use an instantiation of it from malloc_hook.cc. We then reinterpret those
|
||||
// values as integers for testing.
|
||||
typedef base::internal::HookList<MallocHook::NewHook> TestHookList;
|
||||
|
||||
int TestHookList_Traverse(const TestHookList& list, uintptr_t* output_array, int n) {
|
||||
MallocHook::NewHook values_as_hooks[kHookListMaxValues];
|
||||
int result = list.Traverse(values_as_hooks, min(n, kHookListMaxValues));
|
||||
for (int i = 0; i < result; ++i) {
|
||||
output_array[i] = reinterpret_cast<const uintptr_t>(*values_as_hooks[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TestHookList_Add(TestHookList* list, int val) {
|
||||
return list->Add(reinterpret_cast<MallocHook::NewHook>(val));
|
||||
}
|
||||
|
||||
bool TestHookList_Remove(TestHookList* list, int val) {
|
||||
return list->Remove(reinterpret_cast<MallocHook::NewHook>(val));
|
||||
}
|
||||
|
||||
// Note that this is almost the same as INIT_HOOK_LIST in malloc_hook.cc without
|
||||
// the cast.
|
||||
#define INIT_HOOK_LIST(initial_value) { 1, { initial_value } }
|
||||
|
||||
TEST(HookListTest, InitialValueExists) {
|
||||
TestHookList list = INIT_HOOK_LIST(69);
|
||||
uintptr_t values[2] = { 0, 0 };
|
||||
EXPECT_EQ(1, TestHookList_Traverse(list, values, 2));
|
||||
EXPECT_EQ(69, values[0]);
|
||||
EXPECT_EQ(1, list.priv_end);
|
||||
}
|
||||
|
||||
TEST(HookListTest, CanRemoveInitialValue) {
|
||||
TestHookList list = INIT_HOOK_LIST(69);
|
||||
ASSERT_TRUE(TestHookList_Remove(&list, 69));
|
||||
EXPECT_EQ(0, list.priv_end);
|
||||
|
||||
uintptr_t values[2] = { 0, 0 };
|
||||
EXPECT_EQ(0, TestHookList_Traverse(list, values, 2));
|
||||
}
|
||||
|
||||
TEST(HookListTest, AddAppends) {
|
||||
TestHookList list = INIT_HOOK_LIST(69);
|
||||
ASSERT_TRUE(TestHookList_Add(&list, 42));
|
||||
EXPECT_EQ(2, list.priv_end);
|
||||
|
||||
uintptr_t values[2] = { 0, 0 };
|
||||
EXPECT_EQ(2, TestHookList_Traverse(list, values, 2));
|
||||
EXPECT_EQ(69, values[0]);
|
||||
EXPECT_EQ(42, values[1]);
|
||||
}
|
||||
|
||||
TEST(HookListTest, RemoveWorksAndWillClearSize) {
|
||||
TestHookList list = INIT_HOOK_LIST(69);
|
||||
ASSERT_TRUE(TestHookList_Add(&list, 42));
|
||||
|
||||
ASSERT_TRUE(TestHookList_Remove(&list, 69));
|
||||
EXPECT_EQ(2, list.priv_end);
|
||||
|
||||
uintptr_t values[2] = { 0, 0 };
|
||||
EXPECT_EQ(1, TestHookList_Traverse(list, values, 2));
|
||||
EXPECT_EQ(42, values[0]);
|
||||
|
||||
ASSERT_TRUE(TestHookList_Remove(&list, 42));
|
||||
EXPECT_EQ(0, list.priv_end);
|
||||
EXPECT_EQ(0, TestHookList_Traverse(list, values, 2));
|
||||
}
|
||||
|
||||
TEST(HookListTest, AddPrependsAfterRemove) {
|
||||
TestHookList list = INIT_HOOK_LIST(69);
|
||||
ASSERT_TRUE(TestHookList_Add(&list, 42));
|
||||
|
||||
ASSERT_TRUE(TestHookList_Remove(&list, 69));
|
||||
EXPECT_EQ(2, list.priv_end);
|
||||
|
||||
ASSERT_TRUE(TestHookList_Add(&list, 7));
|
||||
EXPECT_EQ(2, list.priv_end);
|
||||
|
||||
uintptr_t values[2] = { 0, 0 };
|
||||
EXPECT_EQ(2, TestHookList_Traverse(list, values, 2));
|
||||
EXPECT_EQ(7, values[0]);
|
||||
EXPECT_EQ(42, values[1]);
|
||||
}
|
||||
|
||||
TEST(HookListTest, InvalidAddRejected) {
|
||||
TestHookList list = INIT_HOOK_LIST(69);
|
||||
EXPECT_FALSE(TestHookList_Add(&list, 0));
|
||||
|
||||
uintptr_t values[2] = { 0, 0 };
|
||||
EXPECT_EQ(1, TestHookList_Traverse(list, values, 2));
|
||||
EXPECT_EQ(69, values[0]);
|
||||
EXPECT_EQ(1, list.priv_end);
|
||||
}
|
||||
|
||||
TEST(HookListTest, FillUpTheList) {
|
||||
TestHookList list = INIT_HOOK_LIST(69);
|
||||
int num_inserts = 0;
|
||||
while (TestHookList_Add(&list, ++num_inserts))
|
||||
;
|
||||
EXPECT_EQ(kHookListMaxValues, num_inserts);
|
||||
EXPECT_EQ(kHookListMaxValues, list.priv_end);
|
||||
|
||||
uintptr_t values[kHookListMaxValues + 1];
|
||||
EXPECT_EQ(kHookListMaxValues, TestHookList_Traverse(list, values,
|
||||
kHookListMaxValues));
|
||||
EXPECT_EQ(69, values[0]);
|
||||
for (int i = 1; i < kHookListMaxValues; ++i) {
|
||||
EXPECT_EQ(i, values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void MultithreadedTestThread(TestHookList* list, int shift,
|
||||
int thread_num) {
|
||||
string message;
|
||||
char buf[64];
|
||||
for (int i = 1; i < 1000; ++i) {
|
||||
// In each loop, we insert a unique value, check it exists, remove it, and
|
||||
// check it doesn't exist. We also record some stats to log at the end of
|
||||
// each thread. Each insertion location and the length of the list is
|
||||
// non-deterministic (except for the very first one, over all threads, and
|
||||
// after the very last one the list should be empty).
|
||||
int value = (i << shift) + thread_num;
|
||||
EXPECT_TRUE(TestHookList_Add(list, value));
|
||||
sched_yield(); // Ensure some more interleaving.
|
||||
uintptr_t values[kHookListMaxValues + 1];
|
||||
int num_values = TestHookList_Traverse(*list, values, kHookListMaxValues);
|
||||
EXPECT_LT(0, num_values);
|
||||
int value_index;
|
||||
for (value_index = 0;
|
||||
value_index < num_values && values[value_index] != value;
|
||||
++value_index)
|
||||
;
|
||||
EXPECT_LT(value_index, num_values); // Should have found value.
|
||||
snprintf(buf, sizeof(buf), "[%d/%d; ", value_index, num_values);
|
||||
message += buf;
|
||||
sched_yield();
|
||||
EXPECT_TRUE(TestHookList_Remove(list, value));
|
||||
sched_yield();
|
||||
num_values = TestHookList_Traverse(*list, values, kHookListMaxValues);
|
||||
for (value_index = 0;
|
||||
value_index < num_values && values[value_index] != value;
|
||||
++value_index)
|
||||
;
|
||||
EXPECT_EQ(value_index, num_values); // Should not have found value.
|
||||
snprintf(buf, sizeof(buf), "%d]", num_values);
|
||||
message += buf;
|
||||
sched_yield();
|
||||
}
|
||||
fprintf(stderr, "thread %d: %s\n", thread_num, message.c_str());
|
||||
}
|
||||
|
||||
static volatile int num_threads_remaining;
|
||||
static TestHookList list = INIT_HOOK_LIST(69);
|
||||
static Mutex threadcount_lock;
|
||||
|
||||
void MultithreadedTestThreadRunner(int thread_num) {
|
||||
// Wait for all threads to start running.
|
||||
{
|
||||
MutexLock ml(&threadcount_lock);
|
||||
assert(num_threads_remaining > 0);
|
||||
--num_threads_remaining;
|
||||
|
||||
// We should use condvars and the like, but for this test, we'll
|
||||
// go simple and busy-wait.
|
||||
while (num_threads_remaining > 0) {
|
||||
threadcount_lock.Unlock();
|
||||
Sleep(1);
|
||||
threadcount_lock.Lock();
|
||||
}
|
||||
}
|
||||
|
||||
// shift is the smallest number such that (1<<shift) > kHookListMaxValues
|
||||
int shift = 0;
|
||||
for (int i = kHookListMaxValues; i > 0; i >>= 1)
|
||||
shift += 1;
|
||||
|
||||
MultithreadedTestThread(&list, shift, thread_num);
|
||||
}
|
||||
|
||||
|
||||
TEST(HookListTest, MultithreadedTest) {
|
||||
ASSERT_TRUE(TestHookList_Remove(&list, 69));
|
||||
ASSERT_EQ(0, list.priv_end);
|
||||
|
||||
// Run kHookListMaxValues thread, each running MultithreadedTestThread.
|
||||
// First, we need to set up the rest of the globals.
|
||||
num_threads_remaining = kHookListMaxValues; // a global var
|
||||
RunManyThreadsWithId(&MultithreadedTestThreadRunner, num_threads_remaining,
|
||||
1 << 15);
|
||||
|
||||
uintptr_t values[kHookListMaxValues + 1];
|
||||
EXPECT_EQ(0, TestHookList_Traverse(list, values, kHookListMaxValues));
|
||||
EXPECT_EQ(0, list.priv_end);
|
||||
}
|
||||
|
||||
// We only do mmap-hooking on (some) linux systems.
|
||||
#if defined(HAVE_MMAP) && defined(__linux) && \
|
||||
(defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
|
||||
|
||||
int mmap_calls = 0;
|
||||
int mmap_matching_calls = 0;
|
||||
int munmap_calls = 0;
|
||||
int munmap_matching_calls = 0;
|
||||
const int kMmapMagicFd = 1;
|
||||
void* const kMmapMagicPointer = reinterpret_cast<void*>(1);
|
||||
|
||||
int MmapReplacement(const void* start,
|
||||
size_t size,
|
||||
int protection,
|
||||
int flags,
|
||||
int fd,
|
||||
off_t offset,
|
||||
void** result) {
|
||||
++mmap_calls;
|
||||
if (fd == kMmapMagicFd) {
|
||||
++mmap_matching_calls;
|
||||
*result = kMmapMagicPointer;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int MunmapReplacement(const void* ptr, size_t size, int* result) {
|
||||
++munmap_calls;
|
||||
if (ptr == kMmapMagicPointer) {
|
||||
++munmap_matching_calls;
|
||||
*result = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST(MallocMookTest, MmapReplacements) {
|
||||
mmap_calls = mmap_matching_calls = munmap_calls = munmap_matching_calls = 0;
|
||||
MallocHook::SetMmapReplacement(&MmapReplacement);
|
||||
MallocHook::SetMunmapReplacement(&MunmapReplacement);
|
||||
EXPECT_EQ(kMmapMagicPointer, mmap(NULL, 1, PROT_READ, MAP_PRIVATE,
|
||||
kMmapMagicFd, 0));
|
||||
EXPECT_EQ(1, mmap_matching_calls);
|
||||
|
||||
char* ptr = reinterpret_cast<char*>(
|
||||
mmap(NULL, 1, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
EXPECT_EQ(2, mmap_calls);
|
||||
EXPECT_EQ(1, mmap_matching_calls);
|
||||
ASSERT_NE(MAP_FAILED, ptr);
|
||||
*ptr = 'a';
|
||||
|
||||
EXPECT_EQ(0, munmap(kMmapMagicPointer, 1));
|
||||
EXPECT_EQ(1, munmap_calls);
|
||||
EXPECT_EQ(1, munmap_matching_calls);
|
||||
|
||||
EXPECT_EQ(0, munmap(ptr, 1));
|
||||
EXPECT_EQ(2, munmap_calls);
|
||||
EXPECT_EQ(1, munmap_matching_calls);
|
||||
|
||||
// The DEATH test below is flaky, because we've just munmapped the memory,
|
||||
// making it available for mmap()ing again. There is no guarantee that it
|
||||
// will stay unmapped, and in fact it gets reused ~10% of the time.
|
||||
// It the area is reused, then not only we don't die, but we also corrupt
|
||||
// whoever owns that memory now.
|
||||
// EXPECT_DEATH(*ptr = 'a', "SIGSEGV");
|
||||
}
|
||||
#endif // #ifdef HAVE_MMAP && linux && ...
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
127
trunk/3rdparty/gperftools-2-fit/src/tests/markidle_unittest.cc
vendored
Normal file
127
trunk/3rdparty/gperftools-2-fit/src/tests/markidle_unittest.cc
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2003, 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.
|
||||
|
||||
// ---
|
||||
// Author: Sanjay Ghemawat
|
||||
//
|
||||
// MallocExtension::MarkThreadIdle() testing
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include "base/logging.h"
|
||||
#include <gperftools/malloc_extension.h>
|
||||
#include "tests/testutil.h" // for RunThread()
|
||||
|
||||
// Helper routine to do lots of allocations
|
||||
static void TestAllocation() {
|
||||
static const int kNum = 100;
|
||||
void* ptr[kNum];
|
||||
for (int size = 8; size <= 65536; size*=2) {
|
||||
for (int i = 0; i < kNum; i++) {
|
||||
ptr[i] = malloc(size);
|
||||
}
|
||||
for (int i = 0; i < kNum; i++) {
|
||||
free(ptr[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Routine that does a bunch of MarkThreadIdle() calls in sequence
|
||||
// without any intervening allocations
|
||||
static void MultipleIdleCalls() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
MallocExtension::instance()->MarkThreadIdle();
|
||||
}
|
||||
}
|
||||
|
||||
// Routine that does a bunch of MarkThreadIdle() calls in sequence
|
||||
// with intervening allocations
|
||||
static void MultipleIdleNonIdlePhases() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
TestAllocation();
|
||||
MallocExtension::instance()->MarkThreadIdle();
|
||||
}
|
||||
}
|
||||
|
||||
// Get current thread cache usage
|
||||
static size_t GetTotalThreadCacheSize() {
|
||||
size_t result;
|
||||
CHECK(MallocExtension::instance()->GetNumericProperty(
|
||||
"tcmalloc.current_total_thread_cache_bytes",
|
||||
&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check that MarkThreadIdle() actually reduces the amount
|
||||
// of per-thread memory.
|
||||
static void TestIdleUsage() {
|
||||
const size_t original = GetTotalThreadCacheSize();
|
||||
|
||||
TestAllocation();
|
||||
const size_t post_allocation = GetTotalThreadCacheSize();
|
||||
CHECK_GT(post_allocation, original);
|
||||
|
||||
MallocExtension::instance()->MarkThreadIdle();
|
||||
const size_t post_idle = GetTotalThreadCacheSize();
|
||||
CHECK_LE(post_idle, original);
|
||||
|
||||
// Log after testing because logging can allocate heap memory.
|
||||
VLOG(0, "Original usage: %zu\n", original);
|
||||
VLOG(0, "Post allocation: %zu\n", post_allocation);
|
||||
VLOG(0, "Post idle: %zu\n", post_idle);
|
||||
}
|
||||
|
||||
static void TestTemporarilyIdleUsage() {
|
||||
const size_t original = MallocExtension::instance()->GetThreadCacheSize();
|
||||
|
||||
TestAllocation();
|
||||
const size_t post_allocation = MallocExtension::instance()->GetThreadCacheSize();
|
||||
CHECK_GT(post_allocation, original);
|
||||
|
||||
MallocExtension::instance()->MarkThreadIdle();
|
||||
const size_t post_idle = MallocExtension::instance()->GetThreadCacheSize();
|
||||
CHECK_EQ(post_idle, 0);
|
||||
|
||||
// Log after testing because logging can allocate heap memory.
|
||||
VLOG(0, "Original usage: %zu\n", original);
|
||||
VLOG(0, "Post allocation: %zu\n", post_allocation);
|
||||
VLOG(0, "Post idle: %zu\n", post_idle);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
RunThread(&TestIdleUsage);
|
||||
RunThread(&TestAllocation);
|
||||
RunThread(&MultipleIdleCalls);
|
||||
RunThread(&MultipleIdleNonIdlePhases);
|
||||
RunThread(&TestTemporarilyIdleUsage);
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
79
trunk/3rdparty/gperftools-2-fit/src/tests/maybe_threads_unittest.sh
vendored
Executable file
79
trunk/3rdparty/gperftools-2-fit/src/tests/maybe_threads_unittest.sh
vendored
Executable file
|
@ -0,0 +1,79 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2007, 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.
|
||||
|
||||
# ---
|
||||
# Author: Craig Silverstein
|
||||
#
|
||||
# maybe_threads.cc was written to allow LD_PRELOAD=libtcmalloc.so to
|
||||
# work even on binaries that were not linked with pthreads. This
|
||||
# unittest tests that, by running low_level_alloc_unittest with an
|
||||
# LD_PRELOAD. (low_level_alloc_unittest was chosen because it doesn't
|
||||
# link in tcmalloc.)
|
||||
#
|
||||
# We assume all the .so files are in the same directory as both
|
||||
# addressmap_unittest and profiler1_unittest. The reason we need
|
||||
# profiler1_unittest is because it's instrumented to show the directory
|
||||
# it's "really" in when run without any args. In practice this will either
|
||||
# be BINDIR, or, when using libtool, BINDIR/.lib.
|
||||
|
||||
# We expect BINDIR to be set in the environment.
|
||||
# If not, we set them to some reasonable values.
|
||||
BINDIR="${BINDIR:-.}"
|
||||
|
||||
if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then
|
||||
echo "USAGE: $0 [unittest dir]"
|
||||
echo " By default, unittest_dir=$BINDIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
UNITTEST_DIR=${1:-$BINDIR}
|
||||
|
||||
# Figure out the "real" unittest directory. Also holds the .so files.
|
||||
UNITTEST_DIR=`$UNITTEST_DIR/low_level_alloc_unittest --help 2>&1 \
|
||||
| awk '{print $2; exit;}' \
|
||||
| xargs dirname`
|
||||
|
||||
# Figure out where libtcmalloc lives. It should be in UNITTEST_DIR,
|
||||
# but with libtool it might be in a subdir.
|
||||
if [ -r "$UNITTEST_DIR/libtcmalloc_minimal.so" ]; then
|
||||
LIB_PATH="$UNITTEST_DIR/libtcmalloc_minimal.so"
|
||||
elif [ -r "$UNITTEST_DIR/.libs/libtcmalloc_minimal.so" ]; then
|
||||
LIB_PATH="$UNITTEST_DIR/.libs/libtcmalloc_minimal.so"
|
||||
elif [ -r "$UNITTEST_DIR/libtcmalloc_minimal.dylib" ]; then # for os x
|
||||
LIB_PATH="$UNITTEST_DIR/libtcmalloc_minimal.dylib"
|
||||
elif [ -r "$UNITTEST_DIR/.libs/libtcmalloc_minimal.dylib" ]; then
|
||||
LIB_PATH="$UNITTEST_DIR/.libs/libtcmalloc_minimal.dylib"
|
||||
else
|
||||
echo "Cannot run $0: cannot find libtcmalloc_minimal.so"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
LD_PRELOAD="$LIB_PATH" $UNITTEST_DIR/low_level_alloc_unittest
|
221
trunk/3rdparty/gperftools-2-fit/src/tests/memalign_unittest.cc
vendored
Normal file
221
trunk/3rdparty/gperftools-2-fit/src/tests/memalign_unittest.cc
vendored
Normal file
|
@ -0,0 +1,221 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2004, 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.
|
||||
|
||||
// ---
|
||||
// Author: Sanjay Ghemawat
|
||||
//
|
||||
// Check memalign related routines.
|
||||
//
|
||||
// We can't really do a huge amount of checking, but at the very
|
||||
// least, the following code checks that return values are properly
|
||||
// aligned, and that writing into the objects works.
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
|
||||
// Complicated ordering requirements. tcmalloc.h defines (indirectly)
|
||||
// _POSIX_C_SOURCE, which it needs so stdlib.h defines posix_memalign.
|
||||
// unistd.h, on the other hand, requires _POSIX_C_SOURCE to be unset,
|
||||
// at least on Mac OS X, in order to define getpagesize. The solution
|
||||
// is to #include unistd.h first. This is safe because unistd.h
|
||||
// doesn't sub-include stdlib.h, so we'll still get posix_memalign
|
||||
// when we #include stdlib.h. Blah.
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> // for getpagesize()
|
||||
#endif
|
||||
#include "tcmalloc.h" // must come early, to pick up posix_memalign
|
||||
#include <assert.h>
|
||||
#include <stdlib.h> // defines posix_memalign
|
||||
#include <stdio.h> // for the printf at the end
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h> // for uintptr_t
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> // for getpagesize()
|
||||
#endif
|
||||
// Malloc can be in several places on older versions of OS X.
|
||||
#if defined(HAVE_MALLOC_H)
|
||||
#include <malloc.h> // for memalign() and valloc()
|
||||
#elif defined(HAVE_MALLOC_MALLOC_H)
|
||||
#include <malloc/malloc.h>
|
||||
#elif defined(HAVE_SYS_MALLOC_H)
|
||||
#include <sys/malloc.h>
|
||||
#endif
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "tests/testutil.h"
|
||||
|
||||
|
||||
// Return the next interesting size/delta to check. Returns -1 if no more.
|
||||
static int NextSize(int size) {
|
||||
if (size < 100) {
|
||||
return size+1;
|
||||
} else if (size < 1048576) {
|
||||
// Find next power of two
|
||||
int power = 1;
|
||||
while (power < size) {
|
||||
power <<= 1;
|
||||
}
|
||||
|
||||
// Yield (power-1, power, power+1)
|
||||
if (size < power-1) {
|
||||
return power-1;
|
||||
} else if (size == power-1) {
|
||||
return power;
|
||||
} else {
|
||||
assert(size == power);
|
||||
return power+1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Shortform for cast
|
||||
static uintptr_t Number(void* p) {
|
||||
return reinterpret_cast<uintptr_t>(p);
|
||||
}
|
||||
|
||||
// Check alignment
|
||||
static void CheckAlignment(void* p, int align) {
|
||||
if ((Number(p) & (align-1)) != 0)
|
||||
LOG(FATAL, "wrong alignment; wanted 0x%x; got %p\n", align, p);
|
||||
}
|
||||
|
||||
// Fill a buffer of the specified size with a predetermined pattern
|
||||
static void Fill(void* p, int n, char seed) {
|
||||
unsigned char* buffer = reinterpret_cast<unsigned char*>(p);
|
||||
for (int i = 0; i < n; i++) {
|
||||
buffer[i] = ((seed + i) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the specified buffer has the predetermined pattern
|
||||
// generated by Fill()
|
||||
static bool Valid(const void* p, int n, char seed) {
|
||||
const unsigned char* buffer = reinterpret_cast<const unsigned char*>(p);
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (buffer[i] != ((seed + i) & 0xff)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
SetTestResourceLimit();
|
||||
|
||||
// Try allocating data with a bunch of alignments and sizes
|
||||
for (int a = 1; a < 1048576; a *= 2) {
|
||||
for (int s = 0; s != -1; s = NextSize(s)) {
|
||||
void* ptr = memalign(a, s);
|
||||
CheckAlignment(ptr, a);
|
||||
Fill(ptr, s, 'x');
|
||||
CHECK(Valid(ptr, s, 'x'));
|
||||
free(ptr);
|
||||
|
||||
if ((a >= sizeof(void*)) && ((a & (a-1)) == 0)) {
|
||||
CHECK(posix_memalign(&ptr, a, s) == 0);
|
||||
CheckAlignment(ptr, a);
|
||||
Fill(ptr, s, 'y');
|
||||
CHECK(Valid(ptr, s, 'y'));
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Check various corner cases
|
||||
void* p1 = memalign(1<<20, 1<<19);
|
||||
void* p2 = memalign(1<<19, 1<<19);
|
||||
void* p3 = memalign(1<<21, 1<<19);
|
||||
CheckAlignment(p1, 1<<20);
|
||||
CheckAlignment(p2, 1<<19);
|
||||
CheckAlignment(p3, 1<<21);
|
||||
Fill(p1, 1<<19, 'a');
|
||||
Fill(p2, 1<<19, 'b');
|
||||
Fill(p3, 1<<19, 'c');
|
||||
CHECK(Valid(p1, 1<<19, 'a'));
|
||||
CHECK(Valid(p2, 1<<19, 'b'));
|
||||
CHECK(Valid(p3, 1<<19, 'c'));
|
||||
free(p1);
|
||||
free(p2);
|
||||
free(p3);
|
||||
}
|
||||
|
||||
{
|
||||
// posix_memalign
|
||||
void* ptr;
|
||||
CHECK(posix_memalign(&ptr, 0, 1) == EINVAL);
|
||||
CHECK(posix_memalign(&ptr, sizeof(void*)/2, 1) == EINVAL);
|
||||
CHECK(posix_memalign(&ptr, sizeof(void*)+1, 1) == EINVAL);
|
||||
CHECK(posix_memalign(&ptr, 4097, 1) == EINVAL);
|
||||
|
||||
// Grab some memory so that the big allocation below will definitely fail.
|
||||
void* p_small = malloc(4*1048576);
|
||||
CHECK(p_small != NULL);
|
||||
|
||||
// Make sure overflow is returned as ENOMEM
|
||||
const size_t zero = 0;
|
||||
static const size_t kMinusNTimes = 10;
|
||||
for ( size_t i = 1; i < kMinusNTimes; ++i ) {
|
||||
int r = posix_memalign(&ptr, 1024, zero - i);
|
||||
CHECK(r == ENOMEM);
|
||||
}
|
||||
|
||||
free(p_small);
|
||||
}
|
||||
|
||||
const int pagesize = getpagesize();
|
||||
{
|
||||
// valloc
|
||||
for (int s = 0; s != -1; s = NextSize(s)) {
|
||||
void* p = valloc(s);
|
||||
CheckAlignment(p, pagesize);
|
||||
Fill(p, s, 'v');
|
||||
CHECK(Valid(p, s, 'v'));
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// pvalloc
|
||||
for (int s = 0; s != -1; s = NextSize(s)) {
|
||||
void* p = pvalloc(s);
|
||||
CheckAlignment(p, pagesize);
|
||||
int alloc_needed = ((s + pagesize - 1) / pagesize) * pagesize;
|
||||
Fill(p, alloc_needed, 'x');
|
||||
CHECK(Valid(p, alloc_needed, 'x'));
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
82
trunk/3rdparty/gperftools-2-fit/src/tests/packed-cache_test.cc
vendored
Normal file
82
trunk/3rdparty/gperftools-2-fit/src/tests/packed-cache_test.cc
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2007, 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.
|
||||
|
||||
// ---
|
||||
// Author: Geoff Pike
|
||||
|
||||
#include <stdio.h>
|
||||
#include "base/logging.h"
|
||||
#include "packed-cache-inl.h"
|
||||
|
||||
static const int kHashbits = PackedCache<20>::kHashbits;
|
||||
|
||||
template <int kKeybits>
|
||||
static size_t MustGet(const PackedCache<kKeybits>& cache, uintptr_t key) {
|
||||
uint32 rv;
|
||||
CHECK(cache.TryGet(key, &rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
template <int kKeybits>
|
||||
static size_t Has(const PackedCache<kKeybits>& cache, uintptr_t key) {
|
||||
uint32 dummy;
|
||||
return cache.TryGet(key, &dummy);
|
||||
}
|
||||
|
||||
// A basic sanity test.
|
||||
void PackedCacheTest_basic() {
|
||||
PackedCache<20> cache;
|
||||
|
||||
CHECK(!Has(cache, 0));
|
||||
cache.Put(0, 17);
|
||||
CHECK(Has(cache, 0));
|
||||
CHECK_EQ(MustGet(cache, 0), 17);
|
||||
|
||||
cache.Put(19, 99);
|
||||
CHECK_EQ(MustGet(cache, 0), 17);
|
||||
CHECK_EQ(MustGet(cache, 19), 99);
|
||||
|
||||
// Knock <0, 17> out by using a conflicting key.
|
||||
cache.Put(1 << kHashbits, 22);
|
||||
CHECK(!Has(cache, 0));
|
||||
CHECK_EQ(MustGet(cache, 1 << kHashbits), 22);
|
||||
|
||||
cache.Invalidate(19);
|
||||
CHECK(!Has(cache, 19));
|
||||
CHECK(!Has(cache, 0));
|
||||
CHECK(Has(cache, 1 << kHashbits));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
PackedCacheTest_basic();
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
202
trunk/3rdparty/gperftools-2-fit/src/tests/page_heap_test.cc
vendored
Normal file
202
trunk/3rdparty/gperftools-2-fit/src/tests/page_heap_test.cc
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright 2009 Google Inc. All Rights Reserved.
|
||||
// Author: fikes@google.com (Andrew Fikes)
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can
|
||||
// be found in the LICENSE file.
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "page_heap.h"
|
||||
#include "system-alloc.h"
|
||||
#include "base/logging.h"
|
||||
#include "common.h"
|
||||
|
||||
DECLARE_int64(tcmalloc_heap_limit_mb);
|
||||
|
||||
namespace {
|
||||
|
||||
// The system will only release memory if the block size is equal or hight than
|
||||
// system page size.
|
||||
static bool HaveSystemRelease =
|
||||
TCMalloc_SystemRelease(
|
||||
TCMalloc_SystemAlloc(getpagesize(), NULL, 0), getpagesize());
|
||||
|
||||
static void CheckStats(const tcmalloc::PageHeap* ph,
|
||||
uint64_t system_pages,
|
||||
uint64_t free_pages,
|
||||
uint64_t unmapped_pages) {
|
||||
tcmalloc::PageHeap::Stats stats = ph->stats();
|
||||
|
||||
if (!HaveSystemRelease) {
|
||||
free_pages += unmapped_pages;
|
||||
unmapped_pages = 0;
|
||||
}
|
||||
|
||||
EXPECT_EQ(system_pages, stats.system_bytes >> kPageShift);
|
||||
EXPECT_EQ(free_pages, stats.free_bytes >> kPageShift);
|
||||
EXPECT_EQ(unmapped_pages, stats.unmapped_bytes >> kPageShift);
|
||||
}
|
||||
|
||||
static void TestPageHeap_Stats() {
|
||||
std::unique_ptr<tcmalloc::PageHeap> ph(new tcmalloc::PageHeap());
|
||||
|
||||
// Empty page heap
|
||||
CheckStats(ph.get(), 0, 0, 0);
|
||||
|
||||
// Allocate a span 's1'
|
||||
tcmalloc::Span* s1 = ph->New(256);
|
||||
CheckStats(ph.get(), 256, 0, 0);
|
||||
|
||||
// Split span 's1' into 's1', 's2'. Delete 's2'
|
||||
tcmalloc::Span* s2 = ph->Split(s1, 128);
|
||||
ph->Delete(s2);
|
||||
CheckStats(ph.get(), 256, 128, 0);
|
||||
|
||||
// Unmap deleted span 's2'
|
||||
ph->ReleaseAtLeastNPages(1);
|
||||
CheckStats(ph.get(), 256, 0, 128);
|
||||
|
||||
// Delete span 's1'
|
||||
ph->Delete(s1);
|
||||
CheckStats(ph.get(), 256, 128, 128);
|
||||
}
|
||||
|
||||
// The number of kMaxPages-sized Spans we will allocate and free during the
|
||||
// tests.
|
||||
// We will also do twice this many kMaxPages/2-sized ones.
|
||||
static constexpr int kNumberMaxPagesSpans = 10;
|
||||
|
||||
// Allocates all the last-level page tables we will need. Doing this before
|
||||
// calculating the base heap usage is necessary, because otherwise if any of
|
||||
// these are allocated during the main test it will throw the heap usage
|
||||
// calculations off and cause the test to fail.
|
||||
static void AllocateAllPageTables() {
|
||||
// Make a separate PageHeap from the main test so the test can start without
|
||||
// any pages in the lists.
|
||||
std::unique_ptr<tcmalloc::PageHeap> ph(new tcmalloc::PageHeap());
|
||||
tcmalloc::Span *spans[kNumberMaxPagesSpans * 2];
|
||||
for (int i = 0; i < kNumberMaxPagesSpans; ++i) {
|
||||
spans[i] = ph->New(kMaxPages);
|
||||
EXPECT_NE(spans[i], NULL);
|
||||
}
|
||||
for (int i = 0; i < kNumberMaxPagesSpans; ++i) {
|
||||
ph->Delete(spans[i]);
|
||||
}
|
||||
for (int i = 0; i < kNumberMaxPagesSpans * 2; ++i) {
|
||||
spans[i] = ph->New(kMaxPages >> 1);
|
||||
EXPECT_NE(spans[i], NULL);
|
||||
}
|
||||
for (int i = 0; i < kNumberMaxPagesSpans * 2; ++i) {
|
||||
ph->Delete(spans[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void TestPageHeap_Limit() {
|
||||
AllocateAllPageTables();
|
||||
|
||||
std::unique_ptr<tcmalloc::PageHeap> ph(new tcmalloc::PageHeap());
|
||||
|
||||
CHECK_EQ(kMaxPages, 1 << (20 - kPageShift));
|
||||
|
||||
// We do not know much is taken from the system for other purposes,
|
||||
// so we detect the proper limit:
|
||||
{
|
||||
FLAGS_tcmalloc_heap_limit_mb = 1;
|
||||
tcmalloc::Span* s = NULL;
|
||||
while((s = ph->New(kMaxPages)) == NULL) {
|
||||
FLAGS_tcmalloc_heap_limit_mb++;
|
||||
}
|
||||
FLAGS_tcmalloc_heap_limit_mb += kNumberMaxPagesSpans - 1;
|
||||
ph->Delete(s);
|
||||
// We are [10, 11) mb from the limit now.
|
||||
}
|
||||
|
||||
// Test AllocLarge and GrowHeap first:
|
||||
{
|
||||
tcmalloc::Span * spans[kNumberMaxPagesSpans];
|
||||
for (int i=0; i<kNumberMaxPagesSpans; ++i) {
|
||||
spans[i] = ph->New(kMaxPages);
|
||||
EXPECT_NE(spans[i], NULL);
|
||||
}
|
||||
EXPECT_EQ(ph->New(kMaxPages), NULL);
|
||||
|
||||
for (int i=0; i<kNumberMaxPagesSpans; i += 2) {
|
||||
ph->Delete(spans[i]);
|
||||
}
|
||||
|
||||
tcmalloc::Span *defragmented =
|
||||
ph->New(kNumberMaxPagesSpans / 2 * kMaxPages);
|
||||
|
||||
if (HaveSystemRelease) {
|
||||
// EnsureLimit should release deleted normal spans
|
||||
EXPECT_NE(defragmented, NULL);
|
||||
EXPECT_TRUE(ph->CheckExpensive());
|
||||
ph->Delete(defragmented);
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_EQ(defragmented, NULL);
|
||||
EXPECT_TRUE(ph->CheckExpensive());
|
||||
}
|
||||
|
||||
for (int i=1; i<kNumberMaxPagesSpans; i += 2) {
|
||||
ph->Delete(spans[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Once again, testing small lists this time (twice smaller spans):
|
||||
{
|
||||
tcmalloc::Span * spans[kNumberMaxPagesSpans * 2];
|
||||
for (int i=0; i<kNumberMaxPagesSpans * 2; ++i) {
|
||||
spans[i] = ph->New(kMaxPages >> 1);
|
||||
EXPECT_NE(spans[i], NULL);
|
||||
}
|
||||
// one more half size allocation may be possible:
|
||||
tcmalloc::Span * lastHalf = ph->New(kMaxPages >> 1);
|
||||
EXPECT_EQ(ph->New(kMaxPages >> 1), NULL);
|
||||
|
||||
for (int i=0; i<kNumberMaxPagesSpans * 2; i += 2) {
|
||||
ph->Delete(spans[i]);
|
||||
}
|
||||
|
||||
for (Length len = kMaxPages >> 2;
|
||||
len < kNumberMaxPagesSpans / 2 * kMaxPages; len = len << 1) {
|
||||
if(len <= kMaxPages >> 1 || HaveSystemRelease) {
|
||||
tcmalloc::Span *s = ph->New(len);
|
||||
EXPECT_NE(s, NULL);
|
||||
ph->Delete(s);
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(ph->CheckExpensive());
|
||||
|
||||
for (int i=1; i<kNumberMaxPagesSpans * 2; i += 2) {
|
||||
ph->Delete(spans[i]);
|
||||
}
|
||||
|
||||
if (lastHalf != NULL) {
|
||||
ph->Delete(lastHalf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
TestPageHeap_Stats();
|
||||
TestPageHeap_Limit();
|
||||
printf("PASS\n");
|
||||
// on windows as part of library destructors we call getenv which
|
||||
// calls malloc which fails due to our exhausted heap limit. It then
|
||||
// causes fancy stack overflow because log message we're printing
|
||||
// for failed allocation somehow cause malloc calls too
|
||||
//
|
||||
// To keep us out of trouble we just drop malloc limit
|
||||
FLAGS_tcmalloc_heap_limit_mb = 0;
|
||||
return 0;
|
||||
}
|
178
trunk/3rdparty/gperftools-2-fit/src/tests/pagemap_unittest.cc
vendored
Normal file
178
trunk/3rdparty/gperftools-2-fit/src/tests/pagemap_unittest.cc
vendored
Normal file
|
@ -0,0 +1,178 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2003, 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.
|
||||
|
||||
// ---
|
||||
// Author: Sanjay Ghemawat
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if defined HAVE_STDINT_H
|
||||
#include <stdint.h> // to get intptr_t
|
||||
#elif defined HAVE_INTTYPES_H
|
||||
#include <inttypes.h> // another place intptr_t might be defined
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <vector>
|
||||
#include "base/logging.h"
|
||||
#include "pagemap.h"
|
||||
|
||||
using std::vector;
|
||||
|
||||
static void Permute(vector<intptr_t>* elements) {
|
||||
if (elements->empty())
|
||||
return;
|
||||
const size_t num_elements = elements->size();
|
||||
for (size_t i = num_elements - 1; i > 0; --i) {
|
||||
const size_t newpos = rand() % (i + 1);
|
||||
const intptr_t tmp = (*elements)[i]; // swap
|
||||
(*elements)[i] = (*elements)[newpos];
|
||||
(*elements)[newpos] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: we leak memory every time a map is constructed, so do not
|
||||
// create too many maps.
|
||||
|
||||
// Test specified map type
|
||||
template <class Type>
|
||||
void TestMap(int limit, bool limit_is_below_the_overflow_boundary) {
|
||||
RAW_LOG(INFO, "Running test with %d iterations...\n", limit);
|
||||
|
||||
{ // Test sequential ensure/assignment
|
||||
Type map(malloc);
|
||||
for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
|
||||
map.Ensure(i, 1);
|
||||
map.set(i, (void*)(i+1));
|
||||
CHECK_EQ(map.get(i), (void*)(i+1));
|
||||
}
|
||||
for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
|
||||
CHECK_EQ(map.get(i), (void*)(i+1));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Test bulk Ensure
|
||||
Type map(malloc);
|
||||
map.Ensure(0, limit);
|
||||
for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
|
||||
map.set(i, (void*)(i+1));
|
||||
CHECK_EQ(map.get(i), (void*)(i+1));
|
||||
}
|
||||
for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
|
||||
CHECK_EQ(map.get(i), (void*)(i+1));
|
||||
}
|
||||
}
|
||||
|
||||
// Test that we correctly notice overflow
|
||||
{
|
||||
Type map(malloc);
|
||||
CHECK_EQ(map.Ensure(limit, limit+1), limit_is_below_the_overflow_boundary);
|
||||
}
|
||||
|
||||
{ // Test randomized accesses
|
||||
srand(301); // srand isn't great, but it's portable
|
||||
vector<intptr_t> elements;
|
||||
for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) elements.push_back(i);
|
||||
Permute(&elements);
|
||||
|
||||
Type map(malloc);
|
||||
for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
|
||||
map.Ensure(elements[i], 1);
|
||||
map.set(elements[i], (void*)(elements[i]+1));
|
||||
CHECK_EQ(map.get(elements[i]), (void*)(elements[i]+1));
|
||||
}
|
||||
for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
|
||||
CHECK_EQ(map.get(i), (void*)(i+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// REQUIRES: BITS==10, i.e., valid range is [0,1023].
|
||||
// Representations for different types will end up being:
|
||||
// PageMap1: array[1024]
|
||||
// PageMap2: array[32][32]
|
||||
// PageMap3: array[16][16][4]
|
||||
template <class Type>
|
||||
void TestNext(const char* name) {
|
||||
RAW_LOG(ERROR, "Running NextTest %s\n", name);
|
||||
Type map(malloc);
|
||||
char a, b, c, d, e;
|
||||
|
||||
// When map is empty
|
||||
CHECK(map.Next(0) == NULL);
|
||||
CHECK(map.Next(5) == NULL);
|
||||
CHECK(map.Next(1<<30) == NULL);
|
||||
|
||||
// Add a single value
|
||||
map.Ensure(40, 1);
|
||||
map.set(40, &a);
|
||||
CHECK(map.Next(0) == &a);
|
||||
CHECK(map.Next(39) == &a);
|
||||
CHECK(map.Next(40) == &a);
|
||||
CHECK(map.Next(41) == NULL);
|
||||
CHECK(map.Next(1<<30) == NULL);
|
||||
|
||||
// Add a few values
|
||||
map.Ensure(41, 1);
|
||||
map.Ensure(100, 3);
|
||||
map.set(41, &b);
|
||||
map.set(100, &c);
|
||||
map.set(101, &d);
|
||||
map.set(102, &e);
|
||||
CHECK(map.Next(0) == &a);
|
||||
CHECK(map.Next(39) == &a);
|
||||
CHECK(map.Next(40) == &a);
|
||||
CHECK(map.Next(41) == &b);
|
||||
CHECK(map.Next(42) == &c);
|
||||
CHECK(map.Next(63) == &c);
|
||||
CHECK(map.Next(64) == &c);
|
||||
CHECK(map.Next(65) == &c);
|
||||
CHECK(map.Next(99) == &c);
|
||||
CHECK(map.Next(100) == &c);
|
||||
CHECK(map.Next(101) == &d);
|
||||
CHECK(map.Next(102) == &e);
|
||||
CHECK(map.Next(103) == NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
TestMap< TCMalloc_PageMap1<10> > (100, true);
|
||||
TestMap< TCMalloc_PageMap1<10> > (1 << 10, false);
|
||||
TestMap< TCMalloc_PageMap2<20> > (100, true);
|
||||
TestMap< TCMalloc_PageMap2<20> > (1 << 20, false);
|
||||
TestMap< TCMalloc_PageMap3<20> > (100, true);
|
||||
TestMap< TCMalloc_PageMap3<20> > (1 << 20, false);
|
||||
|
||||
TestNext< TCMalloc_PageMap1<10> >("PageMap1");
|
||||
TestNext< TCMalloc_PageMap2<10> >("PageMap2");
|
||||
TestNext< TCMalloc_PageMap3<10> >("PageMap3");
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
398
trunk/3rdparty/gperftools-2-fit/src/tests/profile-handler_unittest.cc
vendored
Normal file
398
trunk/3rdparty/gperftools-2-fit/src/tests/profile-handler_unittest.cc
vendored
Normal file
|
@ -0,0 +1,398 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright 2009 Google Inc. All Rights Reserved.
|
||||
// Author: Nabeel Mian (nabeelmian@google.com)
|
||||
// Chris Demetriou (cgd@google.com)
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can
|
||||
// be found in the LICENSE file.
|
||||
//
|
||||
//
|
||||
// This file contains the unit tests for profile-handler.h interface.
|
||||
|
||||
#include "config.h"
|
||||
#include "profile-handler.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include "base/logging.h"
|
||||
#include "base/simple_mutex.h"
|
||||
|
||||
// Some helpful macros for the test class
|
||||
#define TEST_F(cls, fn) void cls :: fn()
|
||||
|
||||
// Do we expect the profiler to be enabled?
|
||||
DEFINE_bool(test_profiler_enabled, true,
|
||||
"expect profiler to be enabled during tests");
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(csilvers): error-checking on the pthreads routines
|
||||
class Thread {
|
||||
public:
|
||||
Thread() : joinable_(false) { }
|
||||
virtual ~Thread() { }
|
||||
void SetJoinable(bool value) { joinable_ = value; }
|
||||
void Start() {
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, joinable_ ? PTHREAD_CREATE_JOINABLE
|
||||
: PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&thread_, &attr, &DoRun, this);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
void Join() {
|
||||
assert(joinable_);
|
||||
pthread_join(thread_, NULL);
|
||||
}
|
||||
virtual void Run() = 0;
|
||||
private:
|
||||
static void* DoRun(void* cls) {
|
||||
ProfileHandlerRegisterThread();
|
||||
reinterpret_cast<Thread*>(cls)->Run();
|
||||
return NULL;
|
||||
}
|
||||
pthread_t thread_;
|
||||
bool joinable_;
|
||||
};
|
||||
|
||||
// Sleep interval in nano secs. ITIMER_PROF goes off only afer the specified CPU
|
||||
// time is consumed. Under heavy load this process may no get scheduled in a
|
||||
// timely fashion. Therefore, give enough time (20x of ProfileHandle timer
|
||||
// interval 10ms (100Hz)) for this process to accumulate enought CPU time to get
|
||||
// a profile tick.
|
||||
int kSleepInterval = 200000000;
|
||||
|
||||
// Sleep interval in nano secs. To ensure that if the timer has expired it is
|
||||
// reset.
|
||||
int kTimerResetInterval = 5000000;
|
||||
|
||||
static bool linux_per_thread_timers_mode_ = false;
|
||||
static int timer_type_ = ITIMER_PROF;
|
||||
|
||||
// Delays processing by the specified number of nano seconds. 'delay_ns'
|
||||
// must be less than the number of nano seconds in a second (1000000000).
|
||||
void Delay(int delay_ns) {
|
||||
static const int kNumNSecInSecond = 1000000000;
|
||||
EXPECT_LT(delay_ns, kNumNSecInSecond);
|
||||
struct timespec delay = { 0, delay_ns };
|
||||
nanosleep(&delay, 0);
|
||||
}
|
||||
|
||||
// Checks whether the profile timer is enabled for the current thread.
|
||||
bool IsTimerEnabled() {
|
||||
itimerval current_timer;
|
||||
EXPECT_EQ(0, getitimer(timer_type_, ¤t_timer));
|
||||
if ((current_timer.it_value.tv_sec == 0) &&
|
||||
(current_timer.it_value.tv_usec != 0)) {
|
||||
// May be the timer has expired. Sleep for a bit and check again.
|
||||
Delay(kTimerResetInterval);
|
||||
EXPECT_EQ(0, getitimer(timer_type_, ¤t_timer));
|
||||
}
|
||||
return (current_timer.it_value.tv_sec != 0 ||
|
||||
current_timer.it_value.tv_usec != 0);
|
||||
}
|
||||
|
||||
// Dummy worker thread to accumulate cpu time.
|
||||
class BusyThread : public Thread {
|
||||
public:
|
||||
BusyThread() : stop_work_(false) {
|
||||
}
|
||||
|
||||
// Setter/Getters
|
||||
bool stop_work() {
|
||||
MutexLock lock(&mu_);
|
||||
return stop_work_;
|
||||
}
|
||||
void set_stop_work(bool stop_work) {
|
||||
MutexLock lock(&mu_);
|
||||
stop_work_ = stop_work;
|
||||
}
|
||||
|
||||
private:
|
||||
// Protects stop_work_ below.
|
||||
Mutex mu_;
|
||||
// Whether to stop work?
|
||||
bool stop_work_;
|
||||
|
||||
// Do work until asked to stop.
|
||||
void Run() {
|
||||
while (!stop_work()) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class NullThread : public Thread {
|
||||
private:
|
||||
void Run() {
|
||||
}
|
||||
};
|
||||
|
||||
// Signal handler which tracks the profile timer ticks.
|
||||
static void TickCounter(int sig, siginfo_t* sig_info, void *vuc,
|
||||
void* tick_counter) {
|
||||
int* counter = static_cast<int*>(tick_counter);
|
||||
++(*counter);
|
||||
}
|
||||
|
||||
// This class tests the profile-handler.h interface.
|
||||
class ProfileHandlerTest {
|
||||
protected:
|
||||
|
||||
// Determines the timer type.
|
||||
static void SetUpTestCase() {
|
||||
timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
|
||||
|
||||
#if HAVE_LINUX_SIGEV_THREAD_ID
|
||||
linux_per_thread_timers_mode_ = (getenv("CPUPROFILE_PER_THREAD_TIMERS") != NULL);
|
||||
const char *signal_number = getenv("CPUPROFILE_TIMER_SIGNAL");
|
||||
if (signal_number) {
|
||||
//signal_number_ = strtol(signal_number, NULL, 0);
|
||||
linux_per_thread_timers_mode_ = true;
|
||||
Delay(kTimerResetInterval);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Sets up the profile timers and SIGPROF/SIGALRM handler in a known state.
|
||||
// It does the following:
|
||||
// 1. Unregisters all the callbacks, stops the timer and clears out
|
||||
// timer_sharing state in the ProfileHandler. This clears out any state
|
||||
// left behind by the previous test or during module initialization when
|
||||
// the test program was started.
|
||||
// 3. Starts a busy worker thread to accumulate CPU usage.
|
||||
virtual void SetUp() {
|
||||
// Reset the state of ProfileHandler between each test. This unregisters
|
||||
// all callbacks and stops the timer.
|
||||
ProfileHandlerReset();
|
||||
EXPECT_EQ(0, GetCallbackCount());
|
||||
VerifyDisabled();
|
||||
// Start worker to accumulate cpu usage.
|
||||
StartWorker();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
ProfileHandlerReset();
|
||||
// Stops the worker thread.
|
||||
StopWorker();
|
||||
}
|
||||
|
||||
// Starts a busy worker thread to accumulate cpu time. There should be only
|
||||
// one busy worker running. This is required for the case where there are
|
||||
// separate timers for each thread.
|
||||
void StartWorker() {
|
||||
busy_worker_ = new BusyThread();
|
||||
busy_worker_->SetJoinable(true);
|
||||
busy_worker_->Start();
|
||||
// Wait for worker to start up and register with the ProfileHandler.
|
||||
// TODO(nabeelmian) This may not work under very heavy load.
|
||||
Delay(kSleepInterval);
|
||||
}
|
||||
|
||||
// Stops the worker thread.
|
||||
void StopWorker() {
|
||||
busy_worker_->set_stop_work(true);
|
||||
busy_worker_->Join();
|
||||
delete busy_worker_;
|
||||
}
|
||||
|
||||
// Gets the number of callbacks registered with the ProfileHandler.
|
||||
uint32 GetCallbackCount() {
|
||||
ProfileHandlerState state;
|
||||
ProfileHandlerGetState(&state);
|
||||
return state.callback_count;
|
||||
}
|
||||
|
||||
// Gets the current ProfileHandler interrupt count.
|
||||
uint64 GetInterruptCount() {
|
||||
ProfileHandlerState state;
|
||||
ProfileHandlerGetState(&state);
|
||||
return state.interrupts;
|
||||
}
|
||||
|
||||
// Verifies that a callback is correctly registered and receiving
|
||||
// profile ticks.
|
||||
void VerifyRegistration(const int& tick_counter) {
|
||||
// Check the callback count.
|
||||
EXPECT_GT(GetCallbackCount(), 0);
|
||||
// Check that the profile timer is enabled.
|
||||
EXPECT_EQ(FLAGS_test_profiler_enabled, linux_per_thread_timers_mode_ || IsTimerEnabled());
|
||||
uint64 interrupts_before = GetInterruptCount();
|
||||
// Sleep for a bit and check that tick counter is making progress.
|
||||
int old_tick_count = tick_counter;
|
||||
Delay(kSleepInterval);
|
||||
int new_tick_count = tick_counter;
|
||||
uint64 interrupts_after = GetInterruptCount();
|
||||
if (FLAGS_test_profiler_enabled) {
|
||||
EXPECT_GT(new_tick_count, old_tick_count);
|
||||
EXPECT_GT(interrupts_after, interrupts_before);
|
||||
} else {
|
||||
EXPECT_EQ(new_tick_count, old_tick_count);
|
||||
EXPECT_EQ(interrupts_after, interrupts_before);
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that a callback is not receiving profile ticks.
|
||||
void VerifyUnregistration(const int& tick_counter) {
|
||||
// Sleep for a bit and check that tick counter is not making progress.
|
||||
int old_tick_count = tick_counter;
|
||||
Delay(kSleepInterval);
|
||||
int new_tick_count = tick_counter;
|
||||
EXPECT_EQ(old_tick_count, new_tick_count);
|
||||
// If no callbacks, timer should be disabled.
|
||||
if (GetCallbackCount() == 0) {
|
||||
EXPECT_FALSE(IsTimerEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that the timer is disabled. Expects the worker to be running.
|
||||
void VerifyDisabled() {
|
||||
// Check that the callback count is 0.
|
||||
EXPECT_EQ(0, GetCallbackCount());
|
||||
// Check that the timer is disabled.
|
||||
EXPECT_FALSE(IsTimerEnabled());
|
||||
// Verify that the ProfileHandler is not accumulating profile ticks.
|
||||
uint64 interrupts_before = GetInterruptCount();
|
||||
Delay(kSleepInterval);
|
||||
uint64 interrupts_after = GetInterruptCount();
|
||||
EXPECT_EQ(interrupts_before, interrupts_after);
|
||||
}
|
||||
|
||||
// Registers a callback and waits for kTimerResetInterval for timers to get
|
||||
// reset.
|
||||
ProfileHandlerToken* RegisterCallback(void* callback_arg) {
|
||||
ProfileHandlerToken* token = ProfileHandlerRegisterCallback(
|
||||
TickCounter, callback_arg);
|
||||
Delay(kTimerResetInterval);
|
||||
return token;
|
||||
}
|
||||
|
||||
// Unregisters a callback and waits for kTimerResetInterval for timers to get
|
||||
// reset.
|
||||
void UnregisterCallback(ProfileHandlerToken* token) {
|
||||
ProfileHandlerUnregisterCallback(token);
|
||||
Delay(kTimerResetInterval);
|
||||
}
|
||||
|
||||
// Busy worker thread to accumulate cpu usage.
|
||||
BusyThread* busy_worker_;
|
||||
|
||||
private:
|
||||
// The tests to run
|
||||
void RegisterUnregisterCallback();
|
||||
void MultipleCallbacks();
|
||||
void Reset();
|
||||
void RegisterCallbackBeforeThread();
|
||||
|
||||
public:
|
||||
#define RUN(test) do { \
|
||||
printf("Running %s\n", #test); \
|
||||
ProfileHandlerTest pht; \
|
||||
pht.SetUp(); \
|
||||
pht.test(); \
|
||||
pht.TearDown(); \
|
||||
} while (0)
|
||||
|
||||
static int RUN_ALL_TESTS() {
|
||||
SetUpTestCase();
|
||||
RUN(RegisterUnregisterCallback);
|
||||
RUN(MultipleCallbacks);
|
||||
RUN(Reset);
|
||||
RUN(RegisterCallbackBeforeThread);
|
||||
printf("Done\n");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Verifies ProfileHandlerRegisterCallback and
|
||||
// ProfileHandlerUnregisterCallback.
|
||||
TEST_F(ProfileHandlerTest, RegisterUnregisterCallback) {
|
||||
int tick_count = 0;
|
||||
ProfileHandlerToken* token = RegisterCallback(&tick_count);
|
||||
VerifyRegistration(tick_count);
|
||||
UnregisterCallback(token);
|
||||
VerifyUnregistration(tick_count);
|
||||
}
|
||||
|
||||
// Verifies that multiple callbacks can be registered.
|
||||
TEST_F(ProfileHandlerTest, MultipleCallbacks) {
|
||||
// Register first callback.
|
||||
int first_tick_count = 0;
|
||||
ProfileHandlerToken* token1 = RegisterCallback(&first_tick_count);
|
||||
// Check that callback was registered correctly.
|
||||
VerifyRegistration(first_tick_count);
|
||||
EXPECT_EQ(1, GetCallbackCount());
|
||||
|
||||
// Register second callback.
|
||||
int second_tick_count = 0;
|
||||
ProfileHandlerToken* token2 = RegisterCallback(&second_tick_count);
|
||||
// Check that callback was registered correctly.
|
||||
VerifyRegistration(second_tick_count);
|
||||
EXPECT_EQ(2, GetCallbackCount());
|
||||
|
||||
// Unregister first callback.
|
||||
UnregisterCallback(token1);
|
||||
VerifyUnregistration(first_tick_count);
|
||||
EXPECT_EQ(1, GetCallbackCount());
|
||||
// Verify that second callback is still registered.
|
||||
VerifyRegistration(second_tick_count);
|
||||
|
||||
// Unregister second callback.
|
||||
UnregisterCallback(token2);
|
||||
VerifyUnregistration(second_tick_count);
|
||||
EXPECT_EQ(0, GetCallbackCount());
|
||||
|
||||
// Verify that the timers is correctly disabled.
|
||||
if (!linux_per_thread_timers_mode_) VerifyDisabled();
|
||||
}
|
||||
|
||||
// Verifies ProfileHandlerReset
|
||||
TEST_F(ProfileHandlerTest, Reset) {
|
||||
// Verify that the profile timer interrupt is disabled.
|
||||
if (!linux_per_thread_timers_mode_) VerifyDisabled();
|
||||
int first_tick_count = 0;
|
||||
RegisterCallback(&first_tick_count);
|
||||
VerifyRegistration(first_tick_count);
|
||||
EXPECT_EQ(1, GetCallbackCount());
|
||||
|
||||
// Register second callback.
|
||||
int second_tick_count = 0;
|
||||
RegisterCallback(&second_tick_count);
|
||||
VerifyRegistration(second_tick_count);
|
||||
EXPECT_EQ(2, GetCallbackCount());
|
||||
|
||||
// Reset the profile handler and verify that callback were correctly
|
||||
// unregistered and the timer is disabled.
|
||||
ProfileHandlerReset();
|
||||
VerifyUnregistration(first_tick_count);
|
||||
VerifyUnregistration(second_tick_count);
|
||||
if (!linux_per_thread_timers_mode_) VerifyDisabled();
|
||||
}
|
||||
|
||||
// Verifies that ProfileHandler correctly handles a case where a callback was
|
||||
// registered before the second thread started.
|
||||
TEST_F(ProfileHandlerTest, RegisterCallbackBeforeThread) {
|
||||
// Stop the worker.
|
||||
StopWorker();
|
||||
// Unregister all existing callbacks and stop the timer.
|
||||
ProfileHandlerReset();
|
||||
EXPECT_EQ(0, GetCallbackCount());
|
||||
VerifyDisabled();
|
||||
|
||||
// Start the worker.
|
||||
StartWorker();
|
||||
// Register a callback and check that profile ticks are being delivered and
|
||||
// the timer is enabled.
|
||||
int tick_count = 0;
|
||||
RegisterCallback(&tick_count);
|
||||
EXPECT_EQ(1, GetCallbackCount());
|
||||
VerifyRegistration(tick_count);
|
||||
EXPECT_EQ(FLAGS_test_profiler_enabled, linux_per_thread_timers_mode_ || IsTimerEnabled());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return ProfileHandlerTest::RUN_ALL_TESTS();
|
||||
}
|
612
trunk/3rdparty/gperftools-2-fit/src/tests/profiledata_unittest.cc
vendored
Normal file
612
trunk/3rdparty/gperftools-2-fit/src/tests/profiledata_unittest.cc
vendored
Normal file
|
@ -0,0 +1,612 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2007, 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.
|
||||
//
|
||||
// ---
|
||||
// Author: Chris Demetriou
|
||||
//
|
||||
// This file contains the unit tests for the ProfileData class.
|
||||
|
||||
#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/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "profiledata.h"
|
||||
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
// Some helpful macros for the test class
|
||||
#define TEST_F(cls, fn) void cls :: fn()
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T> class scoped_array {
|
||||
public:
|
||||
scoped_array(T* data) : data_(data) { }
|
||||
~scoped_array() { delete[] data_; }
|
||||
T* get() { return data_; }
|
||||
T& operator[](int i) { return data_[i]; }
|
||||
private:
|
||||
T* const data_;
|
||||
};
|
||||
|
||||
// Re-runs fn until it doesn't cause EINTR.
|
||||
#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
|
||||
|
||||
// Read up to "count" bytes from file descriptor "fd" into the buffer
|
||||
// starting at "buf" while handling short reads and EINTR. On
|
||||
// success, return the number of bytes read. Otherwise, return -1.
|
||||
static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
|
||||
CHECK_GE(fd, 0);
|
||||
char *buf0 = reinterpret_cast<char *>(buf);
|
||||
ssize_t num_bytes = 0;
|
||||
while (num_bytes < count) {
|
||||
ssize_t len;
|
||||
NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
|
||||
if (len < 0) { // There was an error other than EINTR.
|
||||
return -1;
|
||||
}
|
||||
if (len == 0) { // Reached EOF.
|
||||
break;
|
||||
}
|
||||
num_bytes += len;
|
||||
}
|
||||
CHECK(num_bytes <= count);
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
// Thin wrapper around a file descriptor so that the file descriptor
|
||||
// gets closed for sure.
|
||||
struct FileDescriptor {
|
||||
const int fd_;
|
||||
explicit FileDescriptor(int fd) : fd_(fd) {}
|
||||
~FileDescriptor() {
|
||||
if (fd_ >= 0) {
|
||||
NO_INTR(close(fd_));
|
||||
}
|
||||
}
|
||||
int get() { return fd_; }
|
||||
};
|
||||
|
||||
// must be the same as with ProfileData::Slot.
|
||||
typedef uintptr_t ProfileDataSlot;
|
||||
|
||||
// Quick and dirty function to make a number into a void* for use in a
|
||||
// sample.
|
||||
inline void* V(intptr_t x) { return reinterpret_cast<void*>(x); }
|
||||
|
||||
// String returned by ProfileDataChecker helper functions to indicate success.
|
||||
const char kNoError[] = "";
|
||||
|
||||
class ProfileDataChecker {
|
||||
public:
|
||||
ProfileDataChecker() {
|
||||
const char* tmpdir = getenv("TMPDIR");
|
||||
if (tmpdir == NULL)
|
||||
tmpdir = "/tmp";
|
||||
mkdir(tmpdir, 0755); // if necessary
|
||||
filename_ = string(tmpdir) + "/profiledata_unittest.tmp";
|
||||
}
|
||||
|
||||
string filename() const { return filename_; }
|
||||
|
||||
// Checks the first 'num_slots' profile data slots in the file
|
||||
// against the data pointed to by 'slots'. Returns kNoError if the
|
||||
// data matched, otherwise returns an indication of the cause of the
|
||||
// mismatch.
|
||||
string Check(const ProfileDataSlot* slots, int num_slots) {
|
||||
return CheckWithSkips(slots, num_slots, NULL, 0);
|
||||
}
|
||||
|
||||
// Checks the first 'num_slots' profile data slots in the file
|
||||
// against the data pointed to by 'slots', skipping over entries
|
||||
// described by 'skips' and 'num_skips'.
|
||||
//
|
||||
// 'skips' must be a sorted list of (0-based) slot numbers to be
|
||||
// skipped, of length 'num_skips'. Note that 'num_slots' includes
|
||||
// any skipped slots, i.e., the first 'num_slots' profile data slots
|
||||
// will be considered, but some may be skipped.
|
||||
//
|
||||
// Returns kNoError if the data matched, otherwise returns an
|
||||
// indication of the cause of the mismatch.
|
||||
string CheckWithSkips(const ProfileDataSlot* slots, int num_slots,
|
||||
const int* skips, int num_skips);
|
||||
|
||||
// Validate that a profile is correctly formed. The profile is
|
||||
// assumed to have been created by the same kind of binary (e.g.,
|
||||
// same slot size, same endian, etc.) as is validating the profile.
|
||||
//
|
||||
// Returns kNoError if the profile appears valid, otherwise returns
|
||||
// an indication of the problem with the profile.
|
||||
string ValidateProfile();
|
||||
|
||||
private:
|
||||
string filename_;
|
||||
};
|
||||
|
||||
string ProfileDataChecker::CheckWithSkips(const ProfileDataSlot* slots,
|
||||
int num_slots, const int* skips,
|
||||
int num_skips) {
|
||||
FileDescriptor fd(open(filename_.c_str(), O_RDONLY));
|
||||
if (fd.get() < 0)
|
||||
return "file open error";
|
||||
|
||||
scoped_array<ProfileDataSlot> filedata(new ProfileDataSlot[num_slots]);
|
||||
size_t expected_bytes = num_slots * sizeof filedata[0];
|
||||
ssize_t bytes_read = ReadPersistent(fd.get(), filedata.get(), expected_bytes);
|
||||
if (expected_bytes != bytes_read)
|
||||
return "file too small";
|
||||
|
||||
for (int i = 0; i < num_slots; i++) {
|
||||
if (num_skips > 0 && *skips == i) {
|
||||
num_skips--;
|
||||
skips++;
|
||||
continue;
|
||||
}
|
||||
if (slots[i] != filedata[i])
|
||||
return "data mismatch";
|
||||
}
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
string ProfileDataChecker::ValidateProfile() {
|
||||
FileDescriptor fd(open(filename_.c_str(), O_RDONLY));
|
||||
if (fd.get() < 0)
|
||||
return "file open error";
|
||||
|
||||
struct stat statbuf;
|
||||
if (fstat(fd.get(), &statbuf) != 0)
|
||||
return "fstat error";
|
||||
if (statbuf.st_size != static_cast<ssize_t>(statbuf.st_size))
|
||||
return "file impossibly large";
|
||||
ssize_t filesize = statbuf.st_size;
|
||||
|
||||
scoped_array<char> filedata(new char[filesize]);
|
||||
if (ReadPersistent(fd.get(), filedata.get(), filesize) != filesize)
|
||||
return "read of whole file failed";
|
||||
|
||||
// Must have enough data for the header and the trailer.
|
||||
if (filesize < (5 + 3) * sizeof(ProfileDataSlot))
|
||||
return "not enough data in profile for header + trailer";
|
||||
|
||||
// Check the header
|
||||
if (reinterpret_cast<ProfileDataSlot*>(filedata.get())[0] != 0)
|
||||
return "error in header: non-zero count";
|
||||
if (reinterpret_cast<ProfileDataSlot*>(filedata.get())[1] != 3)
|
||||
return "error in header: num_slots != 3";
|
||||
if (reinterpret_cast<ProfileDataSlot*>(filedata.get())[2] != 0)
|
||||
return "error in header: non-zero format version";
|
||||
// Period (slot 3) can have any value.
|
||||
if (reinterpret_cast<ProfileDataSlot*>(filedata.get())[4] != 0)
|
||||
return "error in header: non-zero padding value";
|
||||
ssize_t cur_offset = 5 * sizeof(ProfileDataSlot);
|
||||
|
||||
// While there are samples, skip them. Each sample consists of
|
||||
// at least three slots.
|
||||
bool seen_trailer = false;
|
||||
while (!seen_trailer) {
|
||||
if (cur_offset > filesize - 3 * sizeof(ProfileDataSlot))
|
||||
return "truncated sample header";
|
||||
ProfileDataSlot* sample =
|
||||
reinterpret_cast<ProfileDataSlot*>(filedata.get() + cur_offset);
|
||||
ProfileDataSlot slots_this_sample = 2 + sample[1];
|
||||
ssize_t size_this_sample = slots_this_sample * sizeof(ProfileDataSlot);
|
||||
if (cur_offset > filesize - size_this_sample)
|
||||
return "truncated sample";
|
||||
|
||||
if (sample[0] == 0 && sample[1] == 1 && sample[2] == 0) {
|
||||
seen_trailer = true;
|
||||
} else {
|
||||
if (sample[0] < 1)
|
||||
return "error in sample: sample count < 1";
|
||||
if (sample[1] < 1)
|
||||
return "error in sample: num_pcs < 1";
|
||||
for (int i = 2; i < slots_this_sample; i++) {
|
||||
if (sample[i] == 0)
|
||||
return "error in sample: NULL PC";
|
||||
}
|
||||
}
|
||||
cur_offset += size_this_sample;
|
||||
}
|
||||
|
||||
// There must be at least one line in the (text) list of mapped objects,
|
||||
// and it must be terminated by a newline. Note, the use of newline
|
||||
// here and below Might not be reasonable on non-UNIX systems.
|
||||
if (cur_offset >= filesize)
|
||||
return "no list of mapped objects";
|
||||
if (filedata[filesize - 1] != '\n')
|
||||
return "profile did not end with a complete line";
|
||||
|
||||
while (cur_offset < filesize) {
|
||||
char* line_start = filedata.get() + cur_offset;
|
||||
|
||||
// Find the end of the line, and replace it with a NUL for easier
|
||||
// scanning.
|
||||
char* line_end = strchr(line_start, '\n');
|
||||
*line_end = '\0';
|
||||
|
||||
// Advance past any leading space. It's allowed in some lines,
|
||||
// but not in others.
|
||||
bool has_leading_space = false;
|
||||
char* line_cur = line_start;
|
||||
while (*line_cur == ' ') {
|
||||
has_leading_space = true;
|
||||
line_cur++;
|
||||
}
|
||||
|
||||
bool found_match = false;
|
||||
|
||||
// Check for build lines.
|
||||
if (!found_match) {
|
||||
found_match = (strncmp(line_cur, "build=", 6) == 0);
|
||||
// Anything may follow "build=", and leading space is allowed.
|
||||
}
|
||||
|
||||
// A line from ProcMapsIterator::FormatLine, of the form:
|
||||
//
|
||||
// 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so
|
||||
//
|
||||
// Leading space is not allowed. The filename may be omitted or
|
||||
// may consist of multiple words, so we scan only up to the
|
||||
// space before the filename.
|
||||
if (!found_match) {
|
||||
int chars_scanned = -1;
|
||||
sscanf(line_cur, "%*x-%*x %*c%*c%*c%*c %*x %*x:%*x %*d %n",
|
||||
&chars_scanned);
|
||||
found_match = (chars_scanned > 0 && !has_leading_space);
|
||||
}
|
||||
|
||||
// A line from DumpAddressMap, of the form:
|
||||
//
|
||||
// 40000000-40015000: /lib/ld-2.3.2.so
|
||||
//
|
||||
// Leading space is allowed. The filename may be omitted or may
|
||||
// consist of multiple words, so we scan only up to the space
|
||||
// before the filename.
|
||||
if (!found_match) {
|
||||
int chars_scanned = -1;
|
||||
sscanf(line_cur, "%*x-%*x: %n", &chars_scanned);
|
||||
found_match = (chars_scanned > 0);
|
||||
}
|
||||
|
||||
if (!found_match)
|
||||
return "unrecognized line in text section";
|
||||
|
||||
cur_offset += (line_end - line_start) + 1;
|
||||
}
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
class ProfileDataTest {
|
||||
protected:
|
||||
void ExpectStopped() {
|
||||
EXPECT_FALSE(collector_.enabled());
|
||||
}
|
||||
|
||||
void ExpectRunningSamples(int samples) {
|
||||
ProfileData::State state;
|
||||
collector_.GetCurrentState(&state);
|
||||
EXPECT_TRUE(state.enabled);
|
||||
EXPECT_EQ(samples, state.samples_gathered);
|
||||
}
|
||||
|
||||
void ExpectSameState(const ProfileData::State& before,
|
||||
const ProfileData::State& after) {
|
||||
EXPECT_EQ(before.enabled, after.enabled);
|
||||
EXPECT_EQ(before.samples_gathered, after.samples_gathered);
|
||||
EXPECT_EQ(before.start_time, after.start_time);
|
||||
EXPECT_STREQ(before.profile_name, after.profile_name);
|
||||
}
|
||||
|
||||
ProfileData collector_;
|
||||
ProfileDataChecker checker_;
|
||||
|
||||
private:
|
||||
// The tests to run
|
||||
void OpsWhenStopped();
|
||||
void StartStopEmpty();
|
||||
void StartStopNoOptionsEmpty();
|
||||
void StartWhenStarted();
|
||||
void StartStopEmpty2();
|
||||
void CollectOne();
|
||||
void CollectTwoMatching();
|
||||
void CollectTwoFlush();
|
||||
void StartResetRestart();
|
||||
|
||||
public:
|
||||
#define RUN(test) do { \
|
||||
printf("Running %s\n", #test); \
|
||||
ProfileDataTest pdt; \
|
||||
pdt.test(); \
|
||||
} while (0)
|
||||
|
||||
static int RUN_ALL_TESTS() {
|
||||
RUN(OpsWhenStopped);
|
||||
RUN(StartStopEmpty);
|
||||
RUN(StartWhenStarted);
|
||||
RUN(StartStopEmpty2);
|
||||
RUN(CollectOne);
|
||||
RUN(CollectTwoMatching);
|
||||
RUN(CollectTwoFlush);
|
||||
RUN(StartResetRestart);
|
||||
RUN(StartStopNoOptionsEmpty);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Check that various operations are safe when stopped.
|
||||
TEST_F(ProfileDataTest, OpsWhenStopped) {
|
||||
ExpectStopped();
|
||||
EXPECT_FALSE(collector_.enabled());
|
||||
|
||||
// Verify that state is disabled, all-empty/all-0
|
||||
ProfileData::State state_before;
|
||||
collector_.GetCurrentState(&state_before);
|
||||
EXPECT_FALSE(state_before.enabled);
|
||||
EXPECT_EQ(0, state_before.samples_gathered);
|
||||
EXPECT_EQ(0, state_before.start_time);
|
||||
EXPECT_STREQ("", state_before.profile_name);
|
||||
|
||||
// Safe to call stop again.
|
||||
collector_.Stop();
|
||||
|
||||
// Safe to call FlushTable.
|
||||
collector_.FlushTable();
|
||||
|
||||
// Safe to call Add.
|
||||
const void *trace[] = { V(100), V(101), V(102), V(103), V(104) };
|
||||
collector_.Add(arraysize(trace), trace);
|
||||
|
||||
ProfileData::State state_after;
|
||||
collector_.GetCurrentState(&state_after);
|
||||
|
||||
ExpectSameState(state_before, state_after);
|
||||
}
|
||||
|
||||
// Start and Stop, collecting no samples. Verify output contents.
|
||||
TEST_F(ProfileDataTest, StartStopEmpty) {
|
||||
const int frequency = 1;
|
||||
ProfileDataSlot slots[] = {
|
||||
0, 3, 0, 1000000 / frequency, 0, // binary header
|
||||
0, 1, 0 // binary trailer
|
||||
};
|
||||
|
||||
ExpectStopped();
|
||||
ProfileData::Options options;
|
||||
options.set_frequency(frequency);
|
||||
EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
|
||||
ExpectRunningSamples(0);
|
||||
collector_.Stop();
|
||||
ExpectStopped();
|
||||
EXPECT_EQ(kNoError, checker_.ValidateProfile());
|
||||
EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
|
||||
}
|
||||
|
||||
// Start and Stop with no options, collecting no samples. Verify
|
||||
// output contents.
|
||||
TEST_F(ProfileDataTest, StartStopNoOptionsEmpty) {
|
||||
// We're not requesting a specific period, implementation can do
|
||||
// whatever it likes.
|
||||
ProfileDataSlot slots[] = {
|
||||
0, 3, 0, 0 /* skipped */, 0, // binary header
|
||||
0, 1, 0 // binary trailer
|
||||
};
|
||||
int slots_to_skip[] = { 3 };
|
||||
|
||||
ExpectStopped();
|
||||
EXPECT_TRUE(collector_.Start(checker_.filename().c_str(),
|
||||
ProfileData::Options()));
|
||||
ExpectRunningSamples(0);
|
||||
collector_.Stop();
|
||||
ExpectStopped();
|
||||
EXPECT_EQ(kNoError, checker_.ValidateProfile());
|
||||
EXPECT_EQ(kNoError, checker_.CheckWithSkips(slots, arraysize(slots),
|
||||
slots_to_skip,
|
||||
arraysize(slots_to_skip)));
|
||||
}
|
||||
|
||||
// Start after already started. Should return false and not impact
|
||||
// collected data or state.
|
||||
TEST_F(ProfileDataTest, StartWhenStarted) {
|
||||
const int frequency = 1;
|
||||
ProfileDataSlot slots[] = {
|
||||
0, 3, 0, 1000000 / frequency, 0, // binary header
|
||||
0, 1, 0 // binary trailer
|
||||
};
|
||||
|
||||
ProfileData::Options options;
|
||||
options.set_frequency(frequency);
|
||||
EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
|
||||
|
||||
ProfileData::State state_before;
|
||||
collector_.GetCurrentState(&state_before);
|
||||
|
||||
options.set_frequency(frequency * 2);
|
||||
CHECK(!collector_.Start("foobar", options));
|
||||
|
||||
ProfileData::State state_after;
|
||||
collector_.GetCurrentState(&state_after);
|
||||
ExpectSameState(state_before, state_after);
|
||||
|
||||
collector_.Stop();
|
||||
ExpectStopped();
|
||||
EXPECT_EQ(kNoError, checker_.ValidateProfile());
|
||||
EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
|
||||
}
|
||||
|
||||
// Like StartStopEmpty, but uses a different file name and frequency.
|
||||
TEST_F(ProfileDataTest, StartStopEmpty2) {
|
||||
const int frequency = 2;
|
||||
ProfileDataSlot slots[] = {
|
||||
0, 3, 0, 1000000 / frequency, 0, // binary header
|
||||
0, 1, 0 // binary trailer
|
||||
};
|
||||
|
||||
ExpectStopped();
|
||||
ProfileData::Options options;
|
||||
options.set_frequency(frequency);
|
||||
EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
|
||||
ExpectRunningSamples(0);
|
||||
collector_.Stop();
|
||||
ExpectStopped();
|
||||
EXPECT_EQ(kNoError, checker_.ValidateProfile());
|
||||
EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
|
||||
}
|
||||
|
||||
TEST_F(ProfileDataTest, CollectOne) {
|
||||
const int frequency = 2;
|
||||
ProfileDataSlot slots[] = {
|
||||
0, 3, 0, 1000000 / frequency, 0, // binary header
|
||||
1, 5, 100, 101, 102, 103, 104, // our sample
|
||||
0, 1, 0 // binary trailer
|
||||
};
|
||||
|
||||
ExpectStopped();
|
||||
ProfileData::Options options;
|
||||
options.set_frequency(frequency);
|
||||
EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
|
||||
ExpectRunningSamples(0);
|
||||
|
||||
const void *trace[] = { V(100), V(101), V(102), V(103), V(104) };
|
||||
collector_.Add(arraysize(trace), trace);
|
||||
ExpectRunningSamples(1);
|
||||
|
||||
collector_.Stop();
|
||||
ExpectStopped();
|
||||
EXPECT_EQ(kNoError, checker_.ValidateProfile());
|
||||
EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
|
||||
}
|
||||
|
||||
TEST_F(ProfileDataTest, CollectTwoMatching) {
|
||||
const int frequency = 2;
|
||||
ProfileDataSlot slots[] = {
|
||||
0, 3, 0, 1000000 / frequency, 0, // binary header
|
||||
2, 5, 100, 201, 302, 403, 504, // our two samples
|
||||
0, 1, 0 // binary trailer
|
||||
};
|
||||
|
||||
ExpectStopped();
|
||||
ProfileData::Options options;
|
||||
options.set_frequency(frequency);
|
||||
EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
|
||||
ExpectRunningSamples(0);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
const void *trace[] = { V(100), V(201), V(302), V(403), V(504) };
|
||||
collector_.Add(arraysize(trace), trace);
|
||||
ExpectRunningSamples(i + 1);
|
||||
}
|
||||
|
||||
collector_.Stop();
|
||||
ExpectStopped();
|
||||
EXPECT_EQ(kNoError, checker_.ValidateProfile());
|
||||
EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
|
||||
}
|
||||
|
||||
TEST_F(ProfileDataTest, CollectTwoFlush) {
|
||||
const int frequency = 2;
|
||||
ProfileDataSlot slots[] = {
|
||||
0, 3, 0, 1000000 / frequency, 0, // binary header
|
||||
1, 5, 100, 201, 302, 403, 504, // first sample (flushed)
|
||||
1, 5, 100, 201, 302, 403, 504, // second identical sample
|
||||
0, 1, 0 // binary trailer
|
||||
};
|
||||
|
||||
ExpectStopped();
|
||||
ProfileData::Options options;
|
||||
options.set_frequency(frequency);
|
||||
EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
|
||||
ExpectRunningSamples(0);
|
||||
|
||||
const void *trace[] = { V(100), V(201), V(302), V(403), V(504) };
|
||||
|
||||
collector_.Add(arraysize(trace), trace);
|
||||
ExpectRunningSamples(1);
|
||||
collector_.FlushTable();
|
||||
|
||||
collector_.Add(arraysize(trace), trace);
|
||||
ExpectRunningSamples(2);
|
||||
|
||||
collector_.Stop();
|
||||
ExpectStopped();
|
||||
EXPECT_EQ(kNoError, checker_.ValidateProfile());
|
||||
EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
|
||||
}
|
||||
|
||||
// Start then reset, verify that the result is *not* a valid profile.
|
||||
// Then start again and make sure the result is OK.
|
||||
TEST_F(ProfileDataTest, StartResetRestart) {
|
||||
ExpectStopped();
|
||||
ProfileData::Options options;
|
||||
options.set_frequency(1);
|
||||
EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
|
||||
ExpectRunningSamples(0);
|
||||
collector_.Reset();
|
||||
ExpectStopped();
|
||||
// We expect the resulting file to be empty. This is a minimal test
|
||||
// of ValidateProfile.
|
||||
EXPECT_NE(kNoError, checker_.ValidateProfile());
|
||||
|
||||
struct stat statbuf;
|
||||
EXPECT_EQ(0, stat(checker_.filename().c_str(), &statbuf));
|
||||
EXPECT_EQ(0, statbuf.st_size);
|
||||
|
||||
const int frequency = 2; // Different frequency than used above.
|
||||
ProfileDataSlot slots[] = {
|
||||
0, 3, 0, 1000000 / frequency, 0, // binary header
|
||||
0, 1, 0 // binary trailer
|
||||
};
|
||||
|
||||
options.set_frequency(frequency);
|
||||
EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
|
||||
ExpectRunningSamples(0);
|
||||
collector_.Stop();
|
||||
ExpectStopped();
|
||||
EXPECT_EQ(kNoError, checker_.ValidateProfile());
|
||||
EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int rc = ProfileDataTest::RUN_ALL_TESTS();
|
||||
printf("%s\n", rc == 0 ? "PASS" : "FAIL");
|
||||
return rc;
|
||||
}
|
147
trunk/3rdparty/gperftools-2-fit/src/tests/profiler_unittest.cc
vendored
Normal file
147
trunk/3rdparty/gperftools-2-fit/src/tests/profiler_unittest.cc
vendored
Normal file
|
@ -0,0 +1,147 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2005, 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.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// Does some simple arithmetic and a few libc routines, so we can profile it.
|
||||
// Define WITH_THREADS to add pthread functionality as well (otherwise, btw,
|
||||
// the num_threads argument to this program is ingored).
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> // for fork()
|
||||
#endif
|
||||
#include <sys/wait.h> // for wait()
|
||||
#include "gperftools/profiler.h"
|
||||
#include "base/simple_mutex.h"
|
||||
#include "tests/testutil.h"
|
||||
|
||||
static volatile int result = 0;
|
||||
static int g_iters = 0; // argv[1]
|
||||
|
||||
Mutex mutex(Mutex::LINKER_INITIALIZED);
|
||||
|
||||
static void test_other_thread() {
|
||||
#ifndef NO_THREADS
|
||||
ProfilerRegisterThread();
|
||||
|
||||
int i, m;
|
||||
char b[128];
|
||||
MutexLock ml(&mutex);
|
||||
for (m = 0; m < 1000000; ++m) { // run millions of times
|
||||
for (i = 0; i < g_iters; ++i ) {
|
||||
result ^= i;
|
||||
}
|
||||
snprintf(b, sizeof(b), "other: %d", result); // get some libc action
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_main_thread() {
|
||||
int i, m;
|
||||
char b[128];
|
||||
MutexLock ml(&mutex);
|
||||
for (m = 0; m < 1000000; ++m) { // run millions of times
|
||||
for (i = 0; i < g_iters; ++i ) {
|
||||
result ^= i;
|
||||
}
|
||||
snprintf(b, sizeof(b), "same: %d", result); // get some libc action
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if ( argc <= 1 ) {
|
||||
fprintf(stderr, "USAGE: %s <iters> [num_threads] [filename]\n", argv[0]);
|
||||
fprintf(stderr, " iters: How many million times to run the XOR test.\n");
|
||||
fprintf(stderr, " num_threads: how many concurrent threads.\n");
|
||||
fprintf(stderr, " 0 or 1 for single-threaded mode,\n");
|
||||
fprintf(stderr, " -# to fork instead of thread.\n");
|
||||
fprintf(stderr, " filename: The name of the output profile.\n");
|
||||
fprintf(stderr, (" If you don't specify, set CPUPROFILE "
|
||||
"in the environment instead!\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_iters = atoi(argv[1]);
|
||||
int num_threads = 1;
|
||||
const char* filename = NULL;
|
||||
if (argc > 2) {
|
||||
num_threads = atoi(argv[2]);
|
||||
}
|
||||
if (argc > 3) {
|
||||
filename = argv[3];
|
||||
}
|
||||
|
||||
if (filename) {
|
||||
ProfilerStart(filename);
|
||||
}
|
||||
|
||||
test_main_thread();
|
||||
|
||||
ProfilerFlush(); // just because we can
|
||||
|
||||
// The other threads, if any, will run only half as long as the main thread
|
||||
if(num_threads > 0) {
|
||||
RunManyThreads(test_other_thread, num_threads);
|
||||
} else {
|
||||
// Or maybe they asked to fork. The fork test is only interesting
|
||||
// when we use CPUPROFILE to name, so check for that
|
||||
#ifdef HAVE_UNISTD_H
|
||||
for (; num_threads < 0; ++num_threads) { // -<num_threads> to fork
|
||||
if (filename) {
|
||||
printf("FORK test only makes sense when no filename is specified.\n");
|
||||
return 2;
|
||||
}
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
printf("FORK failed!\n");
|
||||
return 1;
|
||||
case 0: // child
|
||||
return execl(argv[0], argv[0], argv[1], NULL);
|
||||
default:
|
||||
wait(NULL); // we'll let the kids run one at a time
|
||||
}
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "%s was compiled without support for fork() and exec()\n", argv[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
test_main_thread();
|
||||
|
||||
if (filename) {
|
||||
ProfilerStop();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
269
trunk/3rdparty/gperftools-2-fit/src/tests/profiler_unittest.sh
vendored
Executable file
269
trunk/3rdparty/gperftools-2-fit/src/tests/profiler_unittest.sh
vendored
Executable file
|
@ -0,0 +1,269 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2005, 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.
|
||||
|
||||
# ---
|
||||
# Author: Craig Silverstein
|
||||
#
|
||||
# Runs the 4 profiler unittests and makes sure their profiles look
|
||||
# appropriate. We expect two commandline args, as described below.
|
||||
#
|
||||
# We run under the assumption that if $PROFILER1 is run with no
|
||||
# arguments, it prints a usage line of the form
|
||||
# USAGE: <actual executable being run> [...]
|
||||
#
|
||||
# This is because libtool sometimes turns the 'executable' into a
|
||||
# shell script which runs an actual binary somewhere else.
|
||||
|
||||
# We expect BINDIR and PPROF_PATH to be set in the environment.
|
||||
# If not, we set them to some reasonable values
|
||||
BINDIR="${BINDIR:-.}"
|
||||
PPROF_PATH="${PPROF_PATH:-$BINDIR/src/pprof}"
|
||||
|
||||
if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then
|
||||
echo "USAGE: $0 [unittest dir] [path to pprof]"
|
||||
echo " By default, unittest_dir=$BINDIR, pprof_path=$PPROF_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TMPDIR=/tmp/profile_info
|
||||
|
||||
UNITTEST_DIR=${1:-$BINDIR}
|
||||
PPROF=${2:-$PPROF_PATH}
|
||||
|
||||
# We test the sliding-window functionality of the cpu-profile reader
|
||||
# by using a small stride, forcing lots of reads.
|
||||
PPROF_FLAGS="--test_stride=128"
|
||||
|
||||
PROFILER1="$UNITTEST_DIR/profiler1_unittest"
|
||||
PROFILER2="$UNITTEST_DIR/profiler2_unittest"
|
||||
PROFILER3="$UNITTEST_DIR/profiler3_unittest"
|
||||
PROFILER4="$UNITTEST_DIR/profiler4_unittest"
|
||||
|
||||
# Unfortunately, for us, libtool can replace executables with a shell
|
||||
# script that does some work before calling the 'real' executable
|
||||
# under a different name. We need the 'real' executable name to run
|
||||
# pprof on it. We've constructed all the binaries used in this
|
||||
# unittest so when they are called with no arguments, they report
|
||||
# their argv[0], which is the real binary name.
|
||||
Realname() {
|
||||
"$1" 2>&1 | awk '{print $2; exit;}'
|
||||
}
|
||||
|
||||
PROFILER1_REALNAME=`Realname "$PROFILER1"`
|
||||
PROFILER2_REALNAME=`Realname "$PROFILER2"`
|
||||
PROFILER3_REALNAME=`Realname "$PROFILER3"`
|
||||
PROFILER4_REALNAME=`Realname "$PROFILER4"`
|
||||
|
||||
# It's meaningful to the profiler, so make sure we know its state
|
||||
unset CPUPROFILE
|
||||
|
||||
# Some output/logging in the profiler can cause issues when running the unit
|
||||
# tests. For example, logging a warning when the profiler is detected as being
|
||||
# present but no CPUPROFILE is specified in the environment. Especially when
|
||||
# we are checking for a silent run or specific timing constraints are being
|
||||
# checked. So set the env variable signifying that we are running in a unit
|
||||
# test environment.
|
||||
PERFTOOLS_UNITTEST=1
|
||||
|
||||
rm -rf "$TMPDIR"
|
||||
mkdir "$TMPDIR" || exit 2
|
||||
|
||||
num_failures=0
|
||||
|
||||
RegisterFailure() {
|
||||
num_failures=`expr $num_failures + 1`
|
||||
}
|
||||
|
||||
# Takes two filenames representing profiles, with their executable scripts,
|
||||
# and a multiplier, and verifies that the 'contentful' functions in each
|
||||
# profile take the same time (possibly scaled by the given multiplier). It
|
||||
# used to be "same" meant within 50%, after adding an noise-reducing X units
|
||||
# to each value. But even that would often spuriously fail, so now it's
|
||||
# "both non-zero". We're pretty forgiving.
|
||||
VerifySimilar() {
|
||||
prof1="$TMPDIR/$1"
|
||||
exec1="$2"
|
||||
prof2="$TMPDIR/$3"
|
||||
exec2="$4"
|
||||
mult="$5"
|
||||
|
||||
# We are careful not to put exec1 and exec2 in quotes, because if
|
||||
# they are the empty string, it means we want to use the 1-arg
|
||||
# version of pprof.
|
||||
mthread1=`"$PPROF" $PPROF_FLAGS $exec1 "$prof1" | grep test_main_thread | awk '{print $1}'`
|
||||
mthread2=`"$PPROF" $PPROF_FLAGS $exec2 "$prof2" | grep test_main_thread | awk '{print $1}'`
|
||||
mthread1_plus=`expr $mthread1 + 5`
|
||||
mthread2_plus=`expr $mthread2 + 5`
|
||||
if [ -z "$mthread1" ] || [ -z "$mthread2" ] || \
|
||||
[ "$mthread1" -le 0 -o "$mthread2" -le 0 ]
|
||||
# || [ `expr $mthread1_plus \* $mult` -gt `expr $mthread2_plus \* 2` -o \
|
||||
# `expr $mthread1_plus \* $mult \* 2` -lt `expr $mthread2_plus` ]
|
||||
then
|
||||
echo
|
||||
echo ">>> profile on $exec1 vs $exec2 with multiplier $mult failed:"
|
||||
echo "Actual times (in profiling units) were '$mthread1' vs. '$mthread2'"
|
||||
echo
|
||||
RegisterFailure
|
||||
fi
|
||||
}
|
||||
|
||||
# Takes two filenames representing profiles, and optionally their
|
||||
# executable scripts (these may be empty if the profiles include
|
||||
# symbols), and verifies that the two profiles are identical.
|
||||
VerifyIdentical() {
|
||||
prof1="$TMPDIR/$1"
|
||||
exec1="$2"
|
||||
prof2="$TMPDIR/$3"
|
||||
exec2="$4"
|
||||
|
||||
# We are careful not to put exec1 and exec2 in quotes, because if
|
||||
# they are the empty string, it means we want to use the 1-arg
|
||||
# version of pprof.
|
||||
"$PPROF" $PPROF_FLAGS $exec1 "$prof1" > "$TMPDIR/out1"
|
||||
"$PPROF" $PPROF_FLAGS $exec2 "$prof2" > "$TMPDIR/out2"
|
||||
diff=`diff "$TMPDIR/out1" "$TMPDIR/out2"`
|
||||
|
||||
if [ ! -z "$diff" ]; then
|
||||
echo
|
||||
echo ">>> profile doesn't match, args: $exec1 $prof1 vs. $exec2 $prof2"
|
||||
echo ">>> Diff:"
|
||||
echo "$diff"
|
||||
echo
|
||||
RegisterFailure
|
||||
fi
|
||||
}
|
||||
|
||||
# Takes a filename representing a profile, with its executable,
|
||||
# and a multiplier, and verifies that the main-thread function takes
|
||||
# the same amount of time as the other-threads function (possibly scaled
|
||||
# by the given multiplier). Figuring out the multiplier can be tricky,
|
||||
# since by design the main thread runs twice as long as each of the
|
||||
# 'other' threads! It used to be "same" meant within 50%, after adding an
|
||||
# noise-reducing X units to each value. But even that would often
|
||||
# spuriously fail, so now it's "both non-zero". We're pretty forgiving.
|
||||
VerifyAcrossThreads() {
|
||||
prof1="$TMPDIR/$1"
|
||||
# We need to run the script with no args to get the actual exe name
|
||||
exec1="$2"
|
||||
mult="$3"
|
||||
|
||||
# We are careful not to put exec1 in quotes, because if it is the
|
||||
# empty string, it means we want to use the 1-arg version of pprof.
|
||||
mthread=`$PPROF $PPROF_FLAGS $exec1 "$prof1" | grep test_main_thread | awk '{print $1}'`
|
||||
othread=`$PPROF $PPROF_FLAGS $exec1 "$prof1" | grep test_other_thread | awk '{print $1}'`
|
||||
if [ -z "$mthread" ] || [ -z "$othread" ] || \
|
||||
[ "$mthread" -le 0 -o "$othread" -le 0 ]
|
||||
# || [ `expr $mthread \* $mult \* 3` -gt `expr $othread \* 10` -o \
|
||||
# `expr $mthread \* $mult \* 10` -lt `expr $othread \* 3` ]
|
||||
then
|
||||
echo
|
||||
echo ">>> profile on $exec1 (main vs thread) with multiplier $mult failed:"
|
||||
echo "Actual times (in profiling units) were '$mthread' vs. '$othread'"
|
||||
echo
|
||||
RegisterFailure
|
||||
fi
|
||||
}
|
||||
|
||||
echo
|
||||
echo ">>> WARNING <<<"
|
||||
echo "This test looks at timing information to determine correctness."
|
||||
echo "If your system is loaded, the test may spuriously fail."
|
||||
echo "If the test does fail with an 'Actual times' error, try running again."
|
||||
echo
|
||||
|
||||
# profiler1 is a non-threaded version
|
||||
"$PROFILER1" 50 1 "$TMPDIR/p1" || RegisterFailure
|
||||
"$PROFILER1" 100 1 "$TMPDIR/p2" || RegisterFailure
|
||||
VerifySimilar p1 "$PROFILER1_REALNAME" p2 "$PROFILER1_REALNAME" 2
|
||||
|
||||
# Verify the same thing works if we statically link
|
||||
"$PROFILER2" 50 1 "$TMPDIR/p3" || RegisterFailure
|
||||
"$PROFILER2" 100 1 "$TMPDIR/p4" || RegisterFailure
|
||||
VerifySimilar p3 "$PROFILER2_REALNAME" p4 "$PROFILER2_REALNAME" 2
|
||||
|
||||
# Verify the same thing works if we specify via CPUPROFILE
|
||||
CPUPROFILE="$TMPDIR/p5" "$PROFILER2" 50 || RegisterFailure
|
||||
CPUPROFILE="$TMPDIR/p6" "$PROFILER2" 100 || RegisterFailure
|
||||
VerifySimilar p5 "$PROFILER2_REALNAME" p6 "$PROFILER2_REALNAME" 2
|
||||
|
||||
CPUPROFILE="$TMPDIR/p5b" "$PROFILER3" 30 || RegisterFailure
|
||||
CPUPROFILE="$TMPDIR/p5c" "$PROFILER3" 60 || RegisterFailure
|
||||
VerifySimilar p5b "$PROFILER3_REALNAME" p5c "$PROFILER3_REALNAME" 2
|
||||
|
||||
# Now try what happens when we use threads
|
||||
"$PROFILER3" 30 2 "$TMPDIR/p7" || RegisterFailure
|
||||
"$PROFILER3" 60 2 "$TMPDIR/p8" || RegisterFailure
|
||||
VerifySimilar p7 "$PROFILER3_REALNAME" p8 "$PROFILER3_REALNAME" 2
|
||||
|
||||
"$PROFILER4" 30 2 "$TMPDIR/p9" || RegisterFailure
|
||||
"$PROFILER4" 60 2 "$TMPDIR/p10" || RegisterFailure
|
||||
VerifySimilar p9 "$PROFILER4_REALNAME" p10 "$PROFILER4_REALNAME" 2
|
||||
|
||||
# More threads!
|
||||
"$PROFILER4" 25 3 "$TMPDIR/p9" || RegisterFailure
|
||||
"$PROFILER4" 50 3 "$TMPDIR/p10" || RegisterFailure
|
||||
VerifySimilar p9 "$PROFILER4_REALNAME" p10 "$PROFILER4_REALNAME" 2
|
||||
|
||||
# Compare how much time the main thread takes compared to the other threads
|
||||
# Recall the main thread runs twice as long as the other threads, by design.
|
||||
"$PROFILER4" 20 4 "$TMPDIR/p11" || RegisterFailure
|
||||
VerifyAcrossThreads p11 "$PROFILER4_REALNAME" 2
|
||||
|
||||
# Test symbol save and restore
|
||||
"$PROFILER1" 50 1 "$TMPDIR/p12" || RegisterFailure
|
||||
"$PPROF" $PPROF_FLAGS "$PROFILER1_REALNAME" "$TMPDIR/p12" --raw \
|
||||
>"$TMPDIR/p13" 2>/dev/null || RegisterFailure
|
||||
VerifyIdentical p12 "$PROFILER1_REALNAME" p13 "" || RegisterFailure
|
||||
|
||||
"$PROFILER3" 30 2 "$TMPDIR/p14" || RegisterFailure
|
||||
"$PPROF" $PPROF_FLAGS "$PROFILER3_REALNAME" "$TMPDIR/p14" --raw \
|
||||
>"$TMPDIR/p15" 2>/dev/null || RegisterFailure
|
||||
VerifyIdentical p14 "$PROFILER3_REALNAME" p15 "" || RegisterFailure
|
||||
|
||||
# Test using ITIMER_REAL instead of ITIMER_PROF.
|
||||
env CPUPROFILE_REALTIME=1 "$PROFILER3" 30 2 "$TMPDIR/p16" || RegisterFailure
|
||||
env CPUPROFILE_REALTIME=1 "$PROFILER3" 60 2 "$TMPDIR/p17" || RegisterFailure
|
||||
VerifySimilar p16 "$PROFILER3_REALNAME" p17 "$PROFILER3_REALNAME" 2
|
||||
|
||||
|
||||
# Make sure that when we have a process with a fork, the profiles don't
|
||||
# clobber each other
|
||||
CPUPROFILE="$TMPDIR/pfork" "$PROFILER1" 1 -2 || RegisterFailure
|
||||
n=`ls $TMPDIR/pfork* | wc -l`
|
||||
if [ $n != 3 ]; then
|
||||
echo "FORK test FAILED: expected 3 profiles (for main + 2 children), found $n"
|
||||
num_failures=`expr $num_failures + 1`
|
||||
fi
|
||||
|
||||
rm -rf "$TMPDIR" # clean up
|
||||
|
||||
echo "Tests finished with $num_failures failures"
|
||||
exit $num_failures
|
64
trunk/3rdparty/gperftools-2-fit/src/tests/raw_printer_test.cc
vendored
Normal file
64
trunk/3rdparty/gperftools-2-fit/src/tests/raw_printer_test.cc
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright 2009 Google Inc. All Rights Reserved.
|
||||
// Author: sanjay@google.com (Sanjay Ghemawat)
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can
|
||||
// be found in the LICENSE file.
|
||||
|
||||
#include "raw_printer.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include "base/logging.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
#define TEST(a, b) void TEST_##a##_##b()
|
||||
#define RUN_TEST(a, b) TEST_##a##_##b()
|
||||
|
||||
TEST(RawPrinter, Empty) {
|
||||
char buffer[1];
|
||||
base::RawPrinter printer(buffer, arraysize(buffer));
|
||||
CHECK_EQ(0, printer.length());
|
||||
CHECK_EQ(string(""), buffer);
|
||||
CHECK_EQ(0, printer.space_left());
|
||||
printer.Printf("foo");
|
||||
CHECK_EQ(string(""), string(buffer));
|
||||
CHECK_EQ(0, printer.length());
|
||||
CHECK_EQ(0, printer.space_left());
|
||||
}
|
||||
|
||||
TEST(RawPrinter, PartiallyFilled) {
|
||||
char buffer[100];
|
||||
base::RawPrinter printer(buffer, arraysize(buffer));
|
||||
printer.Printf("%s %s", "hello", "world");
|
||||
CHECK_EQ(string("hello world"), string(buffer));
|
||||
CHECK_EQ(11, printer.length());
|
||||
CHECK_LT(0, printer.space_left());
|
||||
}
|
||||
|
||||
TEST(RawPrinter, Truncated) {
|
||||
char buffer[3];
|
||||
base::RawPrinter printer(buffer, arraysize(buffer));
|
||||
printer.Printf("%d", 12345678);
|
||||
CHECK_EQ(string("12"), string(buffer));
|
||||
CHECK_EQ(2, printer.length());
|
||||
CHECK_EQ(0, printer.space_left());
|
||||
}
|
||||
|
||||
TEST(RawPrinter, ExactlyFilled) {
|
||||
char buffer[12];
|
||||
base::RawPrinter printer(buffer, arraysize(buffer));
|
||||
printer.Printf("%s %s", "hello", "world");
|
||||
CHECK_EQ(string("hello world"), string(buffer));
|
||||
CHECK_EQ(11, printer.length());
|
||||
CHECK_EQ(0, printer.space_left());
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
RUN_TEST(RawPrinter, Empty);
|
||||
RUN_TEST(RawPrinter, PartiallyFilled);
|
||||
RUN_TEST(RawPrinter, Truncated);
|
||||
RUN_TEST(RawPrinter, ExactlyFilled);
|
||||
printf("PASS\n");
|
||||
return 0; // 0 means success
|
||||
}
|
125
trunk/3rdparty/gperftools-2-fit/src/tests/realloc_unittest.cc
vendored
Normal file
125
trunk/3rdparty/gperftools-2-fit/src/tests/realloc_unittest.cc
vendored
Normal file
|
@ -0,0 +1,125 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2004, 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.
|
||||
|
||||
// ---
|
||||
// Author: Sanjay Ghemawat
|
||||
//
|
||||
// Test realloc() functionality
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <assert.h> // for assert
|
||||
#include <stdio.h>
|
||||
#include <stddef.h> // for size_t, NULL
|
||||
#include <stdlib.h> // for free, malloc, realloc
|
||||
#include <algorithm> // for min
|
||||
#include "base/logging.h"
|
||||
|
||||
using std::min;
|
||||
|
||||
|
||||
// Fill a buffer of the specified size with a predetermined pattern
|
||||
static void Fill(unsigned char* buffer, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
buffer[i] = (i & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the specified buffer has the predetermined pattern
|
||||
// generated by Fill()
|
||||
static bool Valid(unsigned char* buffer, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (buffer[i] != (i & 0xff)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the next interesting size/delta to check. Returns -1 if no more.
|
||||
static int NextSize(int size) {
|
||||
if (size < 100) {
|
||||
return size+1;
|
||||
} else if (size < 100000) {
|
||||
// Find next power of two
|
||||
int power = 1;
|
||||
while (power < size) {
|
||||
power <<= 1;
|
||||
}
|
||||
|
||||
// Yield (power-1, power, power+1)
|
||||
if (size < power-1) {
|
||||
return power-1;
|
||||
} else if (size == power-1) {
|
||||
return power;
|
||||
} else {
|
||||
assert(size == power);
|
||||
return power+1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
|
||||
for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
|
||||
unsigned char* src = (unsigned char*) malloc(src_size);
|
||||
Fill(src, src_size);
|
||||
unsigned char* dst = (unsigned char*) realloc(src, dst_size);
|
||||
CHECK(Valid(dst, min(src_size, dst_size)));
|
||||
Fill(dst, dst_size);
|
||||
CHECK(Valid(dst, dst_size));
|
||||
if (dst != NULL) free(dst);
|
||||
}
|
||||
}
|
||||
|
||||
// Now make sure realloc works correctly even when we overflow the
|
||||
// packed cache, so some entries are evicted from the cache.
|
||||
// The cache has 2^12 entries, keyed by page number.
|
||||
const int kNumEntries = 1 << 14;
|
||||
int** p = (int**)malloc(sizeof(*p) * kNumEntries);
|
||||
int sum = 0;
|
||||
for (int i = 0; i < kNumEntries; i++) {
|
||||
p[i] = (int*)malloc(8192); // no page size is likely to be bigger
|
||||
p[i][1000] = i; // use memory deep in the heart of p
|
||||
}
|
||||
for (int i = 0; i < kNumEntries; i++) {
|
||||
p[i] = (int*)realloc(p[i], 9000);
|
||||
}
|
||||
for (int i = 0; i < kNumEntries; i++) {
|
||||
sum += p[i][1000];
|
||||
free(p[i]);
|
||||
}
|
||||
CHECK_EQ(kNumEntries/2 * (kNumEntries - 1), sum); // assume kNE is even
|
||||
free(p);
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
631
trunk/3rdparty/gperftools-2-fit/src/tests/sampler_test.cc
vendored
Normal file
631
trunk/3rdparty/gperftools-2-fit/src/tests/sampler_test.cc
vendored
Normal file
|
@ -0,0 +1,631 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// 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 <math.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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.RecordAllocation(size_big)) {
|
||||
counter_big += 1;
|
||||
}
|
||||
for (int i = 0; i < 129; i++) {
|
||||
if (!sampler.RecordAllocation(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("log2(q) = %f\n", log(q)/log(2.0));
|
||||
uint64_t smallest_sample_step
|
||||
= static_cast<uint64_t>(min(log2(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);
|
||||
uint64_t largest_sample_step
|
||||
= static_cast<uint64_t>(min(log2(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 <= 63; 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();
|
||||
}
|
83
trunk/3rdparty/gperftools-2-fit/src/tests/sampling_test.cc
vendored
Normal file
83
trunk/3rdparty/gperftools-2-fit/src/tests/sampling_test.cc
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// 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.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// This tests ReadStackTraces and ReadGrowthStackTraces. It does this
|
||||
// by doing a bunch of allocations and then calling those functions.
|
||||
// A driver shell-script can call this, and then call pprof, and
|
||||
// verify the expected output. The output is written to
|
||||
// argv[1].heap and argv[1].growth
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include "base/logging.h"
|
||||
#include <gperftools/malloc_extension.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
extern "C" void* AllocateAllocate() ATTRIBUTE_NOINLINE;
|
||||
|
||||
extern "C" void* AllocateAllocate() {
|
||||
// The VLOG's are mostly to discourage inlining
|
||||
VLOG(1, "Allocating some more");
|
||||
void* p = malloc(10000);
|
||||
VLOG(1, "Done allocating");
|
||||
return p;
|
||||
}
|
||||
|
||||
static void WriteStringToFile(const string& s, const string& filename) {
|
||||
FILE* fp = fopen(filename.c_str(), "w");
|
||||
fwrite(s.data(), 1, s.length(), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "USAGE: %s <base of output files>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
for (int i = 0; i < 8000; i++) {
|
||||
AllocateAllocate();
|
||||
}
|
||||
|
||||
string s;
|
||||
MallocExtension::instance()->GetHeapSample(&s);
|
||||
WriteStringToFile(s, string(argv[1]) + ".heap");
|
||||
|
||||
s.clear();
|
||||
MallocExtension::instance()->GetHeapGrowthStacks(&s);
|
||||
WriteStringToFile(s, string(argv[1]) + ".growth");
|
||||
|
||||
return 0;
|
||||
}
|
94
trunk/3rdparty/gperftools-2-fit/src/tests/sampling_test.sh
vendored
Executable file
94
trunk/3rdparty/gperftools-2-fit/src/tests/sampling_test.sh
vendored
Executable file
|
@ -0,0 +1,94 @@
|
|||
#!/bin/sh
|
||||
|
||||
# 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.
|
||||
#
|
||||
# ---
|
||||
# Author: Craig Silverstein
|
||||
#
|
||||
# This is a test that tcmalloc creates, and pprof reads, sampling data
|
||||
# correctly: both for the heap profile (ReadStackTraces) and for
|
||||
# growth in the heap sized (ReadGrowthStackTraces).
|
||||
|
||||
BINDIR="${BINDIR:-.}"
|
||||
PPROF_PATH="${PPROF_PATH:-$BINDIR/src/pprof}"
|
||||
|
||||
if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then
|
||||
echo "USAGE: $0 [unittest dir] [path to pprof]"
|
||||
echo " By default, unittest_dir=$BINDIR, pprof_path=$PPROF_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SAMPLING_TEST="${1:-$BINDIR/sampling_test}"
|
||||
PPROF="${2:-$PPROF_PATH}"
|
||||
OUTDIR="/tmp/sampling_test_dir"
|
||||
|
||||
# libtool is annoying, and puts the actual executable in a different
|
||||
# directory, replacing the seeming-executable with a shell script.
|
||||
# We use the error output of sampling_test to indicate its real location
|
||||
SAMPLING_TEST_BINARY=`"$SAMPLING_TEST" 2>&1 | awk '/USAGE/ {print $2; exit;}'`
|
||||
|
||||
# A kludge for cygwin. Unfortunately, 'test -f' says that 'foo' exists
|
||||
# even when it doesn't, and only foo.exe exists. Other unix utilities
|
||||
# (like nm) need you to say 'foo.exe'. We use one such utility, cat, to
|
||||
# see what the *real* binary name is.
|
||||
if ! cat "$SAMPLING_TEST_BINARY" >/dev/null 2>&1; then
|
||||
SAMPLING_TEST_BINARY="$SAMPLING_TEST_BINARY".exe
|
||||
fi
|
||||
|
||||
die() { # runs the command given as arguments, and then dies.
|
||||
echo "FAILED. Output from $@"
|
||||
echo "----"
|
||||
"$@"
|
||||
echo "----"
|
||||
exit 1
|
||||
}
|
||||
|
||||
rm -rf "$OUTDIR" || die "Unable to delete $OUTDIR"
|
||||
mkdir "$OUTDIR" || die "Unable to create $OUTDIR"
|
||||
|
||||
# This puts the output into out.heap and out.growth. It allocates
|
||||
# 8*10^7 bytes of memory, which is 76M. Because we sample, the
|
||||
# estimate may be a bit high or a bit low: we accept anything from
|
||||
# 50M to 99M.
|
||||
"$SAMPLING_TEST" "$OUTDIR/out"
|
||||
|
||||
echo "Testing heap output..."
|
||||
"$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.heap" \
|
||||
| grep '[5-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \
|
||||
|| die "$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.heap"
|
||||
echo "OK"
|
||||
|
||||
echo "Testing growth output..."
|
||||
"$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.growth" \
|
||||
| grep '[5-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \
|
||||
|| die "$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.growth"
|
||||
echo "OK"
|
||||
|
||||
echo "PASS"
|
71
trunk/3rdparty/gperftools-2-fit/src/tests/simple_compat_test.cc
vendored
Normal file
71
trunk/3rdparty/gperftools-2-fit/src/tests/simple_compat_test.cc
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2012, 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.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// This just verifies that we can compile code that #includes stuff
|
||||
// via the backwards-compatibility 'google/' #include-dir. It does
|
||||
// not include config.h on purpose, to better simulate a perftools
|
||||
// client.
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define GPERFTOOLS_SUPPRESS_LEGACY_WARNING
|
||||
|
||||
#include <google/heap-checker.h>
|
||||
#include <google/heap-profiler.h>
|
||||
#include <google/malloc_extension.h>
|
||||
#include <google/malloc_extension_c.h>
|
||||
#include <google/malloc_hook.h>
|
||||
#include <google/malloc_hook_c.h>
|
||||
#include <google/profiler.h>
|
||||
#include <google/stacktrace.h>
|
||||
#include <google/tcmalloc.h>
|
||||
|
||||
// We don't link in -lprofiler for this test, so be sure not to make
|
||||
// any function calls that require the cpu-profiler code. The
|
||||
// heap-profiler is ok.
|
||||
|
||||
HeapLeakChecker::Disabler* heap_checker_h;
|
||||
void (*heap_profiler_h)(const char*) = &HeapProfilerStart;
|
||||
MallocExtension::Ownership malloc_extension_h;
|
||||
MallocExtension_Ownership malloc_extension_c_h;
|
||||
MallocHook::NewHook* malloc_hook_h;
|
||||
MallocHook_NewHook* malloc_hook_c_h;
|
||||
ProfilerOptions* profiler_h;
|
||||
int (*stacktrace_h)(void**, int, int) = &GetStackTrace;
|
||||
void* (*tcmalloc_h)(size_t) = &tc_new;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
93
trunk/3rdparty/gperftools-2-fit/src/tests/stack_trace_table_test.cc
vendored
Normal file
93
trunk/3rdparty/gperftools-2-fit/src/tests/stack_trace_table_test.cc
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright 2009 Google Inc. All Rights Reserved.
|
||||
// Author: fikes@google.com (Andrew Fikes)
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can
|
||||
// be found in the LICENSE file.
|
||||
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <stdio.h> // for puts()
|
||||
#include "stack_trace_table.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/spinlock.h"
|
||||
#include "static_vars.h"
|
||||
|
||||
#undef ARRAYSIZE // may be defined on, eg, windows
|
||||
#define ARRAYSIZE(a) ( sizeof(a) / sizeof(*(a)) )
|
||||
|
||||
static void CheckTracesAndReset(tcmalloc::StackTraceTable* table,
|
||||
const uintptr_t* expected, int len) {
|
||||
void** entries = table->ReadStackTracesAndClear();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
CHECK_EQ(reinterpret_cast<uintptr_t>(entries[i]), expected[i]);
|
||||
}
|
||||
delete[] entries;
|
||||
}
|
||||
|
||||
static void AddTrace(tcmalloc::StackTraceTable* table,
|
||||
const tcmalloc::StackTrace& t) {
|
||||
// Normally we'd need this lock, but since the test is single-threaded
|
||||
// we don't. I comment it out on windows because the DLL-decl thing
|
||||
// is really annoying in this case.
|
||||
#ifndef _MSC_VER
|
||||
SpinLockHolder h(tcmalloc::Static::pageheap_lock());
|
||||
#endif
|
||||
table->AddTrace(t);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
tcmalloc::StackTraceTable table;
|
||||
|
||||
// Empty table
|
||||
CHECK_EQ(table.depth_total(), 0);
|
||||
CHECK_EQ(table.bucket_total(), 0);
|
||||
static const uintptr_t k1[] = {0};
|
||||
CheckTracesAndReset(&table, k1, ARRAYSIZE(k1));
|
||||
|
||||
tcmalloc::StackTrace t1;
|
||||
t1.size = static_cast<uintptr_t>(1024);
|
||||
t1.depth = static_cast<uintptr_t>(2);
|
||||
t1.stack[0] = reinterpret_cast<void*>(1);
|
||||
t1.stack[1] = reinterpret_cast<void*>(2);
|
||||
|
||||
|
||||
tcmalloc::StackTrace t2;
|
||||
t2.size = static_cast<uintptr_t>(512);
|
||||
t2.depth = static_cast<uintptr_t>(2);
|
||||
t2.stack[0] = reinterpret_cast<void*>(2);
|
||||
t2.stack[1] = reinterpret_cast<void*>(1);
|
||||
|
||||
// Table w/ just t1
|
||||
AddTrace(&table, t1);
|
||||
CHECK_EQ(table.depth_total(), 2);
|
||||
CHECK_EQ(table.bucket_total(), 1);
|
||||
static const uintptr_t k2[] = {1, 1024, 2, 1, 2, 0};
|
||||
CheckTracesAndReset(&table, k2, ARRAYSIZE(k2));
|
||||
|
||||
// Table w/ t1, t2
|
||||
AddTrace(&table, t1);
|
||||
AddTrace(&table, t2);
|
||||
CHECK_EQ(table.depth_total(), 4);
|
||||
CHECK_EQ(table.bucket_total(), 2);
|
||||
static const uintptr_t k3[] = {1, 512, 2, 2, 1, 1, 1024, 2, 1, 2, 0};
|
||||
CheckTracesAndReset(&table, k3, ARRAYSIZE(k3));
|
||||
|
||||
// Table w/ t1, t3
|
||||
// Same stack as t1, but w/ different size
|
||||
tcmalloc::StackTrace t3;
|
||||
t3.size = static_cast<uintptr_t>(2);
|
||||
t3.depth = static_cast<uintptr_t>(2);
|
||||
t3.stack[0] = reinterpret_cast<void*>(1);
|
||||
t3.stack[1] = reinterpret_cast<void*>(2);
|
||||
|
||||
AddTrace(&table, t1);
|
||||
AddTrace(&table, t3);
|
||||
CHECK_EQ(table.depth_total(), 4);
|
||||
CHECK_EQ(table.bucket_total(), 2);
|
||||
static const uintptr_t k5[] = {1, 2, 2, 1, 2, 1, 1024, 2, 1, 2, 0};
|
||||
CheckTracesAndReset(&table, k5, ARRAYSIZE(k5));
|
||||
|
||||
puts("PASS");
|
||||
return 0;
|
||||
}
|
298
trunk/3rdparty/gperftools-2-fit/src/tests/stacktrace_unittest.cc
vendored
Normal file
298
trunk/3rdparty/gperftools-2-fit/src/tests/stacktrace_unittest.cc
vendored
Normal file
|
@ -0,0 +1,298 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2005, 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.
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// On those architectures we can and should test if backtracing with
|
||||
// ucontext and from signal handler works
|
||||
#if __GNUC__ && __linux__ && (__x86_64__ || __aarch64__ || __riscv)
|
||||
#include <signal.h>
|
||||
#define TEST_UCONTEXT_BITS 1
|
||||
#endif
|
||||
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/logging.h"
|
||||
#include <gperftools/stacktrace.h>
|
||||
#include "tests/testutil.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Obtain a backtrace, verify that the expected callers are present in the
|
||||
// backtrace, and maybe print the backtrace to stdout.
|
||||
|
||||
// The sequence of functions whose return addresses we expect to see in the
|
||||
// backtrace.
|
||||
const int BACKTRACE_STEPS = 6;
|
||||
|
||||
struct AddressRange {
|
||||
const void *start, *end;
|
||||
};
|
||||
|
||||
// Expected function [start,end] range.
|
||||
AddressRange expected_range[BACKTRACE_STEPS];
|
||||
|
||||
#if __GNUC__
|
||||
// Using GCC extension: address of a label can be taken with '&&label'.
|
||||
// Start should be a label somewhere before recursive call, end somewhere
|
||||
// after it.
|
||||
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
|
||||
do { \
|
||||
(prange)->start = &&start_label; \
|
||||
(prange)->end = &&end_label; \
|
||||
CHECK_LT((prange)->start, (prange)->end); \
|
||||
} while (0)
|
||||
// This macro expands into "unmovable" code (opaque to GCC), and that
|
||||
// prevents GCC from moving a_label up or down in the code.
|
||||
// Without it, there is no code following the 'end' label, and GCC
|
||||
// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
|
||||
// the recursive call.
|
||||
#define DECLARE_ADDRESS_LABEL(a_label) \
|
||||
a_label: do { __asm__ __volatile__(""); } while (0)
|
||||
// Gcc 4.4.0 may split function into multiple chunks, and the chunk
|
||||
// performing recursive call may end up later in the code then the return
|
||||
// instruction (this actually happens with FDO).
|
||||
// Adjust function range from __builtin_return_address.
|
||||
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
|
||||
do { \
|
||||
void *ra = __builtin_return_address(0); \
|
||||
CHECK_LT((prange)->start, ra); \
|
||||
if (ra > (prange)->end) { \
|
||||
printf("Adjusting range from %p..%p to %p..%p\n", \
|
||||
(prange)->start, (prange)->end, \
|
||||
(prange)->start, ra); \
|
||||
(prange)->end = ra; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
// Assume the Check* functions below are not longer than 256 bytes.
|
||||
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
|
||||
do { \
|
||||
(prange)->start = reinterpret_cast<const void *>(&fn); \
|
||||
(prange)->end = reinterpret_cast<const char *>(&fn) + 256; \
|
||||
} while (0)
|
||||
#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
|
||||
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
|
||||
#endif // __GNUC__
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------//
|
||||
|
||||
void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
|
||||
{
|
||||
CHECK_GE(ret_addr, range.start);
|
||||
CHECK_LE(ret_addr, range.end);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------//
|
||||
|
||||
#if TEST_UCONTEXT_BITS
|
||||
|
||||
struct get_stack_trace_args {
|
||||
int *size_ptr;
|
||||
void **result;
|
||||
int max_depth;
|
||||
uintptr_t where;
|
||||
} gst_args;
|
||||
|
||||
static
|
||||
void SignalHandler(int dummy, siginfo_t *si, void* ucv) {
|
||||
auto uc = static_cast<ucontext_t*>(ucv);
|
||||
|
||||
#ifdef __riscv
|
||||
uc->uc_mcontext.__gregs[REG_PC] = gst_args.where;
|
||||
#elif __aarch64__
|
||||
uc->uc_mcontext.pc = gst_args.where;
|
||||
#else
|
||||
uc->uc_mcontext.gregs[REG_RIP] = gst_args.where;
|
||||
#endif
|
||||
|
||||
*gst_args.size_ptr = GetStackTraceWithContext(
|
||||
gst_args.result,
|
||||
gst_args.max_depth,
|
||||
2,
|
||||
uc);
|
||||
}
|
||||
|
||||
int ATTRIBUTE_NOINLINE CaptureLeafUContext(void **stack, int stack_len) {
|
||||
INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
|
||||
DECLARE_ADDRESS_LABEL(start);
|
||||
|
||||
int size;
|
||||
|
||||
printf("Capturing stack trace from signal's ucontext\n");
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = SignalHandler;
|
||||
sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
|
||||
int rv = sigaction(SIGSEGV, &sa, nullptr);
|
||||
CHECK(rv == 0);
|
||||
|
||||
gst_args.size_ptr = &size;
|
||||
gst_args.result = stack;
|
||||
gst_args.max_depth = stack_len;
|
||||
gst_args.where = reinterpret_cast<uintptr_t>(noopt(&&after));
|
||||
|
||||
// now, "write" to null pointer and trigger sigsegv to run signal
|
||||
// handler. It'll then change PC to after, as if we jumped one line
|
||||
// below.
|
||||
*noopt(reinterpret_cast<void**>(0)) = 0;
|
||||
// this is not reached, but gcc gets really odd if we don't actually
|
||||
// use computed goto.
|
||||
static void* jump_target = &&after;
|
||||
goto *noopt(&jump_target);
|
||||
|
||||
after:
|
||||
printf("Obtained %d stack frames.\n", size);
|
||||
CHECK_GE(size, 1);
|
||||
CHECK_LE(size, stack_len);
|
||||
|
||||
DECLARE_ADDRESS_LABEL(end);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif // TEST_UCONTEXT_BITS
|
||||
|
||||
int ATTRIBUTE_NOINLINE CaptureLeafPlain(void **stack, int stack_len) {
|
||||
INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
|
||||
DECLARE_ADDRESS_LABEL(start);
|
||||
|
||||
int size = GetStackTrace(stack, stack_len, 0);
|
||||
|
||||
printf("Obtained %d stack frames.\n", size);
|
||||
CHECK_GE(size, 1);
|
||||
CHECK_LE(size, stack_len);
|
||||
|
||||
DECLARE_ADDRESS_LABEL(end);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void ATTRIBUTE_NOINLINE CheckStackTrace(int);
|
||||
|
||||
int (*leaf_capture_fn)(void**, int) = CaptureLeafPlain;
|
||||
|
||||
void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(int i) {
|
||||
const int STACK_LEN = 20;
|
||||
void *stack[STACK_LEN];
|
||||
int size;
|
||||
|
||||
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
|
||||
|
||||
size = leaf_capture_fn(stack, STACK_LEN);
|
||||
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
{
|
||||
char **strings = backtrace_symbols(stack, size);
|
||||
for (int i = 0; i < size; i++)
|
||||
printf("%s %p\n", strings[i], stack[i]);
|
||||
printf("CheckStackTrace() addr: %p\n", &CheckStackTrace);
|
||||
free(strings);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0, j = 0; i < BACKTRACE_STEPS; i++, j++) {
|
||||
if (i == 1 && j == 1) {
|
||||
// this is expected to be our function for which we don't
|
||||
// establish bounds. So skip.
|
||||
j++;
|
||||
}
|
||||
printf("Backtrace %d: expected: %p..%p actual: %p ... ",
|
||||
i, expected_range[i].start, expected_range[i].end, stack[j]);
|
||||
fflush(stdout);
|
||||
CheckRetAddrIsInFunction(stack[j], expected_range[i]);
|
||||
printf("OK\n");
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------//
|
||||
|
||||
/* Dummy functions to make the backtrace more interesting. */
|
||||
void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) {
|
||||
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]);
|
||||
INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]);
|
||||
DECLARE_ADDRESS_LABEL(start);
|
||||
for (int j = i; j >= 0; j--)
|
||||
CheckStackTraceLeaf(j);
|
||||
DECLARE_ADDRESS_LABEL(end);
|
||||
}
|
||||
void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) {
|
||||
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]);
|
||||
INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]);
|
||||
DECLARE_ADDRESS_LABEL(start);
|
||||
for (int j = i; j >= 0; j--)
|
||||
CheckStackTrace4(j);
|
||||
DECLARE_ADDRESS_LABEL(end);
|
||||
}
|
||||
void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) {
|
||||
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]);
|
||||
INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]);
|
||||
DECLARE_ADDRESS_LABEL(start);
|
||||
for (int j = i; j >= 0; j--)
|
||||
CheckStackTrace3(j);
|
||||
DECLARE_ADDRESS_LABEL(end);
|
||||
}
|
||||
void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
|
||||
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]);
|
||||
INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]);
|
||||
DECLARE_ADDRESS_LABEL(start);
|
||||
for (int j = i; j >= 0; j--)
|
||||
CheckStackTrace2(j);
|
||||
DECLARE_ADDRESS_LABEL(end);
|
||||
}
|
||||
void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
|
||||
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
|
||||
DECLARE_ADDRESS_LABEL(start);
|
||||
for (int j = i; j >= 0; j--) {
|
||||
CheckStackTrace1(j);
|
||||
}
|
||||
DECLARE_ADDRESS_LABEL(end);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
//-----------------------------------------------------------------------//
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
CheckStackTrace(0);
|
||||
printf("PASS\n");
|
||||
|
||||
#if TEST_UCONTEXT_BITS
|
||||
leaf_capture_fn = CaptureLeafUContext;
|
||||
CheckStackTrace(0);
|
||||
printf("PASS\n");
|
||||
#endif // TEST_UCONTEXT_BITS
|
||||
|
||||
return 0;
|
||||
}
|
161
trunk/3rdparty/gperftools-2-fit/src/tests/system-alloc_unittest.cc
vendored
Normal file
161
trunk/3rdparty/gperftools-2-fit/src/tests/system-alloc_unittest.cc
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2007, 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.
|
||||
|
||||
// ---
|
||||
// Author: Arun Sharma
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
|
||||
#include "system-alloc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#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 <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "base/logging.h" // for Check_GEImpl, Check_LTImpl, etc
|
||||
#include "common.h" // for kAddressBits
|
||||
#include "gperftools/malloc_extension.h" // for MallocExtension::instance
|
||||
#include "gperftools/tcmalloc.h"
|
||||
#include "tests/testutil.h"
|
||||
|
||||
class ArraySysAllocator : public SysAllocator {
|
||||
public:
|
||||
// Was this allocator invoked at least once?
|
||||
bool invoked_;
|
||||
|
||||
ArraySysAllocator() : SysAllocator() {
|
||||
ptr_ = 0;
|
||||
invoked_ = false;
|
||||
}
|
||||
|
||||
void* Alloc(size_t size, size_t *actual_size, size_t alignment) {
|
||||
invoked_ = true;
|
||||
|
||||
if (size > kArraySize) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *result = &array_[ptr_];
|
||||
uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
|
||||
|
||||
if (actual_size) {
|
||||
*actual_size = size;
|
||||
}
|
||||
|
||||
// Try to get more memory for alignment
|
||||
size_t extra = alignment - (ptr & (alignment-1));
|
||||
size += extra;
|
||||
CHECK_LT(ptr_ + size, kArraySize);
|
||||
|
||||
if ((ptr & (alignment-1)) != 0) {
|
||||
ptr += alignment - (ptr & (alignment-1));
|
||||
}
|
||||
|
||||
ptr_ += size;
|
||||
return reinterpret_cast<void *>(ptr);
|
||||
}
|
||||
|
||||
void DumpStats() {
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kArraySize = 8 * 1024 * 1024;
|
||||
char array_[kArraySize];
|
||||
// We allocate the next chunk from here
|
||||
int ptr_;
|
||||
|
||||
};
|
||||
const int ArraySysAllocator::kArraySize;
|
||||
ArraySysAllocator a;
|
||||
|
||||
static void TestBasicInvoked() {
|
||||
MallocExtension::instance()->SetSystemAllocator(&a);
|
||||
|
||||
// An allocation size that is likely to trigger the system allocator.
|
||||
// XXX: this is implementation specific.
|
||||
char *p = noopt(new char[1024 * 1024]);
|
||||
delete [] p;
|
||||
|
||||
// Make sure that our allocator was invoked.
|
||||
CHECK(a.invoked_);
|
||||
}
|
||||
|
||||
#if 0 // could port this to various OSs, but won't bother for now
|
||||
TEST(AddressBits, CpuVirtualBits) {
|
||||
// Check that kAddressBits is as least as large as either the number of bits
|
||||
// in a pointer or as the number of virtual bits handled by the processor.
|
||||
// To be effective this test must be run on each processor model.
|
||||
const int kPointerBits = 8 * sizeof(void*);
|
||||
const int kImplementedVirtualBits = NumImplementedVirtualBits();
|
||||
|
||||
CHECK_GE(kAddressBits, std::min(kImplementedVirtualBits, kPointerBits));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void TestBasicRetryFailTest() {
|
||||
// Check with the allocator still works after a failed allocation.
|
||||
//
|
||||
// There is no way to call malloc and guarantee it will fail. malloc takes a
|
||||
// size_t parameter and the C++ standard does not constrain the size of
|
||||
// size_t. For example, consider an implementation where size_t is 32 bits
|
||||
// and pointers are 64 bits.
|
||||
//
|
||||
// It is likely, though, that sizeof(size_t) == sizeof(void*). In that case,
|
||||
// the first allocation here might succeed but the second allocation must
|
||||
// fail.
|
||||
//
|
||||
// If the second allocation succeeds, you will have to rewrite or
|
||||
// disable this test.
|
||||
// The weird parens are to avoid macro-expansion of 'max' on windows.
|
||||
const size_t kHugeSize = (std::numeric_limits<size_t>::max)() / 2;
|
||||
void* p1 = noopt(malloc(kHugeSize));
|
||||
void* p2 = noopt(malloc(kHugeSize));
|
||||
CHECK(p2 == NULL);
|
||||
if (p1 != NULL) free(p1);
|
||||
|
||||
char* q = noopt(new char[1024]);
|
||||
CHECK(q != NULL);
|
||||
delete [] q;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
TestBasicInvoked();
|
||||
TestBasicRetryFailTest();
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
139
trunk/3rdparty/gperftools-2-fit/src/tests/tcmalloc_large_unittest.cc
vendored
Normal file
139
trunk/3rdparty/gperftools-2-fit/src/tests/tcmalloc_large_unittest.cc
vendored
Normal file
|
@ -0,0 +1,139 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2005, 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.
|
||||
|
||||
// ---
|
||||
// Author: Michael Chastain
|
||||
//
|
||||
// This is a unit test for large allocations in malloc and friends.
|
||||
// "Large" means "so large that they overflow the address space".
|
||||
// For 32 bits, this means allocations near 2^32 bytes and 2^31 bytes.
|
||||
// For 64 bits, this means allocations near 2^64 bytes and 2^63 bytes.
|
||||
|
||||
#include <stddef.h> // for size_t, NULL
|
||||
#include <stdlib.h> // for malloc, free, realloc
|
||||
#include <stdio.h>
|
||||
#include <set> // for set, etc
|
||||
|
||||
#include "base/logging.h" // for operator<<, CHECK, etc
|
||||
#include "gperftools/tcmalloc.h"
|
||||
#include "tests/testutil.h"
|
||||
|
||||
using std::set;
|
||||
|
||||
// Alloc a size that should always fail.
|
||||
|
||||
void TryAllocExpectFail(size_t size) {
|
||||
void* p1 = noopt(malloc(size));
|
||||
CHECK(p1 == NULL);
|
||||
|
||||
void* p2 = noopt(malloc(1));
|
||||
CHECK(p2 != NULL);
|
||||
|
||||
void* p3 = noopt(realloc(p2, size));
|
||||
CHECK(p3 == NULL);
|
||||
|
||||
free(p2);
|
||||
}
|
||||
|
||||
// Alloc a size that might work and might fail.
|
||||
// If it does work, touch some pages.
|
||||
|
||||
void TryAllocMightFail(size_t size) {
|
||||
unsigned char* p = static_cast<unsigned char*>(noopt(malloc(size)));
|
||||
if (p != NULL) {
|
||||
static const size_t kPoints = 1024;
|
||||
|
||||
for ( size_t i = 0; i < kPoints; ++i ) {
|
||||
p[i * (size / kPoints)] = static_cast<unsigned char>(i);
|
||||
}
|
||||
|
||||
for ( size_t i = 0; i < kPoints; ++i ) {
|
||||
CHECK(p[i * (size / kPoints)] == static_cast<unsigned char>(i));
|
||||
}
|
||||
|
||||
p[size-1] = 'M';
|
||||
CHECK(p[size-1] == 'M');
|
||||
}
|
||||
|
||||
free(noopt(p));
|
||||
}
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
// Allocate some 0-byte objects. They better be unique.
|
||||
// 0 bytes is not large but it exercises some paths related to
|
||||
// large-allocation code.
|
||||
{
|
||||
static const int kZeroTimes = 1024;
|
||||
printf("Test malloc(0) x %d\n", kZeroTimes);
|
||||
set<char*> p_set;
|
||||
for ( int i = 0; i < kZeroTimes; ++i ) {
|
||||
char* p = new char;
|
||||
CHECK(p != NULL);
|
||||
CHECK(p_set.find(p) == p_set.end());
|
||||
p_set.insert(p_set.end(), p);
|
||||
}
|
||||
// Just leak the memory.
|
||||
}
|
||||
|
||||
// Grab some memory so that some later allocations are guaranteed to fail.
|
||||
printf("Test small malloc\n");
|
||||
void* p_small = noopt(malloc(4*1048576));
|
||||
CHECK(p_small != NULL);
|
||||
|
||||
// Test sizes up near the maximum size_t.
|
||||
// These allocations test the wrap-around code.
|
||||
printf("Test malloc(0 - N)\n");
|
||||
const size_t zero = 0;
|
||||
static const size_t kMinusNTimes = 16384;
|
||||
for ( size_t i = 1; i < kMinusNTimes; ++i ) {
|
||||
TryAllocExpectFail(zero - i);
|
||||
}
|
||||
|
||||
// Test sizes a bit smaller.
|
||||
// The small malloc above guarantees that all these return NULL.
|
||||
printf("Test malloc(0 - 1048576 - N)\n");
|
||||
static const size_t kMinusMBMinusNTimes = 16384;
|
||||
for ( size_t i = 0; i < kMinusMBMinusNTimes; ++i) {
|
||||
TryAllocExpectFail(zero - 1048576 - i);
|
||||
}
|
||||
|
||||
// Test sizes at half of size_t.
|
||||
// These might or might not fail to allocate.
|
||||
printf("Test malloc(max/2 +- N)\n");
|
||||
static const size_t kHalfPlusMinusTimes = 64;
|
||||
const size_t half = (zero - 2) / 2 + 1;
|
||||
for ( size_t i = 0; i < kHalfPlusMinusTimes; ++i) {
|
||||
TryAllocMightFail(half - i);
|
||||
TryAllocMightFail(half + i);
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
1669
trunk/3rdparty/gperftools-2-fit/src/tests/tcmalloc_unittest.cc
vendored
Normal file
1669
trunk/3rdparty/gperftools-2-fit/src/tests/tcmalloc_unittest.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
84
trunk/3rdparty/gperftools-2-fit/src/tests/tcmalloc_unittest.sh
vendored
Executable file
84
trunk/3rdparty/gperftools-2-fit/src/tests/tcmalloc_unittest.sh
vendored
Executable file
|
@ -0,0 +1,84 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2013, 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.
|
||||
|
||||
# ---
|
||||
# Author: Adhemerval Zanella
|
||||
#
|
||||
# Runs the tcmalloc_unittest with various environment variables.
|
||||
# This is necessary because tuning some environment variables
|
||||
# (TCMALLOC_TRANSFER_NUM_OBJ for instance) should not change program
|
||||
# behavior, just performance.
|
||||
|
||||
BINDIR="${BINDIR:-.}"
|
||||
TCMALLOC_UNITTEST="${1:-$BINDIR/tcmalloc_unittest}"
|
||||
|
||||
TMPDIR=/tmp/tcmalloc_unittest
|
||||
rm -rf $TMPDIR || exit 2
|
||||
mkdir $TMPDIR || exit 3
|
||||
|
||||
run_unittest() {
|
||||
if $TCMALLOC_UNITTEST > $TMPDIR/output 2>&1; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "FAILED"
|
||||
echo "Output from the failed run:"
|
||||
echo "----"
|
||||
cat $TMPDIR/output
|
||||
echo "----"
|
||||
exit 4
|
||||
fi
|
||||
}
|
||||
|
||||
# $1: value of tcmalloc_unittest env. var.
|
||||
run_check_transfer_num_obj() {
|
||||
[ -n "$1" ] && export TCMALLOC_TRANSFER_NUM_OBJ="$1"
|
||||
|
||||
echo -n "Testing $TCMALLOC_UNITTEST with TCMALLOC_TRANSFER_NUM_OBJ=$1 ... "
|
||||
run_unittest
|
||||
}
|
||||
|
||||
run_check_transfer_num_obj ""
|
||||
run_check_transfer_num_obj "40"
|
||||
run_check_transfer_num_obj "4096"
|
||||
|
||||
echo -n "Testing $TCMALLOC_UNITTEST with TCMALLOC_AGGRESSIVE_DECOMMIT=t ... "
|
||||
|
||||
TCMALLOC_AGGRESSIVE_DECOMMIT=t run_unittest
|
||||
|
||||
echo -n "Testing $TCMALLOC_UNITTEST with TCMALLOC_HEAP_LIMIT_MB=512 ... "
|
||||
|
||||
TCMALLOC_HEAP_LIMIT_MB=512 run_unittest
|
||||
|
||||
echo -n "Testing $TCMALLOC_UNITTEST with TCMALLOC_ENABLE_SIZED_DELETE=t ..."
|
||||
|
||||
TCMALLOC_ENABLE_SIZED_DELETE=t run_unittest
|
||||
|
||||
echo "PASS"
|
224
trunk/3rdparty/gperftools-2-fit/src/tests/testutil.cc
vendored
Normal file
224
trunk/3rdparty/gperftools-2-fit/src/tests/testutil.cc
vendored
Normal file
|
@ -0,0 +1,224 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2007, 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.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// A few routines that are useful for multiple tests in this directory.
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <stdlib.h> // for NULL, abort()
|
||||
// On FreeBSD, if you #include <sys/resource.h>, you have to get stdint first.
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include "tests/testutil.h"
|
||||
|
||||
|
||||
// When compiled 64-bit and run on systems with swap several unittests will end
|
||||
// up trying to consume all of RAM+swap, and that can take quite some time. By
|
||||
// limiting the address-space size we get sufficient coverage without blowing
|
||||
// out job limits.
|
||||
void SetTestResourceLimit() {
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
// The actual resource we need to set varies depending on which flavour of
|
||||
// unix. On Linux we need RLIMIT_AS because that covers the use of mmap.
|
||||
// Otherwise hopefully RLIMIT_RSS is good enough. (Unfortunately 64-bit
|
||||
// and 32-bit headers disagree on the type of these constants!)
|
||||
#ifdef RLIMIT_AS
|
||||
#define USE_RESOURCE RLIMIT_AS
|
||||
#else
|
||||
#define USE_RESOURCE RLIMIT_RSS
|
||||
#endif
|
||||
|
||||
// Restrict the test to 1GiB, which should fit comfortably well on both
|
||||
// 32-bit and 64-bit hosts, and executes in ~1s.
|
||||
const rlim_t kMaxMem = 1<<30;
|
||||
|
||||
struct rlimit rlim;
|
||||
if (getrlimit(USE_RESOURCE, &rlim) == 0) {
|
||||
if (rlim.rlim_cur == RLIM_INFINITY || rlim.rlim_cur > kMaxMem) {
|
||||
rlim.rlim_cur = kMaxMem;
|
||||
setrlimit(USE_RESOURCE, &rlim); // ignore result
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SYS_RESOURCE_H */
|
||||
}
|
||||
|
||||
|
||||
struct FunctionAndId {
|
||||
void (*ptr_to_function)(int);
|
||||
int id;
|
||||
};
|
||||
|
||||
#if defined(NO_THREADS) || !(defined(HAVE_PTHREAD) || defined(_WIN32))
|
||||
|
||||
extern "C" void RunThread(void (*fn)()) {
|
||||
(*fn)();
|
||||
}
|
||||
|
||||
extern "C" void RunManyThreads(void (*fn)(), int count) {
|
||||
// I guess the best we can do is run fn sequentially, 'count' times
|
||||
for (int i = 0; i < count; i++)
|
||||
(*fn)();
|
||||
}
|
||||
|
||||
extern "C" void RunManyThreadsWithId(void (*fn)(int), int count, int) {
|
||||
for (int i = 0; i < count; i++)
|
||||
(*fn)(i); // stacksize doesn't make sense in a non-threaded context
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
extern "C" {
|
||||
// This helper function has the signature that pthread_create wants.
|
||||
DWORD WINAPI RunFunctionInThread(LPVOID ptr_to_ptr_to_fn) {
|
||||
(**static_cast<void (**)()>(ptr_to_ptr_to_fn))(); // runs fn
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WINAPI RunFunctionInThreadWithId(LPVOID ptr_to_fnid) {
|
||||
FunctionAndId* fn_and_id = static_cast<FunctionAndId*>(ptr_to_fnid);
|
||||
(*fn_and_id->ptr_to_function)(fn_and_id->id); // runs fn
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RunManyThreads(void (*fn)(), int count) {
|
||||
DWORD dummy;
|
||||
HANDLE* hThread = new HANDLE[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
hThread[i] = CreateThread(NULL, 0, RunFunctionInThread, &fn, 0, &dummy);
|
||||
if (hThread[i] == NULL) ExitProcess(i);
|
||||
}
|
||||
WaitForMultipleObjects(count, hThread, TRUE, INFINITE);
|
||||
for (int i = 0; i < count; i++) {
|
||||
CloseHandle(hThread[i]);
|
||||
}
|
||||
delete[] hThread;
|
||||
}
|
||||
|
||||
void RunThread(void (*fn)()) {
|
||||
RunManyThreads(fn, 1);
|
||||
}
|
||||
|
||||
void RunManyThreadsWithId(void (*fn)(int), int count, int stacksize) {
|
||||
DWORD dummy;
|
||||
HANDLE* hThread = new HANDLE[count];
|
||||
FunctionAndId* fn_and_ids = new FunctionAndId[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
fn_and_ids[i].ptr_to_function = fn;
|
||||
fn_and_ids[i].id = i;
|
||||
hThread[i] = CreateThread(NULL, stacksize, RunFunctionInThreadWithId,
|
||||
&fn_and_ids[i], 0, &dummy);
|
||||
if (hThread[i] == NULL) ExitProcess(i);
|
||||
}
|
||||
WaitForMultipleObjects(count, hThread, TRUE, INFINITE);
|
||||
for (int i = 0; i < count; i++) {
|
||||
CloseHandle(hThread[i]);
|
||||
}
|
||||
delete[] fn_and_ids;
|
||||
delete[] hThread;
|
||||
}
|
||||
}
|
||||
|
||||
#else // not NO_THREADS, not !HAVE_PTHREAD, not _WIN32
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
|
||||
|
||||
extern "C" {
|
||||
// This helper function has the signature that pthread_create wants.
|
||||
static void* RunFunctionInThread(void *ptr_to_ptr_to_fn) {
|
||||
(**static_cast<void (**)()>(ptr_to_ptr_to_fn))(); // runs fn
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* RunFunctionInThreadWithId(void *ptr_to_fnid) {
|
||||
FunctionAndId* fn_and_id = static_cast<FunctionAndId*>(ptr_to_fnid);
|
||||
(*fn_and_id->ptr_to_function)(fn_and_id->id); // runs fn
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Run a function in a thread of its own and wait for it to finish.
|
||||
// This is useful for tcmalloc testing, because each thread is
|
||||
// handled separately in tcmalloc, so there's interesting stuff to
|
||||
// test even if the threads are not running concurrently.
|
||||
void RunThread(void (*fn)()) {
|
||||
pthread_t thr;
|
||||
// Even though fn is on the stack, it's safe to pass a pointer to it,
|
||||
// because we pthread_join immediately (ie, before RunInThread exits).
|
||||
SAFE_PTHREAD(pthread_create(&thr, NULL, RunFunctionInThread, &fn));
|
||||
SAFE_PTHREAD(pthread_join(thr, NULL));
|
||||
}
|
||||
|
||||
void RunManyThreads(void (*fn)(), int count) {
|
||||
pthread_t* thr = new pthread_t[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
SAFE_PTHREAD(pthread_create(&thr[i], NULL, RunFunctionInThread, &fn));
|
||||
}
|
||||
for (int i = 0; i < count; i++) {
|
||||
SAFE_PTHREAD(pthread_join(thr[i], NULL));
|
||||
}
|
||||
delete[] thr;
|
||||
}
|
||||
|
||||
void RunManyThreadsWithId(void (*fn)(int), int count, int stacksize) {
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setstacksize(&attr, stacksize);
|
||||
|
||||
pthread_t* thr = new pthread_t[count];
|
||||
FunctionAndId* fn_and_ids = new FunctionAndId[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
fn_and_ids[i].ptr_to_function = fn;
|
||||
fn_and_ids[i].id = i;
|
||||
SAFE_PTHREAD(pthread_create(&thr[i], &attr,
|
||||
RunFunctionInThreadWithId, &fn_and_ids[i]));
|
||||
}
|
||||
for (int i = 0; i < count; i++) {
|
||||
SAFE_PTHREAD(pthread_join(thr[i], NULL));
|
||||
}
|
||||
delete[] fn_and_ids;
|
||||
delete[] thr;
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
73
trunk/3rdparty/gperftools-2-fit/src/tests/testutil.h
vendored
Normal file
73
trunk/3rdparty/gperftools-2-fit/src/tests/testutil.h
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2007, 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.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
|
||||
#ifndef TCMALLOC_TOOLS_TESTUTIL_H_
|
||||
#define TCMALLOC_TOOLS_TESTUTIL_H_
|
||||
|
||||
// Run a function in a thread of its own and wait for it to finish.
|
||||
// The function you pass in must have the signature
|
||||
// void MyFunction();
|
||||
extern "C" void RunThread(void (*fn)());
|
||||
|
||||
// Run a function X times, in X threads, and wait for them all to finish.
|
||||
// The function you pass in must have the signature
|
||||
// void MyFunction();
|
||||
extern "C" void RunManyThreads(void (*fn)(), int count);
|
||||
|
||||
// The 'advanced' version: run a function X times, in X threads, and
|
||||
// wait for them all to finish. Give them all the specified stack-size.
|
||||
// (If you're curious why this takes a stacksize and the others don't,
|
||||
// it's because the one client of this fn wanted to specify stacksize. :-) )
|
||||
// The function you pass in must have the signature
|
||||
// void MyFunction(int idx);
|
||||
// where idx is the index of the thread (which of the X threads this is).
|
||||
extern "C" void RunManyThreadsWithId(void (*fn)(int), int count, int stacksize);
|
||||
|
||||
// When compiled 64-bit and run on systems with swap several unittests will end
|
||||
// up trying to consume all of RAM+swap, and that can take quite some time. By
|
||||
// limiting the address-space size we get sufficient coverage without blowing
|
||||
// out job limits.
|
||||
void SetTestResourceLimit();
|
||||
|
||||
static void (* volatile noopt_helper)(void *) = +[] (void* dummy) {};
|
||||
|
||||
// This function forces compiler to forget specific knowledge about
|
||||
// value of 'val'. This is useful to avoid compiler optimizing out
|
||||
// new/delete pairs for our unit tests.
|
||||
template <typename T>
|
||||
T noopt(T val) {
|
||||
noopt_helper(&val);
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif // TCMALLOC_TOOLS_TESTUTIL_H_
|
84
trunk/3rdparty/gperftools-2-fit/src/tests/thread_dealloc_unittest.cc
vendored
Normal file
84
trunk/3rdparty/gperftools-2-fit/src/tests/thread_dealloc_unittest.cc
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2004, 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.
|
||||
|
||||
// ---
|
||||
// Author: Sanjay Ghemawat
|
||||
//
|
||||
// Check that we do not leak memory when cycling through lots of threads.
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> // for sleep()
|
||||
#endif
|
||||
#include "base/logging.h"
|
||||
#include <gperftools/malloc_extension.h>
|
||||
#include "tests/testutil.h" // for RunThread()
|
||||
|
||||
// Size/number of objects to allocate per thread (1 MB per thread)
|
||||
static const int kObjectSize = 1024;
|
||||
static const int kNumObjects = 1024;
|
||||
|
||||
// Number of threads to create and destroy
|
||||
static const int kNumThreads = 1000;
|
||||
|
||||
// Allocate lots of stuff
|
||||
static void AllocStuff() {
|
||||
void** objects = new void*[kNumObjects];
|
||||
for (int i = 0; i < kNumObjects; i++) {
|
||||
objects[i] = malloc(kObjectSize);
|
||||
}
|
||||
for (int i = 0; i < kNumObjects; i++) {
|
||||
free(objects[i]);
|
||||
}
|
||||
delete[] objects;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
static const int kDisplaySize = 1048576;
|
||||
char* display = new char[kDisplaySize];
|
||||
|
||||
for (int i = 0; i < kNumThreads; i++) {
|
||||
RunThread(&AllocStuff);
|
||||
|
||||
if (((i+1) % 200) == 0) {
|
||||
fprintf(stderr, "Iteration: %d of %d\n", (i+1), kNumThreads);
|
||||
MallocExtension::instance()->GetStats(display, kDisplaySize);
|
||||
fprintf(stderr, "%s\n", display);
|
||||
}
|
||||
}
|
||||
delete[] display;
|
||||
|
||||
printf("PASS\n");
|
||||
#ifdef HAVE_UNISTD_H
|
||||
sleep(1); // Prevent exit race problem with glibc
|
||||
#endif
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue