@@ -304,39 +304,13 @@ namespace xt
304304 xt_simd::simd_type<value_type>>;
305305 static constexpr bool needs_cast = has_assign_conversion<e2_value_type, e1_value_type>::value;
306306
307- // Holds the per-thread state (steppers and outer index) required
308- // to assign a sequence of consecutive outer iterations.
309- class cursor
310- {
311- public:
312-
313- explicit cursor (const strided_loop_assigner& assigner);
314-
315- // Assigns the inner loop corresponding to the outer iteration ox,
316- // and moves to the next outer iteration. The first call positions
317- // the steppers on ox, subsequent calls must be made with ox + 1.
318- void assign_row (size_type ox);
319-
320- private:
321-
322- void step_to_index ();
323-
324- const strided_loop_assigner* p_assigner;
325- lhs_stepper m_lhs;
326- rhs_stepper m_rhs;
327- index_type m_index;
328- bool m_positioned;
329- };
330-
331307 strided_loop_assigner (E1 & e1 , const E2 & e2 );
332308
333309 bool can_do_strided_assign () const noexcept ;
334310 size_type inner_loop_size () const noexcept ;
335311 size_type outer_loop_size () const noexcept ;
336312
337- cursor make_cursor () const ;
338-
339- // Assigns the outer iterations [begin, end)
313+ // Assigns the outer iterations [begin, end).
340314 void run (size_type begin, size_type end) const ;
341315
342316 private:
@@ -583,13 +557,17 @@ namespace xt
583557 size_type outer_loop_size = helper.outer_loop_size ();
584558 if (outer_loop_size >= XTENSOR_OPENMP_TRESHOLD / helper.inner_loop_size ())
585559 {
586- // Each thread gets its own copy of the cursor, which positions itself
587- // on the first outer iteration of the chunk assigned to the thread.
588- auto cursor = helper.make_cursor ();
589- #pragma omp parallel for schedule(static) firstprivate(cursor)
590- for (std::ptrdiff_t ox = 0 ; ox < static_cast <std::ptrdiff_t >(outer_loop_size); ++ox)
560+ // Each thread assigns a contiguous chunk of outer iterations,
561+ // as schedule(static) would do
562+ #pragma omp parallel default(none) shared(helper, outer_loop_size)
591563 {
592- cursor.assign_row (static_cast <size_type>(ox));
564+ size_type nb_threads = static_cast <size_type>(omp_get_num_threads ());
565+ size_type thread_id = static_cast <size_type>(omp_get_thread_num ());
566+ size_type chunk = outer_loop_size / nb_threads;
567+ size_type rest = outer_loop_size % nb_threads;
568+ size_type begin = thread_id * chunk + std::min (thread_id, rest);
569+ size_type end = begin + chunk + (thread_id < rest ? 1u : 0u );
570+ helper.run (begin, end);
593571 }
594572 }
595573 else
@@ -1070,19 +1048,65 @@ namespace xt
10701048 return m_loop_sizes.outer_loop_size ;
10711049 }
10721050
1073- template <class E1 , class E2 >
1074- inline auto strided_loop_assigner<E1 , E2 >::make_cursor() const -> cursor
1075- {
1076- return cursor (*this );
1077- }
1078-
10791051 template <class E1 , class E2 >
10801052 inline void strided_loop_assigner<E1 , E2 >::run(size_type begin, size_type end) const
10811053 {
1082- cursor c (*this );
1054+ if (begin >= end)
1055+ {
1056+ return ;
1057+ }
1058+
1059+ const size_type step_dim = m_step_dim;
1060+ const size_type simd_size = m_simd_size;
1061+ const size_type simd_rest = m_simd_rest;
1062+
1063+ lhs_stepper lhs = m_e1.stepper_begin (m_e1.shape ());
1064+ rhs_stepper rhs = m_e2.stepper_begin (m_e1.shape ());
1065+ index_type index = xtl::make_sequence<index_type>(m_max_shape.size (), size_type (0 ));
1066+
1067+ if (begin != size_type (0 ))
1068+ {
1069+ nth_idx (begin, index);
1070+ for (size_type i = 0 ; i < index.size (); ++i)
1071+ {
1072+ lhs.step (i + step_dim, index[i]);
1073+ rhs.step (i + step_dim, index[i]);
1074+ }
1075+ }
1076+
10831077 for (size_type ox = begin; ox < end; ++ox)
10841078 {
1085- c.assign_row (ox);
1079+ for (size_type i = 0 ; i < simd_size; ++i)
1080+ {
1081+ lhs.store_simd (rhs.template step_simd <value_type>());
1082+ }
1083+ for (size_type i = 0 ; i < simd_rest; ++i)
1084+ {
1085+ *lhs = conditional_cast<needs_cast, e1_value_type>(*rhs);
1086+ lhs.step_leading ();
1087+ rhs.step_leading ();
1088+ }
1089+
1090+ next_idx (index);
1091+
1092+ // need to step E1 as well if not contiguous assign (e.g. view)
1093+ rhs.to_begin ();
1094+ if (!E1 ::contiguous_layout)
1095+ {
1096+ lhs.to_begin ();
1097+ for (size_type i = 0 ; i < index.size (); ++i)
1098+ {
1099+ lhs.step (i + step_dim, index[i]);
1100+ rhs.step (i + step_dim, index[i]);
1101+ }
1102+ }
1103+ else
1104+ {
1105+ for (size_type i = 0 ; i < index.size (); ++i)
1106+ {
1107+ rhs.step (i + step_dim, index[i]);
1108+ }
1109+ }
10861110 }
10871111 }
10881112
@@ -1111,70 +1135,4 @@ namespace xt
11111135 strided_assign_detail::idx_tools<layout_type::column_major>::next_idx (index, m_max_shape);
11121136 }
11131137 }
1114-
1115- template <class E1 , class E2 >
1116- inline strided_loop_assigner<E1 , E2 >::cursor::cursor(const strided_loop_assigner& assigner)
1117- : p_assigner(&assigner)
1118- , m_lhs(assigner.m_e1.stepper_begin(assigner.m_e1.shape()))
1119- , m_rhs(assigner.m_e2.stepper_begin(assigner.m_e1.shape()))
1120- , m_index(xtl::make_sequence<index_type>(assigner.m_max_shape.size(), size_type(0 )))
1121- , m_positioned(false )
1122- {
1123- }
1124-
1125- template <class E1 , class E2 >
1126- inline void strided_loop_assigner<E1 , E2 >::cursor::assign_row(size_type ox)
1127- {
1128- const strided_loop_assigner& a = *p_assigner;
1129-
1130- if (!m_positioned)
1131- {
1132- if (ox != size_type (0 ))
1133- {
1134- a.nth_idx (ox, m_index);
1135- step_to_index ();
1136- }
1137- m_positioned = true ;
1138- }
1139-
1140- for (size_type i = 0 ; i < a.m_simd_size ; ++i)
1141- {
1142- m_lhs.store_simd (m_rhs.template step_simd <value_type>());
1143- }
1144- for (size_type i = 0 ; i < a.m_simd_rest ; ++i)
1145- {
1146- *m_lhs = conditional_cast<needs_cast, e1_value_type>(*m_rhs);
1147- m_lhs.step_leading ();
1148- m_rhs.step_leading ();
1149- }
1150-
1151- a.next_idx (m_index);
1152-
1153- // need to step E1 as well if not contiguous assign (e.g. view)
1154- if (!E1 ::contiguous_layout)
1155- {
1156- m_lhs.to_begin ();
1157- m_rhs.to_begin ();
1158- step_to_index ();
1159- }
1160- else
1161- {
1162- m_rhs.to_begin ();
1163- for (size_type i = 0 ; i < m_index.size (); ++i)
1164- {
1165- m_rhs.step (i + a.m_step_dim , m_index[i]);
1166- }
1167- }
1168- }
1169-
1170- template <class E1 , class E2 >
1171- inline void strided_loop_assigner<E1 , E2 >::cursor::step_to_index()
1172- {
1173- size_type step_dim = p_assigner->m_step_dim ;
1174- for (size_type i = 0 ; i < m_index.size (); ++i)
1175- {
1176- m_lhs.step (i + step_dim, m_index[i]);
1177- m_rhs.step (i + step_dim, m_index[i]);
1178- }
1179- }
11801138}
0 commit comments