From 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 20:24:20 +0200 Subject: Adding upstream version 14.2.21. Signed-off-by: Daniel Baumann --- src/seastar/tests/unit/allocator_test.cc | 235 +++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 src/seastar/tests/unit/allocator_test.cc (limited to 'src/seastar/tests/unit/allocator_test.cc') diff --git a/src/seastar/tests/unit/allocator_test.cc b/src/seastar/tests/unit/allocator_test.cc new file mode 100644 index 00000000..c0d93210 --- /dev/null +++ b/src/seastar/tests/unit/allocator_test.cc @@ -0,0 +1,235 @@ +/* + * This file is open source software, licensed to you under the terms + * of the Apache License, Version 2.0 (the "License"). See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. 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. + */ +/* + * Copyright 2014 Cloudius Systems + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace seastar; + +template +void test_aligned_allocator() { +#ifdef __cpp_aligned_new + using aptr = std::unique_ptr; + std::vector v; + for (unsigned i = 0; i < 1000; ++i) { + aptr p(new (std::align_val_t(64)) char[N]); + assert(reinterpret_cast(p.get()) % 64 == 0); + v.push_back(std::move(p)); + } +#endif +} + +struct allocation { + size_t n; + std::unique_ptr data; + char poison; + allocation(size_t n, char poison) : n(n), data(new char[n]), poison(poison) { + std::fill_n(data.get(), n, poison); + } + ~allocation() { + verify(); + } + allocation(allocation&& x) noexcept = default; + void verify() { + if (data) { + assert(std::find_if(data.get(), data.get() + n, [this] (char c) { + return c != poison; + }) == data.get() + n); + } + } + allocation& operator=(allocation&& x) { + verify(); + if (this != &x) { + data = std::move(x.data); + n = x.n; + poison = x.poison; + } + return *this; + } +}; + +#ifdef __cpp_aligned_new + +template +struct alignas(N) cpp17_allocation final { + char v; +}; + +struct test17 { + struct handle { + const test17* d; + void* p; + handle(const test17* d, void* p) : d(d), p(p) {} + handle(const handle&) = delete; + handle(handle&& x) noexcept : d(std::exchange(x.d, nullptr)), p(std::exchange(x.p, nullptr)) {} + handle& operator=(const handle&) = delete; + handle& operator=(handle&& x) noexcept { + std::swap(d, x.d); + std::swap(p, x.p); + return *this; + } + ~handle() { + if (d) { + d->free(p); + } + } + }; + virtual ~test17() {} + virtual handle alloc() const = 0; + virtual void free(void* ptr) const = 0; +}; + +template +struct test17_concrete : test17 { + using value_type = cpp17_allocation; + static_assert(sizeof(value_type) == N, "language does not guarantee size >= align"); + virtual handle alloc() const override { + auto ptr = new value_type(); + assert((reinterpret_cast(ptr) & (N - 1)) == 0); + return handle{this, ptr}; + } + virtual void free(void* ptr) const override { + delete static_cast(ptr); + } +}; + +void test_cpp17_aligned_allocator() { + std::vector> tv; + tv.push_back(std::make_unique>()); + tv.push_back(std::make_unique>()); + tv.push_back(std::make_unique>()); + tv.push_back(std::make_unique>()); + tv.push_back(std::make_unique>()); + tv.push_back(std::make_unique>()); + tv.push_back(std::make_unique>()); + tv.push_back(std::make_unique>()); + tv.push_back(std::make_unique>()); + tv.push_back(std::make_unique>()); + tv.push_back(std::make_unique>()); + + std::default_random_engine random_engine; + std::uniform_int_distribution<> type_dist(0, 1); + std::uniform_int_distribution size_dist(0, tv.size() - 1); + std::uniform_real_distribution<> which_dist(0, 1); + + std::vector allocs; + for (unsigned i = 0; i < 10000; ++i) { + auto type = type_dist(random_engine); + switch (type) { + case 0: { + size_t sz_idx = size_dist(random_engine); + allocs.push_back(tv[sz_idx]->alloc()); + break; + } + case 1: + if (!allocs.empty()) { + size_t idx = which_dist(random_engine) * allocs.size(); + std::swap(allocs[idx], allocs.back()); + allocs.pop_back(); + } + break; + } + } +} + +#else + +void test_cpp17_aligned_allocator() { +} + +#endif + +int main(int ac, char** av) { + namespace bpo = boost::program_options; + bpo::options_description opts("Allowed options"); + opts.add_options() + ("help", "produce this help message") + ("iterations", bpo::value(), "run s specified number of iterations") + ("time", bpo::value()->default_value(5.0), "run for a specified amount of time, in seconds") + ; + bpo::variables_map vm; + bpo::store(bpo::parse_command_line(ac, av, opts), vm); + bpo::notify(vm); + test_aligned_allocator<1>(); + test_aligned_allocator<4>(); + test_aligned_allocator<80>(); + test_cpp17_aligned_allocator(); + std::default_random_engine random_engine; + std::exponential_distribution<> distr(0.2); + std::uniform_int_distribution<> type(0, 1); + std::uniform_int_distribution poison(-128, 127); + std::uniform_real_distribution<> which(0, 1); + std::vector allocations; + auto iteration = [&] { + auto typ = type(random_engine); + switch (typ) { + case 0: { + auto n = std::min(std::exp(distr(random_engine)), 1 << 25); + try { + allocations.emplace_back(n, poison(random_engine)); + } catch (std::bad_alloc&) { + + } + break; + } + case 1: { + if (allocations.empty()) { + break; + } + size_t i = which(random_engine) * allocations.size(); + allocations[i] = std::move(allocations.back()); + allocations.pop_back(); + break; + } + } + }; + if (vm.count("help")) { + std::cout << opts << "\n"; + return 1; + } + if (vm.count("iterations")) { + auto iterations = vm["iterations"].as(); + for (unsigned i = 0; i < iterations; ++i) { + iteration(); + } + } else { + auto time = vm["time"].as(); + using clock = steady_clock_type; + auto end = clock::now() + std::chrono::duration_cast(std::chrono::seconds(1) * time); + while (clock::now() < end) { + for (unsigned i = 0; i < 1000; ++i) { + iteration(); + } + } + } + return 0; +} + + -- cgit v1.2.3