/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/cshift/Cshift_common.h Copyright (C) 2015 Author: Peter Boyle This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. See the full license in the file "LICENSE" in the top level distribution directory *************************************************************************************/ /* END LEGAL */ #pragma once NAMESPACE_BEGIN(Grid); extern std::vector > Cshift_table; extern deviceVector > Cshift_table_device; inline std::pair *MapCshiftTable(void) { // GPU version uint64_t sz=Cshift_table.size(); if (Cshift_table_device.size()!=sz ) { Cshift_table_device.resize(sz); } acceleratorCopyToDevice((void *)&Cshift_table[0], (void *)&Cshift_table_device[0], sizeof(Cshift_table[0])*sz); return &Cshift_table_device[0]; // CPU version use identify map } /////////////////////////////////////////////////////////////////// // Gather for when there is no need to SIMD split /////////////////////////////////////////////////////////////////// template void Gather_plane_simple (const Lattice &rhs,deviceVector &buffer,int dimension,int plane,int cbmask, int off=0) { int rd = rhs.Grid()->_rdimensions[dimension]; if ( !rhs.Grid()->CheckerBoarded(dimension) ) { cbmask = 0x3; } int so=plane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane int e1=rhs.Grid()->_slice_nblock[dimension]; int e2=rhs.Grid()->_slice_block[dimension]; int ent = 0; if(Cshift_table.size()_slice_stride[dimension]; if ( cbmask == 0x3 ) { for(int n=0;n(off+bo+b,so+o+b); } } } else { int bo=0; for(int n=0;nCheckerBoardFromOindex(o+b); if ( ocb &cbmask ) { Cshift_table[ent++]=std::pair (off+bo++,so+o+b); } } } } { auto buffer_p = & buffer[0]; auto table = MapCshiftTable(); autoView(rhs_v , rhs, AcceleratorRead); accelerator_for(i,ent,vobj::Nsimd(),{ coalescedWrite(buffer_p[table[i].first],coalescedRead(rhs_v[table[i].second])); }); } } /////////////////////////////////////////////////////////////////// // Gather for when there *is* need to SIMD split /////////////////////////////////////////////////////////////////// template void Gather_plane_extract(const Lattice &rhs, ExtractPointerArray pointers, int dimension,int plane,int cbmask) { int rd = rhs.Grid()->_rdimensions[dimension]; if ( !rhs.Grid()->CheckerBoarded(dimension) ) { cbmask = 0x3; } int so = plane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane int e1=rhs.Grid()->_slice_nblock[dimension]; int e2=rhs.Grid()->_slice_block[dimension]; int n1=rhs.Grid()->_slice_stride[dimension]; if ( cbmask ==0x3){ autoView(rhs_v , rhs, AcceleratorRead); accelerator_for(nn,e1*e2,1,{ int n = nn%e1; int b = nn/e1; int o = n*n1; int offset = b+n*e2; vobj temp =rhs_v[so+o+b]; extract(temp,pointers,offset); }); } else { Coordinate rdim=rhs.Grid()->_rdimensions; Coordinate cdm =rhs.Grid()->_checker_dim_mask; std::cout << " Dense packed buffer WARNING " <(temp,pointers,offset); } }); } } ////////////////////////////////////////////////////// // Scatter for when there is no need to SIMD split ////////////////////////////////////////////////////// template void Scatter_plane_simple (Lattice &rhs,deviceVector &buffer, int dimension,int plane,int cbmask) { int rd = rhs.Grid()->_rdimensions[dimension]; if ( !rhs.Grid()->CheckerBoarded(dimension) ) { cbmask=0x3; } int so = plane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane int e1=rhs.Grid()->_slice_nblock[dimension]; int e2=rhs.Grid()->_slice_block[dimension]; int stride=rhs.Grid()->_slice_stride[dimension]; if(Cshift_table.size()_slice_stride[dimension]; int bo =n*rhs.Grid()->_slice_block[dimension]; Cshift_table[ent++] = std::pair(so+o+b,bo+b); } } } else { int bo=0; for(int n=0;n_slice_stride[dimension]; int ocb=1<CheckerBoardFromOindex(o+b);// Could easily be a table lookup if ( ocb & cbmask ) { Cshift_table[ent++]=std::pair (so+o+b,bo++); } } } } { auto buffer_p = & buffer[0]; auto table = MapCshiftTable(); autoView( rhs_v, rhs, AcceleratorWrite); accelerator_for(i,ent,vobj::Nsimd(),{ coalescedWrite(rhs_v[table[i].first],coalescedRead(buffer_p[table[i].second])); }); } } ////////////////////////////////////////////////////// // Scatter for when there *is* need to SIMD split ////////////////////////////////////////////////////// template void Scatter_plane_merge(Lattice &rhs,ExtractPointerArray pointers,int dimension,int plane,int cbmask) { int rd = rhs.Grid()->_rdimensions[dimension]; if ( !rhs.Grid()->CheckerBoarded(dimension) ) { cbmask=0x3; } int so = plane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane int e1=rhs.Grid()->_slice_nblock[dimension]; int e2=rhs.Grid()->_slice_block[dimension]; if(cbmask ==0x3 ) { int _slice_stride = rhs.Grid()->_slice_stride[dimension]; int _slice_block = rhs.Grid()->_slice_block[dimension]; autoView( rhs_v , rhs, AcceleratorWrite); accelerator_for(nn,e1*e2,1,{ int n = nn%e1; int b = nn/e1; int o = n*_slice_stride; int offset = b+n*_slice_block; merge(rhs_v[so+o+b],pointers,offset); }); } else { // Case of SIMD split AND checker dim cannot currently be hit, except in // Test_cshift_red_black code. std::cout << "Scatter_plane merge assert(0); think this is buggy FIXME "<< std::endl;// think this is buggy FIXME std::cout<<" Unthreaded warning -- buffer is not densely packed ??"<_slice_stride[dimension]; int offset = b+n*rhs.Grid()->_slice_block[dimension]; int ocb=1<CheckerBoardFromOindex(o+b); if ( ocb&cbmask ) { merge(rhs_v[so+o+b],pointers,offset); } } } } } ////////////////////////////////////////////////////// // local to node block strided copies ////////////////////////////////////////////////////// template void Copy_plane(Lattice& lhs,const Lattice &rhs, int dimension,int lplane,int rplane,int cbmask) { int rd = rhs.Grid()->_rdimensions[dimension]; if ( !rhs.Grid()->CheckerBoarded(dimension) ) { cbmask=0x3; } int ro = rplane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane int lo = lplane*lhs.Grid()->_ostride[dimension]; // base offset for start of plane int e1=rhs.Grid()->_slice_nblock[dimension]; // clearly loop invariant for icpc int e2=rhs.Grid()->_slice_block[dimension]; int stride = rhs.Grid()->_slice_stride[dimension]; if(Cshift_table.size()(lo+o,ro+o); } } } else { for(int n=0;nCheckerBoardFromOindex(o); if ( ocb&cbmask ) { Cshift_table[ent++] = std::pair(lo+o,ro+o); } } } } { auto table = MapCshiftTable(); autoView(rhs_v , rhs, AcceleratorRead); autoView(lhs_v , lhs, AcceleratorWrite); accelerator_for(i,ent,vobj::Nsimd(),{ coalescedWrite(lhs_v[table[i].first],coalescedRead(rhs_v[table[i].second])); }); } } template void Copy_plane_permute(Lattice& lhs,const Lattice &rhs, int dimension,int lplane,int rplane,int cbmask,int permute_type) { int rd = rhs.Grid()->_rdimensions[dimension]; if ( !rhs.Grid()->CheckerBoarded(dimension) ) { cbmask=0x3; } int ro = rplane*rhs.Grid()->_ostride[dimension]; // base offset for start of plane int lo = lplane*lhs.Grid()->_ostride[dimension]; // base offset for start of plane int e1=rhs.Grid()->_slice_nblock[dimension]; int e2=rhs.Grid()->_slice_block [dimension]; int stride = rhs.Grid()->_slice_stride[dimension]; if(Cshift_table.size()(lo+o+b,ro+o+b); }} } else { for(int n=0;nCheckerBoardFromOindex(o+b); if ( ocb&cbmask ) Cshift_table[ent++] = std::pair(lo+o+b,ro+o+b); }} } { auto table = MapCshiftTable(); autoView( rhs_v, rhs, AcceleratorRead); autoView( lhs_v, lhs, AcceleratorWrite); accelerator_for(i,ent,1,{ permute(lhs_v[table[i].first],rhs_v[table[i].second],permute_type); }); } } ////////////////////////////////////////////////////// // Local to node Cshift ////////////////////////////////////////////////////// template void Cshift_local(Lattice& ret,const Lattice &rhs,int dimension,int shift) { int sshift[2]; sshift[0] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Even); sshift[1] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Odd); if ( sshift[0] == sshift[1] ) { Cshift_local(ret,rhs,dimension,shift,0x3); } else { Cshift_local(ret,rhs,dimension,shift,0x1);// if checkerboard is unfavourable take two passes Cshift_local(ret,rhs,dimension,shift,0x2);// both with block stride loop iteration } } template void Cshift_local(Lattice &ret,const Lattice &rhs,int dimension,int shift,int cbmask) { GridBase *grid = rhs.Grid(); int fd = grid->_fdimensions[dimension]; int rd = grid->_rdimensions[dimension]; int ld = grid->_ldimensions[dimension]; int gd = grid->_gdimensions[dimension]; int ly = grid->_simd_layout[dimension]; // Map to always positive shift modulo global full dimension. shift = (shift+fd)%fd; // the permute type ret.Checkerboard() = grid->CheckerBoardDestination(rhs.Checkerboard(),shift,dimension); int permute_dim =grid->PermuteDim(dimension); int permute_type=grid->PermuteType(dimension); int permute_type_dist; for(int x=0;x_ostride[dimension]; int cb= (cbmask==0x2)? Odd : Even; int sshift = grid->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,cb); int sx = (x+sshift)%rd; // wrap is whether sshift > rd. // num is sshift mod rd. // // shift 7 // // XoXo YcYc // oXoX cYcY // XoXo YcYc // oXoX cYcY // // sshift -- // // XX YY ; 3 // XX YY ; 0 // XX YY ; 3 // XX YY ; 0 // int permute_slice=0; if(permute_dim){ int wrap = sshift/rd; wrap=wrap % ly; int num = sshift%rd; if ( x< rd-num ) permute_slice=wrap; else permute_slice = (wrap+1)%ly; if ( (ly>2) && (permute_slice) ) { assert(permute_type & RotateBit); permute_type_dist = permute_type|permute_slice; } else { permute_type_dist = permute_type; } } if ( permute_slice ) Copy_plane_permute(ret,rhs,dimension,x,sx,cbmask,permute_type_dist); else Copy_plane(ret,rhs,dimension,x,sx,cbmask); } } NAMESPACE_END(Grid);