/* * VCluster_meta_function.hpp * * Created on: Dec 8, 2016 * Author: i-bird */ #ifndef OPENFPM_VCLUSTER_SRC_VCLUSTER_VCLUSTER_META_FUNCTION_HPP_ #define OPENFPM_VCLUSTER_SRC_VCLUSTER_VCLUSTER_META_FUNCTION_HPP_ #include "memory/BHeapMemory.hpp" #include "Packer_Unpacker/has_max_prop.hpp" template class layout_base, typename Memory> struct unpack_selector_with_prp { template static void call_unpack(S & recv, openfpm::vector_fr> & recv_buf, openfpm::vector * sz, openfpm::vector * sz_byte, op & op_param, size_t opt) { if (sz_byte != NULL) sz_byte->resize(recv_buf.size()); for (size_t i = 0 ; i < recv_buf.size() ; i++) { T unp; ExtPreAlloc & mem = *(new ExtPreAlloc(recv_buf.get(i).size(),recv_buf.get(i))); mem.incRef(); Unpack_stat ps; Unpacker::template unpack<>(mem, unp, ps); size_t recv_size_old = recv.size(); // Merge the information op_param.template execute(recv,unp,i,opt); size_t recv_size_new = recv.size(); if (sz_byte != NULL) sz_byte->get(i) = recv_buf.get(i).size(); if (sz != NULL) sz->get(i) = recv_size_new - recv_size_old; mem.decRef(); delete &mem; } } }; template class layout_base, typename v_mpl> struct unpack_each_prop_buffer { S & recv; openfpm::vector> & recv_buf; size_t i; op & op_param; openfpm::vector * sz; openfpm::vector * sz_byte; /*! \brief constructor * * \param v set of pointer buffers to set * */ inline unpack_each_prop_buffer(S & recv, openfpm::vector_fr> & recv_buf, op & op_param, size_t i, openfpm::vector * sz, openfpm::vector * sz_byte) :recv(recv),recv_buf(recv_buf),op_param(op_param),i(i),sz(sz),sz_byte(sz_byte) {}; //! It call the copy function for each property template inline void operator()(T& t) const { // here we get the the type of the property at position T::value typedef typename boost::mpl::at >::type prp_type; // here we get the the type of the property at position T::value typedef typename boost::mpl::at>::type prp_num; // calculate the number of received elements size_t n_ele = recv_buf.get(i).size() / sizeof(prp_type); // add the received particles to the vector PtrMemory * ptr1 = new PtrMemory(recv_buf.get(i).getPointer(),recv_buf.get(i).size()); // create vector representation to a piece of memory already allocated openfpm::vector::type,layout_base,openfpm::grow_policy_identity> v2; v2.template setMemory(*ptr1); // resize with the number of elements v2.resize(n_ele); // Merge the information size_t recv_size_old = recv.size(); op_param.template execute(recv,v2,i); size_t recv_size_new = recv.size(); if (sz_byte != NULL) sz_byte->get(i) = recv_buf.get(i).size(); if (sz != NULL) sz->get(i) = recv_size_new - recv_size_old; } }; /*! \brief this class is a functor for "for_each" algorithm * * This class is a functor for "for_each" algorithm. For each * element of the boost::vector the operator() is called. * Is mainly used to process the receive buffers in case of memory_traits_inte layout receive * * \tparam encap source * \tparam encap dst * */ template class layout_base,typename Memory> struct process_receive_mem_traits_inte { //! set of pointers size_t i; //! Receive buffer openfpm::vector_fr> & recv_buf; //! Fake vector that map over received memory openfpm::vector::type,layout_base,openfpm::grow_policy_identity> & v2; size_t n_ele = 0; // options size_t opt; /*! \brief constructor * * \param v set of pointer buffers to set * */ inline process_receive_mem_traits_inte(openfpm::vector::type,layout_base,openfpm::grow_policy_identity> & v2, openfpm::vector_fr> & recv_buf, size_t i, size_t opt) :i(i),recv_buf(recv_buf),v2(v2),opt(opt) {}; //! It call the copy function for each property template inline void operator()(T& t) { typedef typename boost::mpl::at::type type_prp; // calculate the number of received elements this->n_ele = recv_buf.get(i).size() / sizeof(type_prp); PtrMemory * ptr1; if (opt & MPI_GPU_DIRECT) { #if defined(MPIX_CUDA_AWARE_SUPPORT) && MPIX_CUDA_AWARE_SUPPORT // add the received particles to the vector ptr1 = new PtrMemory(recv_buf.get(i).getDevicePointer(),recv_buf.get(i).size()); #else // add the received particles to the vector ptr1 = new PtrMemory(recv_buf.get(i).getPointer(),recv_buf.get(i).size()); #endif } else { // add the received particles to the vector ptr1 = new PtrMemory(recv_buf.get(i).getPointer(),recv_buf.get(i).size()); } v2.template setMemory(*ptr1); ++i; } }; template class layout_base,typename Memory> struct unpack_selector_with_prp_lin { template static int call_unpack_impl(S & recv, openfpm::vector_fr> & recv_buf, openfpm::vector * sz, openfpm::vector * sz_byte, op & op_param, size_t i, size_t opt) { // create vector representation to a piece of memory already allocated openfpm::vector::type,layout_base,openfpm::grow_policy_identity> v2; process_receive_mem_traits_inte prmti(v2,recv_buf,i,opt); boost::mpl::for_each_ref>(prmti); v2.resize(prmti.n_ele); // Merge the information size_t recv_size_old = recv.size(); op_param.template execute(recv,v2,i,opt); size_t recv_size_new = recv.size(); if (sz_byte != NULL) sz_byte->get(i) = recv_buf.get(i).size(); if (sz != NULL) sz->get(i) = recv_size_new - recv_size_old; return sizeof...(prp); } }; template class layout_base, typename Memory> struct unpack_selector_with_prp_lin { template static int call_unpack_impl(S & recv, openfpm::vector_fr> & recv_buf, openfpm::vector * sz, openfpm::vector * sz_byte, op & op_param, size_t i, size_t opt) { // calculate the number of received elements size_t n_ele = recv_buf.get(i).size() / sizeof(typename T::value_type); // add the received particles to the vector PtrMemory * ptr1 = new PtrMemory(recv_buf.get(i).getPointer(),recv_buf.get(i).size()); // create vector representation to a piece of memory already allocated openfpm::vector::type,layout_base,openfpm::grow_policy_identity> v2; v2.setMemory(*ptr1); // resize with the number of elements v2.resize(n_ele); // Merge the information size_t recv_size_old = recv.size(); op_param.template execute(recv,v2,i,opt); size_t recv_size_new = recv.size(); if (sz_byte != NULL) sz_byte->get(i) = recv_buf.get(i).size(); if (sz != NULL) sz->get(i) = recv_size_new - recv_size_old; return 1; } }; typedef aggregate dummy_type; // template class layout_base, typename Memory> struct unpack_selector_with_prp { template static void call_unpack(S & recv, openfpm::vector_fr> & recv_buf, openfpm::vector * sz, openfpm::vector * sz_byte, op & op_param, size_t opt) { if (sz_byte != NULL) sz_byte->resize(recv_buf.size()); for (size_t i = 0 ; i < recv_buf.size() ; ) { i += unpack_selector_with_prp_lin>::value,T,S,layout_base,Memory>::template call_unpack_impl(recv,recv_buf,sz,sz_byte,op_param,i,opt); } } }; template struct call_serialize_variadic {}; template struct call_serialize_variadic> { template inline static void call_pr(T & send, size_t & tot_size) { Packer::template packRequest(send,tot_size); } template inline static void call_pack(ExtPreAlloc & mem, T & send, Pack_stat & sts) { Packer::template pack(mem,send,sts); } template class layout_base, typename Memory> inline static void call_unpack(S & recv, openfpm::vector_fr> & recv_buf, openfpm::vector * sz, openfpm::vector * sz_byte, op & op_param, size_t opt) { const bool result = has_pack_gen::value == false && is_vector::value == true; unpack_selector_with_prp::template call_unpack(recv, recv_buf, sz, sz_byte, op_param,opt); } }; /*! \brief this class is a functor for "for_each" algorithm * * This class is a functor for "for_each" algorithm. For each * element of the boost::vector the operator() is called. * Is mainly used to copy one encap into another encap object * * \tparam encap source * \tparam encap dst * */ template struct set_buf_pointer_for_each_prop { //! set of pointers sT & v; openfpm::vector & send_buf; size_t opt; /*! \brief constructor * * \param v set of pointer buffers to set * */ inline set_buf_pointer_for_each_prop(sT & v, openfpm::vector & send_buf, size_t opt) :v(v),send_buf(send_buf),opt(opt) {}; //! It call the copy function for each property template inline void operator()(T& t) const { // If we have GPU direct activated use directly the cuda buffer if (opt & MPI_GPU_DIRECT) { #if defined(MPIX_CUDA_AWARE_SUPPORT) && MPIX_CUDA_AWARE_SUPPORT send_buf.add(v.template getDeviceBuffer()); #else v.template deviceToHost(); send_buf.add(v.template getPointer()); #endif } else { send_buf.add(v.template getPointer()); } } }; /*! \brief this class is a functor for "for_each" algorithm * * This class is a functor for "for_each" algorithm. For each * element of the boost::vector the operator() is called. * Is mainly used to copy one encap into another encap object * * \tparam encap source * \tparam encap dst * */ template struct set_buf_size_for_each_prop { //! set of pointers sT & v; openfpm::vector & sz; /*! \brief constructor * * \param v set of pointer buffers to set * */ inline set_buf_size_for_each_prop(sT & v, openfpm::vector & sz) :v(v),sz(sz) {}; //! It call the copy function for each property template inline void operator()(T& t) const { typedef typename boost::mpl::at::type type_prp; sz.add(sizeof(type_prp)*v.size()); } }; template::value > struct pack_unpack_cond_with_prp_inte_lin { static void set_buffers(T & send, openfpm::vector & send_buf, size_t opt) { send_buf.add(send.getPointer()); } static void set_size_buffers(T & send, openfpm::vector & sz) { sz.add(send.size()*sizeof(typename T::value_type)); } static void construct_prc(openfpm::vector & prc_send, openfpm::vector & prc_send_) { for (size_t i = 0 ; i < prc_send.size() ; i++) { prc_send_.add(prc_send.get(i)); } } }; // memory_traits_inte template struct pack_unpack_cond_with_prp_inte_lin { static void set_buffers(T & send, openfpm::vector & send_buf, size_t opt) { set_buf_pointer_for_each_prop sbp(send,send_buf,opt); boost::mpl::for_each_ref>(sbp); } static void set_size_buffers(T & send, openfpm::vector & sz) { set_buf_size_for_each_prop sbp(send,sz); boost::mpl::for_each_ref>(sbp); } static void construct_prc(openfpm::vector & prc_send, openfpm::vector & prc_send_) { for (size_t i = 0 ; i < prc_send.size() ; i++) { for (size_t j = 0 ; j < T::value_type::max_prop ; j++) {prc_send_.add(prc_send.get(i));} } } }; //! There is max_prop inside template class layout_base, unsigned int ... prp> struct pack_unpack_cond_with_prp { static void packingRequest(T & send, size_t & tot_size, openfpm::vector & sz) { typedef typename ::generate_indexes::value>::number, MetaFuncOrd>::result ind_prop_to_pack; if (has_pack_gen::value == false && is_vector::value == true) { pack_unpack_cond_with_prp_inte_lin::set_size_buffers(send,sz); } else { call_serialize_variadic::call_pr(send,tot_size); sz.add(tot_size); } } static void packing(ExtPreAlloc & mem, T & send, Pack_stat & sts, openfpm::vector & send_buf, size_t opt = 0) { typedef typename ::generate_indexes::value>::number, MetaFuncOrd>::result ind_prop_to_pack; if (has_pack_gen::value == false && is_vector::value == true) { pack_unpack_cond_with_prp_inte_lin::set_buffers(send,send_buf,opt); } else { send_buf.add(mem.getPointerEnd()); call_serialize_variadic::call_pack(mem,send,sts); } } template static void unpacking(S & recv, openfpm::vector_fr> & recv_buf, openfpm::vector * sz, openfpm::vector * sz_byte, op & op_param, size_t opt) { typedef index_tuple ind_prop_to_pack; call_serialize_variadic::template call_unpack(recv, recv_buf, sz, sz_byte, op_param,opt); } }; ///////////////////////////// //! Helper class to add data without serialization template struct op_ssend_recv_add_sr { //! Add data template class layout_base, int ... prp> static void execute(D & recv,S & v2, size_t i, size_t opt) { if (opt & MPI_GPU_DIRECT) { #if defined(MPIX_CUDA_AWARE_SUPPORT) && MPIX_CUDA_AWARE_SUPPORT // Merge the information recv.template add_prp_device::value, layout_base, prp...>(v2); #else // Merge the information recv.template add_prp::value, layout_base, prp...>(v2); recv.template hostToDevice(recv.size(),recv.size()+v2.size()); #endif } else { // Merge the information recv.template add_prp::value, layout_base, prp...>(v2); } } }; //! Helper class to add data with serialization template<> struct op_ssend_recv_add_sr { //! Add data template class layout_base, int ... prp> static void execute(D & recv,S & v2, size_t i,size_t opt) { // Merge the information recv.template add_prp::value, layout_base, prp...>(v2); } }; //! Helper class to add data template struct op_ssend_recv_add { //! Add data template class layout_base, int ... prp> static void execute(D & recv,S & v2, size_t i, size_t opt) { // Merge the information op_ssend_recv_add_sr::template execute(recv,v2,i,opt); } }; //! Helper class to merge data without serialization template class op> struct op_ssend_recv_merge_impl { //! Merge the template class layout_base, int ... prp> inline static void execute(D & recv,S & v2,size_t i,openfpm::vector>> & opart) { // Merge the information recv.template merge_prp_v(v2,opart.get(i)); } }; //! Helper class to merge data with serialization template class op> struct op_ssend_recv_merge_impl { //! merge the data template class layout_base, int ... prp> inline static void execute(D & recv,S & v2,size_t i,openfpm::vector>> & opart) { // Merge the information recv.template merge_prp_v(v2,opart.get(i)); } }; //! Helper class to merge data template class op> struct op_ssend_recv_merge { //! For each processor contain the list of the particles with which I must merge the information openfpm::vector>> & opart; //! constructor op_ssend_recv_merge(openfpm::vector>> & opart) :opart(opart) {} //! execute the merge template class layout_base, int ... prp> void execute(D & recv,S & v2,size_t i,size_t opt) { op_ssend_recv_merge_impl::template execute(recv,v2,i,opart); } }; //! Helper class to merge data without serialization template struct op_ssend_gg_recv_merge_impl { //! Merge the template class layout_base, int ... prp> inline static void execute(D & recv,S & v2,size_t i,size_t & start) { // Merge the information recv.template merge_prp_v(v2,start); start += v2.size(); } }; //! Helper class to merge data with serialization template<> struct op_ssend_gg_recv_merge_impl { //! merge the data template class layout_base, int ... prp> inline static void execute(D & recv,S & v2,size_t i,size_t & start) { // Merge the information recv.template merge_prp_v(v2,start); // from start += v2.size(); } }; //! Helper class to merge data struct op_ssend_gg_recv_merge { //! starting marker size_t start; //! constructor op_ssend_gg_recv_merge(size_t start) :start(start) {} //! execute the merge template class layout_base, int ... prp> void execute(D & recv,S & v2,size_t i,size_t opt) { op_ssend_gg_recv_merge_impl::template execute(recv,v2,i,start); } }; ////////////////////////////////////////////////// #endif /* OPENFPM_VCLUSTER_SRC_VCLUSTER_VCLUSTER_META_FUNCTION_HPP_ */