15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Copyright (c) 2006, Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modification, are permitted provided that the following conditions are 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * * Redistributions of source code must retain the above copyright 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * notice, this list of conditions and the following disclaimer. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * * Redistributions in binary form must reproduce the above 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in the documentation and/or other materials provided with the 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distribution. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * * Neither the name of Google Inc. nor the names of its 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * contributors may be used to endorse or promote products derived from 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this software without specific prior written permission. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A test for low_level_alloc.cc 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map> 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/low_level_alloc.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gperftools/malloc_hook.h> 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::map; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a block of memory obtained from the allocator 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct BlockDesc { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *ptr; // pointer to memory 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len; // number of bytes 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fill; // filled with data starting with this 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Check that the pattern placed in the block d 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// by RandomizeBlockDesc is still there. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void CheckBlockDesc(const BlockDesc &d) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i != d.len; i++) { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK((d.ptr[i] & 0xff) == ((d.fill + i) & 0xff)); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Fill the block "*d" with a pattern 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// starting with a random byte. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void RandomizeBlockDesc(BlockDesc *d) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) d->fill = rand() & 0xff; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i != d->len; i++) { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) d->ptr[i] = (d->fill + i) & 0xff; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use to indicate to the malloc hooks that 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this calls is from LowLevelAlloc. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool using_low_level_alloc = false; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// n times, toss a coin, and based on the outcome 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// either allocate a new block or deallocate an old block. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// New blocks are placed in a map with a random key 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and initialized with RandomizeBlockDesc(). 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If keys conflict, the older block is freed. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Old blocks are always checked with CheckBlockDesc() 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// before being freed. At the end of the run, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// all remaining allocated blocks are freed. 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If use_new_arena is true, use a fresh arena, and then delete it. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If call_malloc_hook is true and user_arena is true, 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// allocations and deallocations are reported via the MallocHook 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// interface. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void Test(bool use_new_arena, bool call_malloc_hook, int n) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef map<int, BlockDesc> AllocMap; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocMap allocated; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocMap::iterator it; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BlockDesc block_desc; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rnd; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LowLevelAlloc::Arena *arena = 0; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (use_new_arena) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 flags = call_malloc_hook? LowLevelAlloc::kCallMallocHook : 0; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arena = LowLevelAlloc::NewArena(flags, LowLevelAlloc::DefaultArena()); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i != n; i++) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i != 0 && i % 10000 == 0) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("."); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fflush(stdout); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch(rand() & 1) { // toss a coin 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 0: // coin came up heads: add a block 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) using_low_level_alloc = true; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block_desc.len = rand() & 0x3fff; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block_desc.ptr = 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<char *>( 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arena == 0 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ? LowLevelAlloc::Alloc(block_desc.len) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : LowLevelAlloc::AllocWithArena(block_desc.len, arena)); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) using_low_level_alloc = false; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RandomizeBlockDesc(&block_desc); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rnd = rand(); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it = allocated.find(rnd); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != allocated.end()) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckBlockDesc(it->second); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) using_low_level_alloc = true; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LowLevelAlloc::Free(it->second.ptr); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) using_low_level_alloc = false; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->second = block_desc; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allocated[rnd] = block_desc; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 1: // coin came up tails: remove a block 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it = allocated.begin(); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != allocated.end()) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckBlockDesc(it->second); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) using_low_level_alloc = true; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LowLevelAlloc::Free(it->second.ptr); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) using_low_level_alloc = false; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allocated.erase(it); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // remove all remaniing blocks 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((it = allocated.begin()) != allocated.end()) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckBlockDesc(it->second); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) using_low_level_alloc = true; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LowLevelAlloc::Free(it->second.ptr); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) using_low_level_alloc = false; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allocated.erase(it); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (use_new_arena) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(LowLevelAlloc::DeleteArena(arena)); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// used for counting allocates and frees 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int32 allocates; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int32 frees; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// called on each alloc if kCallMallocHook specified 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void AllocHook(const void *p, size_t size) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (using_low_level_alloc) { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allocates++; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// called on each free if kCallMallocHook specified 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void FreeHook(const void *p) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (using_low_level_alloc) { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frees++; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(int argc, char *argv[]) { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is needed by maybe_threads_unittest.sh, which parses argv[0] 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to figure out what directory low_level_alloc_unittest is in. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (argc != 1) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fprintf(stderr, "USAGE: %s\n", argv[0]); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(MallocHook::AddNewHook(&AllocHook)); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(MallocHook::AddDeleteHook(&FreeHook)); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(allocates, 0); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(frees, 0); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Test(false, false, 50000); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_NE(allocates, 0); // default arena calls hooks 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_NE(frees, 0); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i != 16; i++) { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool call_hooks = ((i & 1) == 1); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allocates = 0; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frees = 0; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Test(true, call_hooks, 15000); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (call_hooks) { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GT(allocates, 5000); // arena calls hooks 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GT(frees, 5000); 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(allocates, 0); // arena doesn't call hooks 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(frees, 0); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("\nPASS\n"); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(MallocHook::RemoveNewHook(&AllocHook)); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(MallocHook::RemoveDeleteHook(&FreeHook)); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 197