From 72028de14d618dd8c4eb40bd4508933f63649b51 Mon Sep 17 00:00:00 2001 From: Markus Pilman Date: Fri, 17 Apr 2020 15:30:45 -0700 Subject: [PATCH] intermediate commit --- flow/CMakeLists.txt | 1 + flow/FBTrace.cpp | 144 ++++++++++++++++++++++++++++++++++++++++++++ flow/FBTrace.h | 13 +++- 3 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 flow/FBTrace.cpp diff --git a/flow/CMakeLists.txt b/flow/CMakeLists.txt index f50ee117e9..10c64d4992 100644 --- a/flow/CMakeLists.txt +++ b/flow/CMakeLists.txt @@ -21,6 +21,7 @@ set(FLOW_SRCS FaultInjection.cpp FaultInjection.h FBTrace.h + FBTrace.cpp FileTraceLogWriter.cpp FileTraceLogWriter.h Hash3.c diff --git a/flow/FBTrace.cpp b/flow/FBTrace.cpp new file mode 100644 index 0000000000..0a31dc68da --- /dev/null +++ b/flow/FBTrace.cpp @@ -0,0 +1,144 @@ +/* + * FBTrace.cpp + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2013-2020 Apple Inc. and the FoundationDB project 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 "flow/FBTrace.h" +#include "FastAlloc.h" +#include "Platform.h" +#include +#include +#include +#include +#include +#include +#include + +namespace { + +// A special allocator that quickly allocates small objects +// and deallocates them roughly in the same order +struct Chunk { + // we'll use 1MB chunks + static constexpr size_t size = ChunkAllocator::MAX_CHUNK_SIZE; + // mutable because it is thread safe + // atomic because we ship these into + // a thread pool + mutable std::atomic refCount = 1; + unsigned offset = 0; + + constexpr static size_t beginOffset() { + return sizeof(Chunk) % 8 == 0 ? sizeof(Chunk) : sizeof(Chunk) + (8 - (sizeof(Chunk) % 8)); + } + static Chunk* create() { + void* buffer = aligned_alloc(8, Chunk::size + Chunk::beginOffset()); + return new (buffer) Chunk{}; + } + + void delref() const { + if (refCount.fetch_sub(1) == 1) { + ::aligned_free(const_cast(this)); + } + } + void addref() { + refCount.fetch_and(1); + } + static Chunk& getChunk(void* ptr) { + auto addr = reinterpret_cast(ptr); + unsigned offset = *reinterpret_cast(addr - 4); + return *reinterpret_cast(addr - offset); + } + + uintptr_t begin() const { + return reinterpret_cast(this) + Chunk::beginOffset(); + } + uintptr_t end() const { + return begin() + offset; + } + + void* allocate(size_t sz) { + auto off = offset; + void* res = reinterpret_cast(end()); + addref(); + } +private: + // make sure nobody constructs a Chunk directly + Chunk() {} +}; + + + +struct ChunkDeleter { + void operator()(Chunk* ptr) const { ptr->delref(); } +}; + +struct ChunkAllocatorImpl { + std::unique_ptr currentChunk; + + ChunkAllocatorImpl() : currentChunk(new Chunk{}) {} + + void* allocate(size_t sz) { + if (sz > ChunkAllocator::MAX_CHUNK_SIZE) { + auto res = reinterpret_cast(aligned_alloc(8, sz)); + // I don't think this is necessary, but it help to debug because now this + // means that the 8 bytes before will be 0x00000000ffffffff + res[0] = 0; + res[1] = std::numeric_limits::max(); + return res + 2; + } + void* res = nullptr; + if ((res = currentChunk->allocate(sz)) == nullptr) { + currentChunk.reset(new Chunk{}); + } + return currentChunk->allocate(sz); + } + + void free(void* ptr) { + auto i = reinterpret_cast(ptr); + auto off = *(i - 1); + if (off == std::numeric_limits::max()) { + aligned_free(i - 2); + } else { + auto addr = reinterpret_cast(ptr); + reinterpret_cast(addr - off)->delref(); + } + } +}; + +ChunkAllocatorImpl chunkAllocator; + +} // namespace + +namespace ChunkAllocator { + +void* allocate(size_t sz) { + return chunkAllocator.allocate(sz); +} + +void free(void* ptr) { + return chunkAllocator.free(ptr); +} + +} // namespace ChunkAllocator + +void* FBTraceImpl::operator new(std::size_t sz) { + return ChunkAllocator::allocate(sz); +} +void FBTraceImpl::operator delete(void* ptr) { + Chunk::getChunk(ptr).delref(); +} diff --git a/flow/FBTrace.h b/flow/FBTrace.h index 3c76a108e0..64a4268642 100644 --- a/flow/FBTrace.h +++ b/flow/FBTrace.h @@ -3,7 +3,7 @@ * * This source file is part of the FoundationDB open source project * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors + * Copyright 2013-2020 Apple Inc. and the FoundationDB project authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,18 +22,27 @@ #include "flow/FastRef.h" #include "flow/ObjectSerializer.h" +#include #include +namespace ChunkAllocator { + constexpr size_t MAX_CHUNK_SIZE = 1 << 20; + void* allocate(size_t sz); + void free(void* ptr); +}; + class FBTraceImpl : public ReferenceCounted { protected: virtual void write(ObjectWriter& writer) = 0; public: virtual ~FBTraceImpl(); + static void* operator new(std::size_t sz); + static void operator delete(void* ptr); }; template class FDBTrace : public FBTraceImpl { - protected: +protected: void write(ObjectWriter& writer) override { writer.serialize(*static_cast(this)); }