@@ -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