]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* |
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. | |
6 | * | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
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 | |
16 | * under the License. | |
17 | */ | |
18 | /* | |
19 | * Copyright 2014 Cloudius Systems | |
20 | */ | |
21 | ||
22 | #include <seastar/core/memory.hh> | |
23 | #include <seastar/core/timer.hh> | |
9f95a23c | 24 | #include <seastar/testing/test_runner.hh> |
11fdf7f2 TL |
25 | #include <cmath> |
26 | #include <iostream> | |
27 | #include <iomanip> | |
28 | #include <algorithm> | |
29 | #include <cassert> | |
30 | #include <memory> | |
31 | #include <chrono> | |
32 | #include <boost/program_options.hpp> | |
33 | ||
34 | using namespace seastar; | |
35 | ||
11fdf7f2 TL |
36 | struct allocation { |
37 | size_t n; | |
38 | std::unique_ptr<char[]> data; | |
39 | char poison; | |
40 | allocation(size_t n, char poison) : n(n), data(new char[n]), poison(poison) { | |
41 | std::fill_n(data.get(), n, poison); | |
42 | } | |
43 | ~allocation() { | |
44 | verify(); | |
45 | } | |
46 | allocation(allocation&& x) noexcept = default; | |
47 | void verify() { | |
48 | if (data) { | |
49 | assert(std::find_if(data.get(), data.get() + n, [this] (char c) { | |
50 | return c != poison; | |
51 | }) == data.get() + n); | |
52 | } | |
53 | } | |
54 | allocation& operator=(allocation&& x) { | |
55 | verify(); | |
56 | if (this != &x) { | |
57 | data = std::move(x.data); | |
58 | n = x.n; | |
59 | poison = x.poison; | |
60 | } | |
61 | return *this; | |
62 | } | |
63 | }; | |
64 | ||
65 | #ifdef __cpp_aligned_new | |
66 | ||
67 | template <size_t N> | |
68 | struct alignas(N) cpp17_allocation final { | |
69 | char v; | |
70 | }; | |
71 | ||
72 | struct test17 { | |
73 | struct handle { | |
74 | const test17* d; | |
75 | void* p; | |
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 { | |
81 | std::swap(d, x.d); | |
82 | std::swap(p, x.p); | |
83 | return *this; | |
84 | } | |
85 | ~handle() { | |
86 | if (d) { | |
87 | d->free(p); | |
88 | } | |
89 | } | |
90 | }; | |
91 | virtual ~test17() {} | |
92 | virtual handle alloc() const = 0; | |
93 | virtual void free(void* ptr) const = 0; | |
94 | }; | |
95 | ||
96 | template <size_t N> | |
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}; | |
104 | } | |
105 | virtual void free(void* ptr) const override { | |
106 | delete static_cast<value_type*>(ptr); | |
107 | } | |
108 | }; | |
109 | ||
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>>()); | |
123 | ||
9f95a23c | 124 | std::default_random_engine random_engine(testing::local_random_engine()); |
11fdf7f2 TL |
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); | |
128 | ||
129 | std::vector<test17::handle> allocs; | |
130 | for (unsigned i = 0; i < 10000; ++i) { | |
131 | auto type = type_dist(random_engine); | |
132 | switch (type) { | |
133 | case 0: { | |
134 | size_t sz_idx = size_dist(random_engine); | |
135 | allocs.push_back(tv[sz_idx]->alloc()); | |
136 | break; | |
137 | } | |
138 | case 1: | |
139 | if (!allocs.empty()) { | |
140 | size_t idx = which_dist(random_engine) * allocs.size(); | |
141 | std::swap(allocs[idx], allocs.back()); | |
142 | allocs.pop_back(); | |
143 | } | |
144 | break; | |
145 | } | |
146 | } | |
147 | } | |
148 | ||
149 | #else | |
150 | ||
151 | void test_cpp17_aligned_allocator() { | |
152 | } | |
153 | ||
154 | #endif | |
155 | ||
156 | int main(int ac, char** av) { | |
157 | namespace bpo = boost::program_options; | |
158 | bpo::options_description opts("Allowed options"); | |
159 | opts.add_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") | |
9f95a23c | 163 | ("random-seed", boost::program_options::value<unsigned>(), "Random number generator seed"); |
11fdf7f2 TL |
164 | ; |
165 | bpo::variables_map vm; | |
166 | bpo::store(bpo::parse_command_line(ac, av, opts), vm); | |
167 | bpo::notify(vm); | |
11fdf7f2 | 168 | test_cpp17_aligned_allocator(); |
9f95a23c TL |
169 | auto seed = vm.count("random-seed") ? vm["random-seed"].as<unsigned>() : std::random_device{}(); |
170 | std::default_random_engine random_engine(seed); | |
11fdf7f2 TL |
171 | std::exponential_distribution<> distr(0.2); |
172 | std::uniform_int_distribution<> type(0, 1); | |
1e59de90 | 173 | std::uniform_int_distribution<int> poison(-128, 127); |
11fdf7f2 TL |
174 | std::uniform_real_distribution<> which(0, 1); |
175 | std::vector<allocation> allocations; | |
176 | auto iteration = [&] { | |
177 | auto typ = type(random_engine); | |
178 | switch (typ) { | |
179 | case 0: { | |
f67539c2 | 180 | size_t n = std::min<double>(std::exp(distr(random_engine)), 1 << 25); |
11fdf7f2 TL |
181 | try { |
182 | allocations.emplace_back(n, poison(random_engine)); | |
183 | } catch (std::bad_alloc&) { | |
184 | ||
185 | } | |
186 | break; | |
187 | } | |
188 | case 1: { | |
189 | if (allocations.empty()) { | |
190 | break; | |
191 | } | |
192 | size_t i = which(random_engine) * allocations.size(); | |
193 | allocations[i] = std::move(allocations.back()); | |
194 | allocations.pop_back(); | |
195 | break; | |
196 | } | |
197 | } | |
198 | }; | |
199 | if (vm.count("help")) { | |
200 | std::cout << opts << "\n"; | |
201 | return 1; | |
202 | } | |
9f95a23c | 203 | std::cout << "random-seed=" << seed << "\n"; |
11fdf7f2 TL |
204 | if (vm.count("iterations")) { |
205 | auto iterations = vm["iterations"].as<unsigned>(); | |
206 | for (unsigned i = 0; i < iterations; ++i) { | |
207 | iteration(); | |
208 | } | |
209 | } else { | |
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) { | |
215 | iteration(); | |
216 | } | |
217 | } | |
218 | } | |
219 | return 0; | |
220 | } |