298 m_env = SYCLEnv::instance();
301 m_max_num_groups = m_env->maxNumGroups() ;
302 m_max_work_group_size = m_env->maxWorkGroupSize() ;
303 m_total_threads = m_env->maxNumThreads() ;
307 virtual ~KernelInternal() {}
309 void setDotAlgo(
int dot_algo)
311 m_dot_algo = dot_algo;
314 template <
typename T>
315 void assign(T
const a,
318 m_env->internal()->queue().submit(
319 [&](sycl::handler& cgh)
321 auto acc = y.template get_access<sycl::access::mode::discard_write>(cgh);
343 template <
typename T,
typename Lambda>
344 void apply(Lambda
const& lambda,
347 sycl::range<1> work_items{ m_total_threads };
350 m_env->internal()->queue().submit( [&](sycl::handler& cgh)
352 auto access_y = y.template get_access<sycl::access::mode::read_write>(cgh);
353 auto y_length = y.size() ;
354 cgh.parallel_for<
class vector_apply>(sycl::range<1>{m_total_threads}, [=] (sycl::item<1> itemId)
356 auto id = itemId.get_id(0);
357 for (
auto i =
id; i < y_length; i += itemId.get_range()[0])
358 access_y[i] = lambda(i);
366 template <
typename T>
370 sycl::range<1> work_items{ m_total_threads };
373 m_env->internal()->queue().submit([&](sycl::handler& cgh)
375 auto access_y = y.template get_access<sycl::access::mode::read_write>(cgh);
376 auto y_length = y.size() ;
377 cgh.parallel_for<
class vector_scal>(sycl::range<1>{m_total_threads}, [=] (sycl::item<1> itemId)
379 auto id = itemId.get_id(0);
380 for (
auto i =
id; i < y_length; i += itemId.get_range()[0])
381 access_y[i] = a*access_y[i];
388 template <
typename T>
393 sycl::range<1> work_items{ m_total_threads };
396 m_env->internal()->queue().submit([&](sycl::handler& cgh)
398 auto access_x = x.template get_access<sycl::access::mode::read>(cgh);
399 auto access_y = y.template get_access<sycl::access::mode::read_write>(cgh);
400 auto y_length = y.size() ;
401 cgh.parallel_for<
class vector_axpy>(sycl::range<1>{m_total_threads}, [=] (sycl::item<1> itemId)
403 auto id = itemId.get_id(0);
404 for (
auto i =
id; i < y_length; i += itemId.get_range()[0])
405 access_y[i] += a * access_x[i];
412 template <
typename T>
416 using VecT = sycl::vec<T, 2>;
418 auto& queue = m_env->internal()->queue();
419 const size_t n = y.size();
420 const size_t n2 = n / 2;
421 const size_t tail = n % 2;
423 static constexpr size_t WG_SIZE = 256;
424 const size_t blocks = std::max((n2 + WG_SIZE - 1) / WG_SIZE,
425 m_max_num_groups * 4UL);
426 const size_t total = blocks * WG_SIZE;
431 sycl::buffer<VecT> y2{ y.template reinterpret<VecT>(sycl::range<1>{n2}) };
433 queue.submit([&](sycl::handler& cgh) {
434 auto ay = y2.template get_access<sycl::access::mode::read_write>(cgh);
436 cgh.parallel_for<
class vector_xcal_vec>(
437 sycl::nd_range<1>{ {total}, {WG_SIZE} },
438 [=](sycl::nd_item<1> item) {
439 const size_t stride = item.get_global_range()[0];
440 for (
size_t i = item.get_global_id(0); i < n2; i += stride) {
442 ay[i] = VecT{a, a} * ay[i];
449 sycl::buffer<T> yt{ y.template reinterpret<T>(sycl::range<1>{n}) };
450 queue.submit([&](sycl::handler& cgh) {
451 auto ay = yt.template get_access<sycl::access::mode::read_write>(cgh);
452 cgh.single_task([=]{ ay[n-1] = a * ay[n-1]; });
458 template <
typename T>
463 using VecT = sycl::vec<T, 2>;
465 auto& queue = m_env->internal()->queue();
466 const size_t n = y.size();
467 const size_t n2 = n / 2;
468 const size_t tail = n % 2;
470 static constexpr size_t WG_SIZE = 256;
471 const size_t blocks = std::max((n2 + WG_SIZE - 1) / WG_SIZE,
472 m_max_num_groups * 4UL);
473 const size_t total = blocks * WG_SIZE;
478 sycl::buffer<VecT> x2{ x.template reinterpret<VecT>(sycl::range<1>{n2}) };
479 sycl::buffer<VecT> y2{ y.template reinterpret<VecT>(sycl::range<1>{n2}) };
481 queue.submit([&](sycl::handler& cgh) {
482 auto ax = x2.template get_access<sycl::access::mode::read>(cgh);
483 auto ay = y2.template get_access<sycl::access::mode::read_write>(cgh);
485 cgh.parallel_for<
class vector_axpy_vec>(
486 sycl::nd_range<1>{ {total}, {WG_SIZE} },
487 [=](sycl::nd_item<1> item) {
488 const size_t stride = item.get_global_range()[0];
489 for (
size_t i = item.get_global_id(0); i < n2; i += stride) {
491 ay[i] = ay[i] + VecT{a, a} * ax[i];
498 sycl::buffer<T> xt{ x.template reinterpret<T>(sycl::range<1>{n}) };
499 sycl::buffer<T> yt{ y.template reinterpret<T>(sycl::range<1>{n}) };
500 queue.submit([&](sycl::handler& cgh) {
501 auto ax = xt.template get_access<sycl::access::mode::read>(cgh);
502 auto ay = yt.template get_access<sycl::access::mode::read_write>(cgh);
503 cgh.single_task([=]{ ay[n-1] += a * ax[n-1]; });
508 template <
typename T>
515 sycl::range<1> work_items{ m_total_threads };
518 m_env->internal()->queue().submit([&](sycl::handler& cgh)
520 auto access_x = x.template get_access<sycl::access::mode::read>(cgh);
521 auto access_y = y.template get_access<sycl::access::mode::read_write>(cgh);
522 auto x_length = x.size()/stride_x ;
523 cgh.parallel_for<
class vector_axpy>(sycl::range<1>{m_total_threads}, [=] (sycl::item<1> itemId)
525 auto id = itemId.get_id(0);
526 for (
auto i =
id; i < x_length; i += itemId.get_range()[0])
527 access_y[i*stride_y] += a * access_x[i*stride_x];
533 template <
typename T>
534 void pointwiseMult(sycl::buffer<T>& x,
539 sycl::range<1> work_items{ m_total_threads };
542 m_env->internal()->queue().submit([&](sycl::handler& cgh)
544 auto access_x = x.template get_access<sycl::access::mode::read>(cgh);
545 auto access_y = y.template get_access<sycl::access::mode::read>(cgh);
546 auto access_z = z.template get_access<sycl::access::mode::read_write>(cgh);
547 auto y_length = y.size() ;
548 cgh.parallel_for<
class vector_pointwizemult>(sycl::range<1>{m_total_threads}, [=] (sycl::item<1> itemId)
550 auto id = itemId.get_id(0);
551 for (
auto i =
id; i < y_length; i += itemId.get_range()[0])
552 access_z[i] = access_x[i] * access_y[i];
558 using VecT = sycl::vec<T, 2>;
560 auto& queue = m_env->internal()->queue();
561 const size_t n = y.size();
562 const size_t n2 = n / 2;
563 const size_t tail = n % 2;
565 static constexpr size_t WG_SIZE = 256;
566 const size_t blocks = std::max((n2 + WG_SIZE - 1) / WG_SIZE,
567 m_max_num_groups * 4UL);
568 const size_t total = blocks * WG_SIZE;
573 sycl::buffer<VecT> x2{ x.template reinterpret<VecT>(sycl::range<1>{n2}) };
574 sycl::buffer<VecT> y2{ y.template reinterpret<VecT>(sycl::range<1>{n2}) };
575 sycl::buffer<VecT> z2{ z.template reinterpret<VecT>(sycl::range<1>{n2}) };
577 queue.submit([&](sycl::handler& cgh) {
578 auto ax = x2.template get_access<sycl::access::mode::read>(cgh);
579 auto ay = y2.template get_access<sycl::access::mode::read>(cgh);
580 auto az = z2.template get_access<sycl::access::mode::read_write>(cgh);
582 cgh.parallel_for<
class vector_pointwizemult>(
583 sycl::nd_range<1>{ {total}, {WG_SIZE} },
584 [=](sycl::nd_item<1> item) {
585 const size_t stride = item.get_global_range()[0];
586 for (
size_t i = item.get_global_id(0); i < n2; i += stride) {
588 az[i] = ax[i] * ay[i];
595 sycl::buffer<T> xt{ x.template reinterpret<T>(sycl::range<1>{n}) };
596 sycl::buffer<T> yt{ y.template reinterpret<T>(sycl::range<1>{n}) };
597 sycl::buffer<T> zt{ z.template reinterpret<T>(sycl::range<1>{n}) };
598 queue.submit([&](sycl::handler& cgh) {
599 auto ax = xt.template get_access<sycl::access::mode::read>(cgh);
600 auto ay = yt.template get_access<sycl::access::mode::read>(cgh);
601 auto az = zt.template get_access<sycl::access::mode::read_write>(cgh);
602 cgh.single_task([=]{ az[n-1] = ax[n-1] * ay[n-1]; });
606#ifdef PRINT_DEBUG_INFO
608 sycl::host_accessor<T, 1, sycl::access::mode::read> x_acc(x);
609 sycl::host_accessor<T, 1, sycl::access::mode::read> y_acc(y);
610 sycl::host_accessor<T, 1, sycl::access::mode::read> z_acc(z);
611 for(
int il=0;il<x.size();++il)
613 std::cout<<
"X Y Z ["<<il<<
"] : "<<x_acc[il]<<
"*"<<y_acc[il]<<
"="<<z_acc[il]<<std::endl ;
619 template <
typename T>
620 void copy(sycl::buffer<T>& x,
626 m_env->internal()->queue().submit(
627 [&](sycl::handler& cgh)
629 auto access_x = x.template get_access<sycl::access::mode::read>(cgh);
630 auto access_y = y.template get_access<sycl::access::mode::discard_write>(cgh);
631 cgh.copy(access_x,access_y) ;
646 template <
typename T>
647 void copy(sycl::buffer<T>& x,
652 sycl::range<1> work_items{ m_total_threads };
655 m_env->internal()->queue().submit( [&](sycl::handler& cgh)
657 auto access_x = x.template get_access<sycl::access::mode::read>(cgh);
658 auto access_y = y.template get_access<sycl::access::mode::read_write>(cgh);
659 auto x_length = x.size()/stride_x ;
660 cgh.parallel_for<
class vector_copy>(sycl::range<1>{m_total_threads}, [=] (sycl::item<1> itemId)
662 auto id = itemId.get_id(0);
663 for (
auto i =
id; i < x_length; i += itemId.get_range()[0])
664 access_y[i*stride_y] = access_x[i*stride_x];
671 template <
typename T>
677 template <
typename index_t>
678 inline index_t round_up(
const index_t x,
const index_t y)
680 return ((x + y - 1) / y) * y;
683 template <
typename T>
686 template <
typename T>
687 T reduce_sum(sycl::buffer<T>& x,
691 auto& w = getWorkBuffer<T>(x.size());
694 m_env->internal()->queue().submit( [&](sycl::handler& cgh)
696 auto access_x = x.template get_access<sycl::access::mode::read>(cgh);
697 auto access_y = y.template get_access<sycl::access::mode::read>(cgh);
699 auto access_w = sycl::accessor { w, cgh, sycl::write_only, sycl::property::no_init{}};
701 auto y_length = y.size() ;
702 cgh.parallel_for<
class vector_dot>(sycl::range<1>{m_total_threads}, [=] (sycl::item<1> itemId)
704 auto id = itemId.get_id(0);
705 for (
auto i =
id; i < y_length; i += itemId.get_range()[0])
706 access_w[i] = access_x[i]*access_y[i];
711 std::size_t local = m_max_work_group_size;
712 std::size_t length = x.size();
719 auto round_length = round_up(length, local);
721 auto f = [length, round_length, local, &w](sycl::handler& h)
mutable
723 sycl::nd_range<1> range{sycl::range<1>{round_length},
724 sycl::range<1>{local}};
725 auto access_w = w.template get_access<sycl::access::mode::read_write>(h);
729 sycl::local_accessor<T> scratch{sycl::range<1>(local), h};
733 h.parallel_for<
class sycl_reduction_sum_T>(range,
734 [access_w, scratch, local, length](sycl::nd_item<1> id)
736 std::size_t globalid =
id.get_global_id(0);
737 std::size_t localid =
id.get_local_id(0);
744 scratch[localid] = (globalid < length)? access_w[globalid] : 0. ;
745 id.barrier(sycl::access::fence_space::local_space);
749 if (globalid < length)
752 std::size_t min = local ;
753 for (std::size_t offset = min / 2; offset > 0; offset /= 2)
756 if (localid < offset)
758 scratch[localid] += scratch[localid + offset];
760 id.barrier(sycl::access::fence_space::local_space);
765 access_w[
id.get_group(0)] = scratch[localid];
771 m_env->internal()->queue().submit(f);
775 length = (length + local - 1) / local;
777 }
while (length > 1);
780 auto h_w = w.get_host_access();
785 template <
typename T>
788 template <
typename T>
791 template <
typename T>
792 T map_reduce_sum(sycl::buffer<T>& x,
795 auto& w = getWorkBuffer<T>(x.size());
797 std::size_t local = m_max_work_group_size;
798 std::size_t length = x.size();
806 auto round_length = round_up(length, local);
808 auto f0 = [length, round_length, local, &x,&y, &w](sycl::handler& h)
mutable
810 sycl::nd_range<1> range{sycl::range<1>{round_length},
811 sycl::range<1>{local}};
812 auto access_x = x.template get_access<sycl::access::mode::read>(h);
813 auto access_y = y.template get_access<sycl::access::mode::read>(h);
815 auto access_w = sycl::accessor { w, h, sycl::read_write, sycl::property::no_init{}};
819 sycl::local_accessor<T> scratch{sycl::range<1>(local), h};
823 h.parallel_for<
class sycl_map_reduction_sum0_T>(range,
824 [access_x,access_y,access_w, scratch, local, length](sycl::nd_item<1> id)
826 std::size_t globalid =
id.get_global_id(0);
827 std::size_t localid =
id.get_local_id(0);
834 scratch[localid] = (globalid < length)? access_x[globalid]*access_y[globalid] : 0. ;
836 id.barrier(sycl::access::fence_space::local_space);
840 if (globalid < length)
843 std::size_t min = local ;
844 for (std::size_t offset = min / 2; offset > 0; offset /= 2)
847 if (localid < offset)
849 scratch[localid] += scratch[localid + offset];
851 id.barrier(sycl::access::fence_space::local_space);
856 access_w[
id.get_group(0)] = scratch[localid];
864 auto f1 = [length, round_length, local, &w](sycl::handler& h)
mutable
866 sycl::nd_range<1> range{sycl::range<1>{round_length},
867 sycl::range<1>{local}};
868 auto access_w = w.template get_access<sycl::access::mode::read_write>(h);
872 sycl::local_accessor<T> scratch{sycl::range<1>(local), h};
876 h.parallel_for<
class sycl_map_reduction_sum_T>(range,
877 [access_w, scratch, local, length](sycl::nd_item<1> id)
879 std::size_t globalid =
id.get_global_id(0);
880 std::size_t localid =
id.get_local_id(0);
887 scratch[localid] = (globalid < length)? access_w[globalid] : 0. ;
888 id.barrier(sycl::access::fence_space::local_space);
892 if (globalid < length)
895 std::size_t min = local ;
896 for (std::size_t offset = min / 2; offset > 0; offset /= 2)
899 if (localid < offset)
901 scratch[localid] += scratch[localid + offset];
903 id.barrier(sycl::access::fence_space::local_space);
908 access_w[
id.get_group(0)] = scratch[localid];
915 m_env->internal()->queue().submit(f0);
917 m_env->internal()->queue().submit(f1);
921 length = (length + local - 1) / local;
925 auto h_x = w.get_host_access();
928 for (std::size_t i = 0; i < length; ++i)
933 template <
typename T>
936 template <
typename T>
937 T map2_reduce_sum(sycl::buffer<T>& x,
940 std::size_t local = m_max_work_group_size;
941 std::size_t total_threads = m_total_threads;
942 std::size_t length = x.size();
945 sycl::buffer<T> sum{ &sum_init, 1 };
951 auto round_length = round_up(length, local);
953 auto f0 = [length, round_length,total_threads, local, &x, &y, &sum](sycl::handler& h)
mutable
955 sycl::nd_range<1> range{sycl::range<1>{std::min(total_threads,round_length)},
956 sycl::range<1>{local}};
957 auto access_x = x.template get_access<sycl::access::mode::read>(h);
958 auto access_y = y.template get_access<sycl::access::mode::read>(h);
960 sycl::accessor access_sum {sum, h};
962 auto sumReduction = sycl::reduction(access_sum, sycl::plus<T>());
965 auto sumReduction = sycl::reduction(sum, h, sycl::plus<T>());
968 auto sumReduction = sycl::reduction(sum, h, sycl::plus<T>());
973 sycl::local_accessor<T> scratch{sycl::range<1>(local), h};
977 h.parallel_for<
class sycl_map2_reduction_sum0_T>(range,
979 [access_x,access_y, scratch, local,total_threads,length](sycl::nd_item<1> id, auto &sum)
981 std::size_t globalid =
id.get_global_id(0);
982 std::size_t localid =
id.get_local_id(0);
989 scratch[localid] = (globalid < length)? access_x[globalid]*access_y[globalid] : 0. ;
990 for (
auto i = globalid+total_threads; i < length; i += total_threads)
991 scratch[localid] += access_x[i]*access_y[i];
993 id.barrier(sycl::access::fence_space::local_space);
1000 std::size_t min = local ;
1001 for (std::size_t offset = min / 2; offset > 0; offset /= 2)
1004 if (localid < offset)
1006 scratch[localid] += scratch[localid + offset];
1008 id.barrier(sycl::access::fence_space::local_space);
1014 sum += scratch[localid];
1020 m_env->internal()->queue().submit(f0);
1023 auto h_sum = sum.get_host_access();
1027 template <
typename T>
1030 template <
typename T>
1031 T map3_reduce_sum(sycl::buffer<T>& x,
1034 std::size_t local = m_max_work_group_size;
1035 std::size_t total_threads = m_total_threads;
1036 std::size_t length = x.size();
1040 auto& group_sum = getWorkBuffer<T>(m_max_num_groups);
1045 auto round_length = round_up(length, local);
1052 auto f0 = [total_threads,round_length, length, local, &x, &y,&group_sum](sycl::handler& h)
mutable
1054 sycl::nd_range<1> range{sycl::range<1>{std::min(total_threads,round_length)},
1055 sycl::range<1>{local}};
1056 auto access_x = x.template get_access<sycl::access::mode::read>(h);
1057 auto access_y = y.template get_access<sycl::access::mode::read>(h);
1059 auto access_sum = sycl::accessor { group_sum, h, sycl::read_write, sycl::property::no_init{}};
1066 sycl::local_accessor<T> scratch{sycl::range<1>(local), h};
1071 h.parallel_for<
class sycl_map3_reduction_sum0_T>(range,
1074 [access_x,access_y,access_sum,scratch,local,length,total_threads] (sycl::nd_item<1> id)
1076 std::size_t globalid =
id.get_global_id(0);
1077 std::size_t localid =
id.get_local_id(0);
1079 scratch[localid] = (globalid < length)? access_x[globalid]*access_y[globalid] : 0. ;
1081 for (
auto i = globalid+total_threads; i < length; i += total_threads)
1082 scratch[localid] += access_x[i]*access_y[i];
1084 id.barrier(sycl::access::fence_space::local_space);
1090 std::size_t min = local ;
1091 for (std::size_t offset = min / 2; offset > 0; offset /= 2)
1093 if (localid < offset)
1095 scratch[localid] += scratch[localid + offset];
1097 id.barrier(sycl::access::fence_space::local_space);
1103 access_sum[
id.get_group(0)] = scratch[localid];
1110 m_env->internal()->queue().submit(f0);
1116 auto h_sum = group_sum.get_host_access();
1118 for (std::size_t i = 0; i < std::min(total_threads, round_length) / local; ++i)
1123 template <
typename T>
1126 template <
typename T>
1127 void asynch_map4_reduce_sum(sycl::buffer<T>& x,
1129 sycl::buffer<T>& res,
1132 std::size_t local = m_max_work_group_size;
1133 std::size_t total_threads = m_total_threads;
1134 std::size_t length = x.size();
1143 auto round_length = round_up(length, local);
1145 auto f0 = [total_threads, round_length, length, local, &x, &y,&res](sycl::handler& h)
mutable
1147 sycl::nd_range<1> range{sycl::range<1>{std::min(total_threads,round_length)},
1148 sycl::range<1>{local}};
1149 auto access_x = x.template get_access<sycl::access::mode::read>(h);
1150 auto access_y = y.template get_access<sycl::access::mode::read>(h);
1152 sycl::accessor access_sum {res, h};
1153 auto sumReduction = sycl::reduction(access_sum, sycl::plus<T>());
1156 auto sumReduction = sycl::reduction(res, h, sycl::plus<T>());
1159 auto sumReduction = sycl::reduction(res, h, sycl::plus<T>());
1169 sycl::local_accessor<T> scratch{sycl::range<1>(local), h};
1174 h.parallel_for<
class map4_reduction_sum_T>(range,
1176 [access_x,access_y,scratch,local,length,total_threads] (sycl::nd_item<1> id, auto& sum)
1178 std::size_t globalid =
id.get_global_id(0);
1179 std::size_t localid =
id.get_local_id(0);
1181 scratch[localid] = (globalid < length)? access_x[globalid]*access_y[globalid] : 0. ;
1183 for (
auto i = globalid+total_threads; i < length; i += total_threads)
1184 scratch[localid] += access_x[i]*access_y[i];
1186 id.barrier(sycl::access::fence_space::local_space);
1193 std::size_t min = local ;
1194 for (std::size_t offset = min / 2; offset > 0; offset /= 2)
1197 if (localid < offset)
1199 scratch[localid] += scratch[localid + offset];
1201 id.barrier(sycl::access::fence_space::local_space);
1208 sum += scratch[localid] ;
1214 event = m_env->internal()->queue().submit(f0);
1219 template <
typename T>
1220 T end_map4_reduce_sum(sycl::event& event,
1221 sycl::buffer<T>& res,
1222 [[maybe_unused]] std::size_t num_blocks)
1225 auto h_access = res.get_host_access();
1229 template <
typename T>
1232 template <
typename T>
1235 template <
typename T>
1236 void asynch_map5_reduce_sum(sycl::buffer<T>& x,
1238 sycl::buffer<T>& res,
1241 std::size_t local = m_max_work_group_size;
1242 std::size_t total_threads = m_total_threads;
1243 std::size_t length = x.size();
1251 auto f0 = [total_threads, length, local, &x, &y,&res](sycl::handler& h)
mutable
1253 sycl::nd_range<1> range{sycl::range<1>{total_threads},
1254 sycl::range<1>{local}};
1255 auto access_x = x.template get_access<sycl::access::mode::read>(h);
1256 auto access_y = y.template get_access<sycl::access::mode::read>(h);
1257 auto access_sum = sycl::accessor { res, h, sycl::read_write, sycl::property::no_init{}};
1261 sycl::local_accessor<T> scratch{sycl::range<1>(local), h};
1266 h.parallel_for<
class map5_reduction_sum_T>(range,
1267 [access_x,access_y,access_sum,scratch,local,length,total_threads] (sycl::nd_item<1> id)
1269 std::size_t globalid =
id.get_global_id(0);
1270 std::size_t localid =
id.get_local_id(0);
1272 scratch[localid] = (globalid < length)? access_x[globalid]*access_y[globalid] : 0. ;
1274 for (
auto i = globalid+total_threads; i < length; i += total_threads)
1275 scratch[localid] += access_x[i]*access_y[i];
1277 id.barrier(sycl::access::fence_space::local_space);
1281 if (globalid < length)
1284 for (std::size_t offset = local / 2; offset > 0; offset /= 2)
1287 if (localid < offset)
1289 scratch[localid] += scratch[localid + offset];
1291 id.barrier(sycl::access::fence_space::local_space);
1297 access_sum[
id.get_group(0)] = scratch[localid];
1304 auto f1 = [length, local, &res](sycl::handler& h)
mutable {
1305 sycl::nd_range<1> range{ sycl::range<1>{ local },
1306 sycl::range<1>{ local } };
1307 auto access_sum = res.template get_access<sycl::access::mode::read_write>(h);
1311 sycl::local_accessor<T> scratch{sycl::range<1>(local), h};
1315 h.parallel_for<
class map5_reduction_sum1_T>(range,
1316 [access_sum, scratch, local, length](sycl::nd_item<1> id) {
1318 std::size_t globalid =
id.get_global_id(0);
1319 std::size_t localid =
id.get_local_id(0);
1326 scratch[localid] = (localid < length) ? access_sum[localid] : 0.;
1327 id.barrier(sycl::access::fence_space::local_space);
1331 if (localid < length) {
1333 std::size_t min = local;
1334 for (std::size_t offset = min / 2; offset > 0; offset /= 2)
1337 if (localid < offset) {
1338 scratch[localid] += scratch[localid + offset];
1340 id.barrier(sycl::access::fence_space::local_space);
1344 access_sum[0] = scratch[localid];
1351 event = m_env->internal()->queue().submit(f0);
1353 event = m_env->internal()->queue().submit(f1);
1359 length = (std::min(total_threads, length) + local - 1) / local;
1361 }
while (length > 1);
1372 template <
typename T>
1373 T end_map5_reduce_sum(sycl::event& event,
1374 sycl::buffer<T>& res,
1375 [[maybe_unused]] std::size_t num_blocks)
1378 auto h_access = res.get_host_access();
1382 template <
typename T>
1383 T reduce_sum2(
const std::vector<T>& x)
1391 auto num_groups = m_env->internal()->queue().get_device().get_info<sycl::info::device::max_compute_units>();
1393 auto work_group_size = m_env->internal()->queue().get_device().get_info<sycl::info::device::max_work_group_size>();
1395 auto total_threads = num_groups * work_group_size;
1406 auto device = m_env->internal()->queue().get_device();
1408 std::size_t local = device.get_info<sycl::info::device::max_work_group_size>();
1410 std::size_t length = x.size();
1412 sycl::buffer<T, 1> xbuf(x.data(), sycl::range<1>(x.size()));
1413 xbuf.set_final_data(
nullptr);
1421 auto round_length = round_up(length, local);
1422 std::cout <<
"LENGTH :" << level <<
" " << length <<
" " << round_length <<
" " << local << std::endl;
1424 auto f = [length,round_length,local, &xbuf](sycl::handler& h)
mutable
1428 sycl::nd_range<1> r{sycl::range<1>{round_length},
1429 sycl::range<1>{local}};
1432 auto x_access = xbuf.template get_access<sycl::access::mode::read_write>(h);
1436 sycl::local_accessor<T> scratch{sycl::range<1>(local), h};
1440 h.parallel_for<
class reduce_sum2>(r, [x_access, scratch, local, length](sycl::nd_item<1> id)
1442 std::size_t globalid =
id.get_global_id(0);
1443 std::size_t localid =
id.get_local_id(0);
1450 scratch[localid] = (globalid < length)? x_access[globalid] : 0. ;
1451 id.barrier(sycl::access::fence_space::local_space);
1456 if (globalid < length)
1460 for (std::size_t offset = min / 2; offset > 0; offset /= 2)
1463 if (localid < offset)
1465 scratch[localid] += scratch[localid + offset];
1467 id.barrier(sycl::access::fence_space::local_space);
1472 x_access[
id.get_group(0)] = scratch[localid];
1479 m_env->internal()->queue().submit(f);
1483 length = (length + local - 1) / local;
1484 std::cout <<
"AFTER LENGTH :" << level <<
" new length" << length <<
" " << local << std::endl;
1486 }
while (length > 1);
1491 auto hI = xbuf.get_host_acces();
1498 template <
typename T>
1499 T sycl_reduce_sum(sycl::buffer<T>& x,
1503 sycl::buffer<T> sum_buff{ &sum_init, 1 };
1506 m_env->internal()->queue().submit([&](sycl::handler &cgh)
1508 auto access_x = x.template get_access<sycl::access::mode::read>(cgh);
1509 auto access_y = y.template get_access<sycl::access::mode::read>(cgh);
1511 sycl::accessor sum_acc {sum_buff, cgh};
1512 auto sumReduction = sycl::reduction(sum_acc, sycl::plus<T>());
1515 auto sumReduction = sycl::reduction(sum_buff, cgh, sycl::plus<T>());
1518 auto sumReduction = sycl::reduction(sum_buff, cgh, sycl::plus<T>());
1520 cgh.parallel_for(sycl::range<1>{x.size()},
1522 [=](sycl::id<1> idx,
auto &sum)
1524 sum += access_x[idx]*access_y[idx];
1529 return sum_buff.get_host_access()[0];
1719 template <
typename T>
1720 inline T dot_product_h100(sycl::buffer<T>& buf_x,
1721 sycl::buffer<T>& buf_y)
1723 using namespace sycl;
1724 auto& q = m_env->internal()->queue();
1725 const size_t N = buf_x.size();
1726 assert(buf_y.size() == N);
1728 auto dev = q.get_device();
1733 const size_t blocks_needed = (N + WG_SIZE * ITEMS_PER_WI - 1)
1734 / (WG_SIZE * ITEMS_PER_WI);
1735 const size_t num_blocks = std::max(blocks_needed,
1736 m_max_num_groups * TARGET_WAVES);
1737 const size_t total_threads = num_blocks * WG_SIZE;
1741 sycl::buffer<T> partials{num_blocks};
1747 auto ax = buf_x.template get_access<access::mode::read>(cgh);
1748 auto ay = buf_y.template get_access<access::mode::read>(cgh);
1749 auto ap = partials.template get_access<access::mode::read_write>(cgh);
1751 local_accessor<T,1> lds{WG_SIZE / WARP_SIZE, cgh};
1758 cgh.parallel_for<
class dot_h100_phase1>(
1759 nd_range<1>{{total_threads}, {WG_SIZE}},
1760 [=](nd_item<1> item)
1761 [[intel::reqd_sub_group_size(WARP_SIZE)]]
1763 h100::dot_kernel_h100(item, ax, ay, ap, n, lds);
1774 auto h_partials = partials.get_host_access();
1777 T sum = 0.0, c = 0.0;
1778 for (
size_t b = 0; b < num_blocks; ++b) {
1779 T z = h_partials[b] - c;
1787 template <
typename T>
1788 inline std::size_t asynch_dot_product_h100(sycl::buffer<T>& buf_x,
1789 sycl::buffer<T>& buf_y,
1790 sycl::buffer<T>& res,
1793 using namespace sycl;
1794 auto& q = m_env->internal()->queue();
1795 const size_t N = buf_x.size();
1796 assert(buf_y.size() == N);
1803 const size_t blocks_needed = (N + WG_SIZE * ITEMS_PER_WI - 1)
1804 / (WG_SIZE * ITEMS_PER_WI);
1805 const size_t num_blocks = std::max(blocks_needed,m_max_num_groups * TARGET_WAVES);
1806 const size_t total_threads = num_blocks * WG_SIZE;
1815 auto ax = buf_x.template get_access<access::mode::read>(cgh);
1816 auto ay = buf_y.template get_access<access::mode::read>(cgh);
1817 auto ap = res.template get_access<sycl::access::mode::read_write>(cgh);
1819 local_accessor<T,1> lds{WG_SIZE / WARP_SIZE, cgh};
1826 cgh.parallel_for<
class dot_h100_phase1>(
1827 nd_range<1>{{total_threads}, {WG_SIZE}},
1828 [=](nd_item<1> item)
1829 [[intel::reqd_sub_group_size(WARP_SIZE)]]
1831 h100::dot_kernel_h100(item, ax, ay, ap, n, lds);
1838 template <
typename T>
1839 inline T end_dot_product_h100(sycl::event& event,
1840 sycl::buffer<T>& res,
1841 std::size_t num_blocks)
1851 auto h_partials = res.get_host_access();
1854 T sum = 0.0, c = 0.0;
1855 for (
size_t b = 0; b < num_blocks; ++b) {
1856 T z = h_partials[b] - c;
1869 template<
typename T>
1870 inline T dot_product_mi300(sycl::buffer<T, 1>& x_buf,
1871 sycl::buffer<T, 1>& y_buf)
1873 using namespace mi300 ;
1874 std::cout<<
" DOT PROD MI300 : "<<WG_SIZE<<
" "<<ITEMS_PER_WI<<std::endl ;
1876 bool use_doublebuf =
false;
1877 auto& q = m_env->internal()->queue();
1908 std::size_t N = x_buf.size() ;
1910 const size_t blocks_needed = (N + WG_SIZE * ITEMS_PER_WI - 1)
1911 / (WG_SIZE * ITEMS_PER_WI);
1914 const size_t num_blocks = std::max(blocks_needed,
1915 m_max_num_groups * TARGET_WAVES
1916 * (WG_SIZE / WAVEFRONT));
1917 const size_t total_threads = num_blocks * WG_SIZE;
1920 sycl::buffer<T, 1> partials(num_blocks);
1922 q.submit([&](sycl::handler& cgh)
1924 auto ax = x_buf.template get_access<sycl::access::mode::read>(cgh);
1925 auto ay = y_buf.template get_access<sycl::access::mode::read>(cgh);
1926 auto ap = partials.template get_access<sycl::access::mode::read_write>(cgh);
1927 sycl::local_accessor<double,1> lds{N_WARPS_BLOC, cgh};
1933 const bool db = use_doublebuf;
1935 cgh.parallel_for<
class dot_mi300_phase1>(
1936 sycl::nd_range<1>{{total_threads}, {WG_SIZE}},
1940 [=](sycl::nd_item<1> item)
1941 [[intel::reqd_sub_group_size(WAVEFRONT)]]
1944 mi300::dot_kernel_mi300_doublebuf(item, ax, ay, ap, n, lds);
1946 mi300::dot_kernel_mi300(item, ax, ay, ap, n, lds);
1954 auto h_partials = partials.get_host_access();
1958 for (std::size_t b = 0; b < num_blocks; ++b)
1960 T z = h_partials[b] - c;
1968 template <
typename T>
1969 inline void asynch_dot_product_mi300(sycl::buffer<T, 1>& x_buf,
1970 sycl::buffer<T, 1>& y_buf,
1971 sycl::buffer<T, 1>& result_buf,
1974 using namespace mi300 ;
1976 std::size_t n = x_buf.size() ;
1977 auto& q = m_env->internal()->queue();
1979 const std::size_t stride = WG_SIZE * ITEMS_PER_WI;
1980 const std::size_t n_padded = ((n + stride - 1) / stride) * stride;
1982 event = q.submit([&](sycl::handler& cgh) {
1983 auto x = x_buf.template get_access<sycl::access::mode::read>(cgh);
1984 auto y = y_buf.template get_access<sycl::access::mode::read>(cgh);
1985 auto red = sycl::reduction(result_buf, cgh, sycl::plus<T>{});
1988 sycl::nd_range<1>{n_padded, WG_SIZE}, red,
1989 [=](sycl::nd_item<1> item,
auto& sum) {
1990 const std::size_t lid = item.get_local_id(0);
1991 const std::size_t base = item.get_group(0) * stride;
1994 for (std::size_t k = 0; k < ITEMS_PER_WI; ++k) {
1995 const std::size_t idx = base + lid + k * WG_SIZE;
1996 if (idx < n) acc += x[idx] * y[idx];
2005 template <
typename T>
2006 T end_dot_product_mi300(sycl::event& event,
2007 sycl::buffer<T>& res,
2008 [[maybe_unused]] std::size_t num_blocks)
2011 auto h_access = res.get_host_access();
2015 template <
typename T>
2016 T dot(sycl::buffer<T>& x,
2019 switch (m_dot_algo) {
2021 return reduce_sum(x, y);
2023 return map_reduce_sum(x, y);
2025 return map2_reduce_sum(x, y);
2027 return map3_reduce_sum(x, y);
2029 return dot_product_h100(x, y);
2031 return dot_product_mi300(x, y);
2033 return sycl_reduce_sum(x, y);
2037 template <
typename T>
2038 void dot(sycl::buffer<T>& x,
2045 asynch_map4_reduce_sum(x, y, res.deviceValue(), res.event());
2046 res.setWaitFunction([=](sycl::event& event, sycl::buffer<double>& res, std::size_t num_blocks)
2048 return this->end_map4_reduce_sum(event,res, num_blocks) ;
2053 std::size_t num_blocks = asynch_dot_product_h100(x, y, res.deviceValue(), res.event());
2054 res.setWaitFunction([=](sycl::event& event, sycl::buffer<double>& res, std::size_t num_blocks)
2056 return this->end_dot_product_h100(event, res, num_blocks) ;
2058 res.setNumBlocks(num_blocks) ;
2062 asynch_dot_product_mi300(x, y, res.deviceValue(), res.event());
2063 res.setWaitFunction([=](sycl::event& event, sycl::buffer<T>& res, std::size_t num_blocks)
2065 return this->end_dot_product_mi300(event,res, num_blocks) ;
2069 asynch_map5_reduce_sum(x, y, res.deviceValue(), res.event());
2070 res.setWaitFunction([=](sycl::event& event, sycl::buffer<T>& res, std::size_t num_blocks)
2072 return this->end_map5_reduce_sum(event,res, num_blocks) ;
2080 SYCLEnv* m_env = nullptr ;
2081 std::size_t m_max_num_groups = 0 ;
2082 std::size_t m_max_work_group_size = 0 ;
2083 std::size_t m_total_threads = 0 ;
2086 template <
typename T>
2087 sycl::buffer<T>& getWorkBuffer(std::size_t size);
2089 mutable sycl::buffer<double>* m_double_work =
nullptr;