Skip to content

Commit e725625

Browse files
authored
Merge pull request #51 from JohanMabille/refactoring
benchmark with manual unrolling
2 parents 7f27049 + 6e53131 commit e725625

2 files changed

Lines changed: 119 additions & 27 deletions

File tree

‎benchmark/main.cpp‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111

1212
void benchmark_operation()
1313
{
14-
std::size_t size = 10000;
14+
//std::size_t size = 9984;
15+
std::size_t size = 20000;
1516
xsimd::run_benchmark_2op(xsimd::add_fn(), std::cout, size, 1000);
1617
xsimd::run_benchmark_2op(xsimd::sub_fn(), std::cout, size, 1000);
1718
xsimd::run_benchmark_2op(xsimd::mul_fn(), std::cout, size, 1000);
@@ -20,7 +21,7 @@ void benchmark_operation()
2021

2122
void benchmark_exp_log()
2223
{
23-
std::size_t size = 10000;
24+
std::size_t size = 20000;
2425
xsimd::run_benchmark_1op(xsimd::exp_fn(), std::cout, size, 1000);
2526
xsimd::run_benchmark_1op(xsimd::exp2_fn(), std::cout, size, 100);
2627
xsimd::run_benchmark_1op(xsimd::expm1_fn(), std::cout, size, 1000);
@@ -32,7 +33,7 @@ void benchmark_exp_log()
3233

3334
void benchmark_trigo()
3435
{
35-
std::size_t size = 10000;
36+
std::size_t size = 20000;
3637
xsimd::run_benchmark_1op(xsimd::sin_fn(), std::cout, size, 1000);
3738
xsimd::run_benchmark_1op(xsimd::cos_fn(), std::cout, size, 1000);
3839
xsimd::run_benchmark_1op(xsimd::tan_fn(), std::cout, size, 1000);
@@ -43,7 +44,7 @@ void benchmark_trigo()
4344

4445
void benchmark_hyperbolic()
4546
{
46-
std::size_t size = 10000;
47+
std::size_t size = 20000;
4748
xsimd::run_benchmark_1op(xsimd::sinh_fn(), std::cout, size, 1000);
4849
xsimd::run_benchmark_1op(xsimd::cosh_fn(), std::cout, size, 1000);
4950
xsimd::run_benchmark_1op(xsimd::tanh_fn(), std::cout, size, 1000);
@@ -54,7 +55,7 @@ void benchmark_hyperbolic()
5455

5556
void benchmark_power()
5657
{
57-
std::size_t size = 10000;
58+
std::size_t size = 20000;
5859
xsimd::run_benchmark_2op(xsimd::pow_fn(), std::cout, size, 1000);
5960
xsimd::run_benchmark_1op(xsimd::sqrt_fn(), std::cout, size, 1000);
6061
xsimd::run_benchmark_1op(xsimd::cbrt_fn(), std::cout, size, 100);
@@ -63,7 +64,7 @@ void benchmark_power()
6364

6465
void benchmark_rounding()
6566
{
66-
std::size_t size = 10000;
67+
std::size_t size = 20000;
6768
xsimd::run_benchmark_1op(xsimd::ceil_fn(), std::cout, size, 1000);
6869
xsimd::run_benchmark_1op(xsimd::floor_fn(), std::cout, size, 1000);
6970
xsimd::run_benchmark_1op(xsimd::trunc_fn(), std::cout, size, 1000);

‎benchmark/xsimd_benchmark.hpp‎

Lines changed: 112 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ namespace xsimd
6363
};
6464

6565
template <class F, class V>
66-
inline duration_type benchmark_scalar(F f, V& lhs, V& res, std::size_t number)
66+
duration_type benchmark_scalar(F f, V& lhs, V& res, std::size_t number)
6767
{
6868
size_t s = lhs.size();
6969
duration_type t_res = duration_type::max();
@@ -82,7 +82,7 @@ namespace xsimd
8282
}
8383

8484
template <class F, class V>
85-
inline duration_type benchmark_scalar(F f, V& lhs, V& rhs, V& res, std::size_t number)
85+
duration_type benchmark_scalar(F f, V& lhs, V& rhs, V& res, std::size_t number)
8686
{
8787
size_t s = lhs.size();
8888
duration_type t_res = duration_type::max();
@@ -91,7 +91,7 @@ namespace xsimd
9191
auto start = std::chrono::steady_clock::now();
9292
for (size_t i = 0; i < s; ++i)
9393
{
94-
res[i] = f(lhs[i], rhs[i]);
94+
res[i] = f(lhs[i], rhs[i]);
9595
}
9696
auto end = std::chrono::steady_clock::now();
9797
auto tmp = end - start;
@@ -101,7 +101,7 @@ namespace xsimd
101101
}
102102

103103
template <class B, class F, class V>
104-
inline duration_type benchmark_simd(F f, V& lhs, V& res, std::size_t number)
104+
duration_type benchmark_simd(F f, V& lhs, V& res, std::size_t number)
105105
{
106106
std::size_t s = lhs.size();
107107
duration_type t_res = duration_type::max();
@@ -110,9 +110,9 @@ namespace xsimd
110110
auto start = std::chrono::steady_clock::now();
111111
for (std::size_t i = 0; i < s; i += B::size)
112112
{
113-
B blhs, bres;
113+
B blhs;
114114
blhs.load_aligned(&lhs[i]);
115-
bres = f(blhs);
115+
B bres = f(blhs);
116116
bres.store_aligned(&res[i]);
117117
}
118118
auto end = std::chrono::steady_clock::now();
@@ -123,7 +123,42 @@ namespace xsimd
123123
}
124124

125125
template <class B, class F, class V>
126-
inline duration_type benchmark_simd(F f, V& lhs, V& rhs, V& res, std::size_t number)
126+
duration_type benchmark_simd_unrolled(F f, V& lhs, V& res, std::size_t number)
127+
{
128+
std::size_t s = lhs.size();
129+
std::size_t inc = 4 * B::size;
130+
duration_type t_res = duration_type::max();
131+
for (std::size_t count = 0; count < number; ++count)
132+
{
133+
auto start = std::chrono::steady_clock::now();
134+
for (std::size_t i = 0; i < s; i += inc)
135+
{
136+
size_t j = i + B::size;
137+
size_t k = j + B::size;
138+
size_t l = k + B::size;
139+
B blhs, blhs2, blhs3, blhs4;
140+
blhs.load_aligned(&lhs[i]);
141+
blhs2.load_aligned(&lhs[j]);
142+
blhs3.load_aligned(&lhs[k]);
143+
blhs4.load_aligned(&lhs[l]);
144+
B bres = f(blhs);
145+
B bres2 = f(blhs2);
146+
B bres3 = f(blhs3);
147+
B bres4 = f(blhs4);
148+
bres.store_aligned(&res[i]);
149+
bres2.store_aligned(&res[j]);
150+
bres3.store_aligned(&res[k]);
151+
bres4.store_aligned(&res[l]);
152+
}
153+
auto end = std::chrono::steady_clock::now();
154+
auto tmp = end - start;
155+
t_res = tmp < t_res ? tmp : t_res;
156+
}
157+
return t_res;
158+
}
159+
160+
template <class B, class F, class V>
161+
duration_type benchmark_simd(F f, V& lhs, V& rhs, V& res, std::size_t number)
127162
{
128163
std::size_t s = lhs.size();
129164
duration_type t_res = duration_type::max();
@@ -132,11 +167,51 @@ namespace xsimd
132167
auto start = std::chrono::steady_clock::now();
133168
for (std::size_t i = 0; i < s; i += B::size)
134169
{
135-
B blhs, brhs, bres;
170+
B blhs, brhs;
171+
blhs.load_aligned(&lhs[i]);
172+
brhs.load_aligned(&rhs[i]);
173+
B bres = f(blhs, brhs);
174+
bres.store_aligned(&res[i]);
175+
}
176+
auto end = std::chrono::steady_clock::now();
177+
auto tmp = end - start;
178+
t_res = tmp < t_res ? tmp : t_res;
179+
}
180+
return t_res;
181+
}
182+
183+
template <class B, class F, class V>
184+
duration_type benchmark_simd_unrolled(F f, V& lhs, V& rhs, V& res, std::size_t number)
185+
{
186+
std::size_t s = lhs.size();
187+
std::size_t inc = 4 * B::size;
188+
duration_type t_res = duration_type::max();
189+
for (std::size_t count = 0; count < number; ++count)
190+
{
191+
auto start = std::chrono::steady_clock::now();
192+
for (std::size_t i = 0; i < s; i += inc)
193+
{
194+
size_t j = i + B::size;
195+
size_t k = j + B::size;
196+
size_t l = k + B::size;
197+
B blhs, brhs, blhs2, brhs2;
198+
B blhs3, brhs3, blhs4, brhs4;
136199
blhs.load_aligned(&lhs[i]);
200+
blhs2.load_aligned(&lhs[j]);
201+
blhs3.load_aligned(&lhs[k]);
202+
blhs4.load_aligned(&lhs[l]);
137203
brhs.load_aligned(&rhs[i]);
138-
bres = f(blhs, brhs);
204+
brhs2.load_aligned(&rhs[j]);
205+
brhs3.load_aligned(&rhs[k]);
206+
brhs4.load_aligned(&rhs[l]);
207+
B bres = f(blhs, brhs);
208+
B bres2 = f(blhs2, brhs2);
209+
B bres3 = f(blhs3, brhs3);
210+
B bres4 = f(blhs4, brhs4);
139211
bres.store_aligned(&res[i]);
212+
bres2.store_aligned(&res[j]);
213+
bres3.store_aligned(&res[k]);
214+
bres4.store_aligned(&res[l]);
140215
}
141216
auto end = std::chrono::steady_clock::now();
142217
auto tmp = end - start;
@@ -171,33 +246,41 @@ namespace xsimd
171246
duration_type t_float_scalar = benchmark_scalar(f, f_lhs, f_res, iter);
172247
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_SSE2_VERSION
173248
duration_type t_float_sse = benchmark_simd<batch<float, 4>>(f, f_lhs, f_res, iter);
249+
duration_type t_float_sse_u = benchmark_simd_unrolled<batch<float, 4>>(f, f_lhs, f_res, iter);
174250
#endif
175251
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_AVX_VERSION
176252
duration_type t_float_avx = benchmark_simd<batch<float, 8>>(f, f_lhs, f_res, iter);
253+
duration_type t_float_avx_u = benchmark_simd_unrolled<batch<float, 8>>(f, f_lhs, f_res, iter);
177254
#endif
178255
duration_type t_double_scalar = benchmark_scalar(f, d_lhs, d_res, iter);
179256
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_SSE2_VERSION
180257
duration_type t_double_sse = benchmark_simd<batch<double, 2>>(f, d_lhs, d_res, iter);
258+
duration_type t_double_sse_u = benchmark_simd_unrolled<batch<double, 2>>(f, d_lhs, d_res, iter);
181259
#endif
182260
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_AVX_VERSION
183261
duration_type t_double_avx = benchmark_simd<batch<double, 4>>(f, d_lhs, d_res, iter);
262+
duration_type t_double_avx_u = benchmark_simd_unrolled<batch<double, 4>>(f, d_lhs, d_res, iter);
184263
#endif
185264

186265
out << "=======================" << std::endl;
187266
out << f.name() << std::endl;
188-
out << "scalar float : " << t_float_scalar.count() << "ms" << std::endl;
267+
out << "scalar float : " << t_float_scalar.count() << "ms" << std::endl;
189268
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_SSE2_VERSION
190-
out << "sse float : " << t_float_sse.count() << "ms" << std::endl;
269+
out << "sse float : " << t_float_sse.count() << "ms" << std::endl;
270+
out << "sse float unr : " << t_float_sse_u.count() << "ms" << std::endl;
191271
#endif
192272
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_AVX_VERSION
193-
out << "avx float : " << t_float_avx.count() << "ms" << std::endl;
273+
out << "avx float : " << t_float_avx.count() << "ms" << std::endl;
274+
out << "avx float unr : " << t_float_avx_u.count() << "ms" << std::endl;
194275
#endif
195-
out << "scalar double: " << t_double_scalar.count() << "ms" << std::endl;
276+
out << "scalar double : " << t_double_scalar.count() << "ms" << std::endl;
196277
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_SSE2_VERSION
197-
out << "sse double : " << t_double_sse.count() << "ms" << std::endl;
278+
out << "sse double : " << t_double_sse.count() << "ms" << std::endl;
279+
out << "sse double unr: " << t_double_sse_u.count() << "ms" << std::endl;
198280
#endif
199281
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_AVX_VERSION
200-
out << "avx double : " << t_double_avx.count() << "ms" << std::endl;
282+
out << "avx double : " << t_double_avx.count() << "ms" << std::endl;
283+
out << "avx double unr: " << t_double_avx_u.count() << "ms" << std::endl;
201284
#endif
202285
out << "=======================" << std::endl;
203286
}
@@ -214,33 +297,41 @@ namespace xsimd
214297
duration_type t_float_scalar = benchmark_scalar(f, f_lhs, f_rhs, f_res, iter);
215298
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_SSE2_VERSION
216299
duration_type t_float_sse = benchmark_simd<batch<float, 4>>(f, f_lhs, f_rhs, f_res, iter);
300+
duration_type t_float_sse_u = benchmark_simd_unrolled<batch<float, 4>>(f, f_lhs, f_rhs, f_res, iter);
217301
#endif
218302
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_AVX_VERSION
219303
duration_type t_float_avx = benchmark_simd<batch<float, 8>>(f, f_lhs, f_rhs, f_res, iter);
304+
duration_type t_float_avx_u = benchmark_simd_unrolled<batch<float, 8>>(f, f_lhs, f_rhs, f_res, iter);
220305
#endif
221306
duration_type t_double_scalar = benchmark_scalar(f, d_lhs, d_rhs, d_res, iter);
222307
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_SSE2_VERSION
223308
duration_type t_double_sse = benchmark_simd<batch<double, 2>>(f, d_lhs, d_rhs, d_res, iter);
309+
duration_type t_double_sse_u = benchmark_simd_unrolled<batch<double, 2>>(f, d_lhs, d_rhs, d_res, iter);
224310
#endif
225311
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_AVX_VERSION
226312
duration_type t_double_avx = benchmark_simd<batch<double, 4>>(f, d_lhs, d_rhs, d_res, iter);
313+
duration_type t_double_avx_u = benchmark_simd_unrolled<batch<double, 4>>(f, d_lhs, d_rhs, d_res, iter);
227314
#endif
228315

229316
out << "=======================" << std::endl;
230317
out << f.name() << std::endl;
231-
out << "scalar float : " << t_float_scalar.count() << "ms" << std::endl;
318+
out << "scalar float : " << t_float_scalar.count() << "ms" << std::endl;
232319
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_SSE2_VERSION
233-
out << "sse float : " << t_float_sse.count() << "ms" << std::endl;
320+
out << "sse float : " << t_float_sse.count() << "ms" << std::endl;
321+
out << "sse float unr : " << t_float_sse_u.count() << "ms" << std::endl;
234322
#endif
235323
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_AVX_VERSION
236-
out << "avx float : " << t_float_avx.count() << "ms" << std::endl;
324+
out << "avx float : " << t_float_avx.count() << "ms" << std::endl;
325+
out << "avx float unr : " << t_float_avx_u.count() << "ms" << std::endl;
237326
#endif
238-
out << "scalar double: " << t_double_scalar.count() << "ms" << std::endl;
327+
out << "scalar double : " << t_double_scalar.count() << "ms" << std::endl;
239328
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_SSE2_VERSION
240-
out << "sse double : " << t_double_sse.count() << "ms" << std::endl;
329+
out << "sse double : " << t_double_sse.count() << "ms" << std::endl;
330+
out << "sse double unr: " << t_double_sse_u.count() << "ms" << std::endl;
241331
#endif
242332
#if XSIMD_X86_INSTR_SET >= XSIMD_X86_AVX_VERSION
243-
out << "avx double : " << t_double_avx.count() << "ms" << std::endl;
333+
out << "avx double : " << t_double_avx.count() << "ms" << std::endl;
334+
out << "avx double unr: " << t_double_avx_u.count() << "ms" << std::endl;
244335
#endif
245336
out << "=======================" << std::endl;
246337
}

0 commit comments

Comments
 (0)