low_level_alloc_unittest.cc 6.5 KB

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