2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 * Copyright 2014 Cloudius Systems
22 #include <seastar/core/memory.hh>
23 #include <seastar/core/timer.hh>
24 #include <seastar/testing/test_runner.hh>
32 #include <boost/program_options.hpp>
34 using namespace seastar
;
38 std::unique_ptr
<char[]> data
;
40 allocation(size_t n
, char poison
) : n(n
), data(new char[n
]), poison(poison
) {
41 std::fill_n(data
.get(), n
, poison
);
46 allocation(allocation
&& x
) noexcept
= default;
49 assert(std::find_if(data
.get(), data
.get() + n
, [this] (char c
) {
51 }) == data
.get() + n
);
54 allocation
& operator=(allocation
&& x
) {
57 data
= std::move(x
.data
);
65 #ifdef __cpp_aligned_new
68 struct alignas(N
) cpp17_allocation final
{
76 handle(const test17
* d
, void* p
) : d(d
), p(p
) {}
77 handle(const handle
&) = delete;
78 handle(handle
&& x
) noexcept
: d(std::exchange(x
.d
, nullptr)), p(std::exchange(x
.p
, nullptr)) {}
79 handle
& operator=(const handle
&) = delete;
80 handle
& operator=(handle
&& x
) noexcept
{
92 virtual handle
alloc() const = 0;
93 virtual void free(void* ptr
) const = 0;
97 struct test17_concrete
: test17
{
98 using value_type
= cpp17_allocation
<N
>;
99 static_assert(sizeof(value_type
) == N
, "language does not guarantee size >= align");
100 virtual handle
alloc() const override
{
101 auto ptr
= new value_type();
102 assert((reinterpret_cast<uintptr_t>(ptr
) & (N
- 1)) == 0);
103 return handle
{this, ptr
};
105 virtual void free(void* ptr
) const override
{
106 delete static_cast<value_type
*>(ptr
);
110 void test_cpp17_aligned_allocator() {
111 std::vector
<std::unique_ptr
<test17
>> tv
;
112 tv
.push_back(std::make_unique
<test17_concrete
<1>>());
113 tv
.push_back(std::make_unique
<test17_concrete
<2>>());
114 tv
.push_back(std::make_unique
<test17_concrete
<4>>());
115 tv
.push_back(std::make_unique
<test17_concrete
<8>>());
116 tv
.push_back(std::make_unique
<test17_concrete
<16>>());
117 tv
.push_back(std::make_unique
<test17_concrete
<64>>());
118 tv
.push_back(std::make_unique
<test17_concrete
<128>>());
119 tv
.push_back(std::make_unique
<test17_concrete
<2048>>());
120 tv
.push_back(std::make_unique
<test17_concrete
<4096>>());
121 tv
.push_back(std::make_unique
<test17_concrete
<4096*16>>());
122 tv
.push_back(std::make_unique
<test17_concrete
<4096*256>>());
124 std::default_random_engine
random_engine(testing::local_random_engine());
125 std::uniform_int_distribution
<> type_dist(0, 1);
126 std::uniform_int_distribution
<size_t> size_dist(0, tv
.size() - 1);
127 std::uniform_real_distribution
<> which_dist(0, 1);
129 std::vector
<test17::handle
> allocs
;
130 for (unsigned i
= 0; i
< 10000; ++i
) {
131 auto type
= type_dist(random_engine
);
134 size_t sz_idx
= size_dist(random_engine
);
135 allocs
.push_back(tv
[sz_idx
]->alloc());
139 if (!allocs
.empty()) {
140 size_t idx
= which_dist(random_engine
) * allocs
.size();
141 std::swap(allocs
[idx
], allocs
.back());
151 void test_cpp17_aligned_allocator() {
156 int main(int ac
, char** av
) {
157 namespace bpo
= boost::program_options
;
158 bpo::options_description
opts("Allowed options");
160 ("help", "produce this help message")
161 ("iterations", bpo::value
<unsigned>(), "run s specified number of iterations")
162 ("time", bpo::value
<float>()->default_value(5.0), "run for a specified amount of time, in seconds")
163 ("random-seed", boost::program_options::value
<unsigned>(), "Random number generator seed");
165 bpo::variables_map vm
;
166 bpo::store(bpo::parse_command_line(ac
, av
, opts
), vm
);
168 test_cpp17_aligned_allocator();
169 auto seed
= vm
.count("random-seed") ? vm
["random-seed"].as
<unsigned>() : std::random_device
{}();
170 std::default_random_engine
random_engine(seed
);
171 std::exponential_distribution
<> distr(0.2);
172 std::uniform_int_distribution
<> type(0, 1);
173 std::uniform_int_distribution
<char> poison(-128, 127);
174 std::uniform_real_distribution
<> which(0, 1);
175 std::vector
<allocation
> allocations
;
176 auto iteration
= [&] {
177 auto typ
= type(random_engine
);
180 size_t n
= std::min
<double>(std::exp(distr(random_engine
)), 1 << 25);
182 allocations
.emplace_back(n
, poison(random_engine
));
183 } catch (std::bad_alloc
&) {
189 if (allocations
.empty()) {
192 size_t i
= which(random_engine
) * allocations
.size();
193 allocations
[i
] = std::move(allocations
.back());
194 allocations
.pop_back();
199 if (vm
.count("help")) {
200 std::cout
<< opts
<< "\n";
203 std::cout
<< "random-seed=" << seed
<< "\n";
204 if (vm
.count("iterations")) {
205 auto iterations
= vm
["iterations"].as
<unsigned>();
206 for (unsigned i
= 0; i
< iterations
; ++i
) {
210 auto time
= vm
["time"].as
<float>();
211 using clock
= steady_clock_type
;
212 auto end
= clock::now() + std::chrono::duration_cast
<std::chrono::nanoseconds
>(std::chrono::seconds(1) * time
);
213 while (clock::now() < end
) {
214 for (unsigned i
= 0; i
< 1000; ++i
) {