1 /* Copyright (c) 2006, Google Inc. 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 // A test for low_level_alloc.cc 32 33 #include <stdio.h> 34 #include <map> 35 #include "base/low_level_alloc.h" 36 #include "base/logging.h" 37 #include <gperftools/malloc_hook.h> 38 39 using std::map; 40 41 // a block of memory obtained from the allocator 42 struct BlockDesc { 43 char *ptr; // pointer to memory 44 int len; // number of bytes 45 int fill; // filled with data starting with this 46 }; 47 48 // Check that the pattern placed in the block d 49 // by RandomizeBlockDesc is still there. 50 static void CheckBlockDesc(const BlockDesc &d) { 51 for (int i = 0; i != d.len; i++) { 52 CHECK((d.ptr[i] & 0xff) == ((d.fill + i) & 0xff)); 53 } 54 } 55 56 // Fill the block "*d" with a pattern 57 // starting with a random byte. 58 static void RandomizeBlockDesc(BlockDesc *d) { 59 d->fill = rand() & 0xff; 60 for (int i = 0; i != d->len; i++) { 61 d->ptr[i] = (d->fill + i) & 0xff; 62 } 63 } 64 65 // Use to indicate to the malloc hooks that 66 // this calls is from LowLevelAlloc. 67 static bool using_low_level_alloc = false; 68 69 // n times, toss a coin, and based on the outcome 70 // either allocate a new block or deallocate an old block. 71 // New blocks are placed in a map with a random key 72 // and initialized with RandomizeBlockDesc(). 73 // If keys conflict, the older block is freed. 74 // Old blocks are always checked with CheckBlockDesc() 75 // before being freed. At the end of the run, 76 // all remaining allocated blocks are freed. 77 // If use_new_arena is true, use a fresh arena, and then delete it. 78 // If call_malloc_hook is true and user_arena is true, 79 // allocations and deallocations are reported via the MallocHook 80 // interface. 81 static void Test(bool use_new_arena, bool call_malloc_hook, int n) { 82 typedef map<int, BlockDesc> AllocMap; 83 AllocMap allocated; 84 AllocMap::iterator it; 85 BlockDesc block_desc; 86 int rnd; 87 LowLevelAlloc::Arena *arena = 0; 88 if (use_new_arena) { 89 int32 flags = call_malloc_hook? LowLevelAlloc::kCallMallocHook : 0; 90 arena = LowLevelAlloc::NewArena(flags, LowLevelAlloc::DefaultArena()); 91 } 92 for (int i = 0; i != n; i++) { 93 if (i != 0 && i % 10000 == 0) { 94 printf("."); 95 fflush(stdout); 96 } 97 98 switch(rand() & 1) { // toss a coin 99 case 0: // coin came up heads: add a block 100 using_low_level_alloc = true; 101 block_desc.len = rand() & 0x3fff; 102 block_desc.ptr = 103 reinterpret_cast<char *>( 104 arena == 0 105 ? LowLevelAlloc::Alloc(block_desc.len) 106 : LowLevelAlloc::AllocWithArena(block_desc.len, arena)); 107 using_low_level_alloc = false; 108 RandomizeBlockDesc(&block_desc); 109 rnd = rand(); 110 it = allocated.find(rnd); 111 if (it != allocated.end()) { 112 CheckBlockDesc(it->second); 113 using_low_level_alloc = true; 114 LowLevelAlloc::Free(it->second.ptr); 115 using_low_level_alloc = false; 116 it->second = block_desc; 117 } else { 118 allocated[rnd] = block_desc; 119 } 120 break; 121 case 1: // coin came up tails: remove a block 122 it = allocated.begin(); 123 if (it != allocated.end()) { 124 CheckBlockDesc(it->second); 125 using_low_level_alloc = true; 126 LowLevelAlloc::Free(it->second.ptr); 127 using_low_level_alloc = false; 128 allocated.erase(it); 129 } 130 break; 131 } 132 } 133 // remove all remaniing blocks 134 while ((it = allocated.begin()) != allocated.end()) { 135 CheckBlockDesc(it->second); 136 using_low_level_alloc = true; 137 LowLevelAlloc::Free(it->second.ptr); 138 using_low_level_alloc = false; 139 allocated.erase(it); 140 } 141 if (use_new_arena) { 142 CHECK(LowLevelAlloc::DeleteArena(arena)); 143 } 144 } 145 146 // used for counting allocates and frees 147 static int32 allocates; 148 static int32 frees; 149 150 // called on each alloc if kCallMallocHook specified 151 static void AllocHook(const void *p, size_t size) { 152 if (using_low_level_alloc) { 153 allocates++; 154 } 155 } 156 157 // called on each free if kCallMallocHook specified 158 static void FreeHook(const void *p) { 159 if (using_low_level_alloc) { 160 frees++; 161 } 162 } 163 164 int main(int argc, char *argv[]) { 165 // This is needed by maybe_threads_unittest.sh, which parses argv[0] 166 // to figure out what directory low_level_alloc_unittest is in. 167 if (argc != 1) { 168 fprintf(stderr, "USAGE: %s\n", argv[0]); 169 return 1; 170 } 171 172 CHECK(MallocHook::AddNewHook(&AllocHook)); 173 CHECK(MallocHook::AddDeleteHook(&FreeHook)); 174 CHECK_EQ(allocates, 0); 175 CHECK_EQ(frees, 0); 176 Test(false, false, 50000); 177 CHECK_NE(allocates, 0); // default arena calls hooks 178 CHECK_NE(frees, 0); 179 for (int i = 0; i != 16; i++) { 180 bool call_hooks = ((i & 1) == 1); 181 allocates = 0; 182 frees = 0; 183 Test(true, call_hooks, 15000); 184 if (call_hooks) { 185 CHECK_GT(allocates, 5000); // arena calls hooks 186 CHECK_GT(frees, 5000); 187 } else { 188 CHECK_EQ(allocates, 0); // arena doesn't call hooks 189 CHECK_EQ(frees, 0); 190 } 191 } 192 printf("\nPASS\n"); 193 CHECK(MallocHook::RemoveNewHook(&AllocHook)); 194 CHECK(MallocHook::RemoveDeleteHook(&FreeHook)); 195 return 0; 196 } 197