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