- c4b7a4e517c9404932c45f2f9f92eb7dc694e45d Internal change by Abseil Team <absl-team@google.com> - 76c78ed9385f65d881511645446e0bb8ababf6ec Add missing ABSL_PREDICT_FALSE to one of FixedArray::at()... by Abseil Team <absl-team@google.com> - 1204fb1c46f007dd9dfb7d9abf3e96c58835d193 Internal change. by Greg Falcon <gfalcon@google.com> - f1f47c98a026bc5e425ae83ff4a2eb391bbd3d9b Add internal-only functionality to examine the stack, to ... by Derek Mauro <dmauro@google.com> - 30d63097cd268d912f917526f6511005580465c4 fix typo by Abseil Team <absl-team@google.com> - 942d7efa6cf54cd248ca57dcaf3c245188b52a76 Remove unnecessary semicolons from comment examples. by Abseil Team <absl-team@google.com> - 7db0669cf23a06d934d3ed8c76aee4e4e23b7e04 Remove malloc_hook and malloc_extension from our internal... by Greg Falcon <gfalcon@google.com> - 0190f1063d101b1ded355019df2e1d325931f6c7 Make the maximum length of a string view equal difference... by Abseil Team <absl-team@google.com> - c8ae37cbce29449b02115a0ebd435ddc3d7ab062 Add namespace qualification. by Shaindel Schwartz <shaindel@google.com> - ff70afe2e6e3dd39f51ce9829e3e1f18231bf4d7 Fix internal/direct_mmap.h for non-linux builds. by Greg Falcon <gfalcon@google.com> GitOrigin-RevId: ed0ba496fe01eb8edfa86beade8a37768e7c12ef Change-Id: I7595ee3480d1d6724fd3797c15ba9d9be0d17e62
		
			
				
	
	
		
			157 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2017 The Abseil Authors.
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //      http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| #include "absl/base/internal/low_level_alloc.h"
 | |
| 
 | |
| #include <stdint.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <thread>  // NOLINT(build/c++11)
 | |
| #include <unordered_map>
 | |
| #include <utility>
 | |
| 
 | |
| namespace absl {
 | |
| namespace base_internal {
 | |
| namespace {
 | |
| 
 | |
| // This test doesn't use gtest since it needs to test that everything
 | |
| // works before main().
 | |
| #define TEST_ASSERT(x)                                           \
 | |
|   if (!(x)) {                                                    \
 | |
|     printf("TEST_ASSERT(%s) FAILED ON LINE %d\n", #x, __LINE__); \
 | |
|     abort();                                                     \
 | |
|   }
 | |
| 
 | |
| // 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++) {
 | |
|     TEST_ASSERT((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 std::unordered_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 std::unordered_map<int, BlockDesc> AllocMap;
 | |
|   AllocMap allocated;
 | |
|   AllocMap::iterator it;
 | |
|   BlockDesc block_desc;
 | |
|   int rnd;
 | |
|   LowLevelAlloc::Arena *arena = 0;
 | |
|   if (use_new_arena) {
 | |
|     int32_t flags = call_malloc_hook ? LowLevelAlloc::kCallMallocHook : 0;
 | |
|     arena = LowLevelAlloc::NewArena(flags);
 | |
|   }
 | |
|   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 remaining 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) {
 | |
|     TEST_ASSERT(LowLevelAlloc::DeleteArena(arena));
 | |
|   }
 | |
| }
 | |
| // LowLevelAlloc is designed to be safe to call before main().
 | |
| static struct BeforeMain {
 | |
|   BeforeMain() {
 | |
|     Test(false, false, 50000);
 | |
|     Test(true, false, 50000);
 | |
|     Test(true, true, 50000);
 | |
|   }
 | |
| } before_main;
 | |
| 
 | |
| }  // namespace
 | |
| }  // namespace base_internal
 | |
| }  // namespace absl
 | |
| 
 | |
| int main(int argc, char *argv[]) {
 | |
|   // The actual test runs in the global constructor of `before_main`.
 | |
|   printf("PASS\n");
 | |
|   return 0;
 | |
| }
 |