- 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;
 | 
						|
}
 |