mirror of
				https://github.com/paboyle/Grid.git
				synced 2025-10-31 03:54:33 +00:00 
			
		
		
		
	Eigen implementation and SYCL implementation
This commit is contained in:
		| @@ -89,9 +89,10 @@ public: | |||||||
|       gridblasHandle = theGridAccelerator; |       gridblasHandle = theGridAccelerator; | ||||||
| #endif | #endif | ||||||
| #ifdef GRID_ONE_MKL | #ifdef GRID_ONE_MKL | ||||||
|       cl::sycl::cpu_selector selector; |       cl::sycl::gpu_selector selector; | ||||||
|       cl::sycl::device selectedDevice { selector }; |       cl::sycl::device selectedDevice { selector }; | ||||||
|       gridblasHandle =new sycl::queue (selectedDevice); |       cl::sycl::property_list q_prop{cl::sycl::property::queue::in_order()}; | ||||||
|  |       gridblasHandle =new sycl::queue (selectedDevice,q_prop); | ||||||
| #endif | #endif | ||||||
|       gridblasInit=1; |       gridblasInit=1; | ||||||
|     } |     } | ||||||
| @@ -207,6 +208,9 @@ public: | |||||||
|     assert(Bkn.size()==batchCount); |     assert(Bkn.size()==batchCount); | ||||||
|     assert(Cmn.size()==batchCount); |     assert(Cmn.size()==batchCount); | ||||||
|  |  | ||||||
|  |     assert(OpA!=GridBLAS_OP_T); // Complex case expect no transpose | ||||||
|  |     assert(OpB!=GridBLAS_OP_T); | ||||||
|  |  | ||||||
|     int lda = m; // m x k column major |     int lda = m; // m x k column major | ||||||
|     int ldb = k; // k x n column major |     int ldb = k; // k x n column major | ||||||
|     int ldc = m; // m x b column major |     int ldc = m; // m x b column major | ||||||
| @@ -266,26 +270,131 @@ public: | |||||||
|     assert(err==CUBLAS_STATUS_SUCCESS); |     assert(err==CUBLAS_STATUS_SUCCESS); | ||||||
| #endif | #endif | ||||||
| #ifdef GRID_SYCL | #ifdef GRID_SYCL | ||||||
|     //MKL’s cblas_<T>gemm_batch & OneAPI |     //    std::cerr << " Calling SYCL batched ZGEMM "<<std::endl; | ||||||
| #warning "oneMKL implementation not built " |       int64_t m64=m; | ||||||
| #endif |       int64_t n64=n; | ||||||
| #if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP) |       int64_t k64=k; | ||||||
|     // Need a default/reference implementation |       int64_t lda64=lda; | ||||||
|     int sda = lda*k; |       int64_t ldb64=ldb; | ||||||
|     int sdb = ldb*k; |       int64_t ldc64=ldc; | ||||||
|     int sdc = ldc*n; |       int64_t batchCount64=batchCount; | ||||||
|     for (int p = 0; p < batchCount; ++p) { |  | ||||||
|  |       oneapi::mkl::transpose iOpA; | ||||||
|  |       oneapi::mkl::transpose iOpB; | ||||||
|  |        | ||||||
|  |       if ( OpA == GridBLAS_OP_N ) iOpA = oneapi::mkl::transpose::N; | ||||||
|  |       if ( OpA == GridBLAS_OP_T ) iOpA = oneapi::mkl::transpose::T; | ||||||
|  |       if ( OpA == GridBLAS_OP_C ) iOpA = oneapi::mkl::transpose::C; | ||||||
|  |       if ( OpB == GridBLAS_OP_N ) iOpB = oneapi::mkl::transpose::N; | ||||||
|  |       if ( OpB == GridBLAS_OP_T ) iOpB = oneapi::mkl::transpose::T; | ||||||
|  |       if ( OpB == GridBLAS_OP_C ) iOpB = oneapi::mkl::transpose::C; | ||||||
|  |  | ||||||
|  |       oneapi::mkl::blas::column_major::gemm_batch(*gridblasHandle, | ||||||
|  | 						  &iOpA, | ||||||
|  | 						  &iOpB, | ||||||
|  | 						  &m64,&n64,&k64, | ||||||
|  | 						  (ComplexD *) &alpha_p[0], | ||||||
|  | 						  (const ComplexD **)&Amk[0], (const int64_t *)&lda64, | ||||||
|  | 						  (const ComplexD **)&Bkn[0], (const int64_t *)&ldb64, | ||||||
|  | 						  (ComplexD *) &beta_p[0], | ||||||
|  | 						  (ComplexD **)&Cmn[0], (const int64_t *)&ldc64, | ||||||
|  | 						  (int64_t)1,&batchCount64,std::vector<sycl::event>()); | ||||||
|  |       synchronise(); | ||||||
|  | #if 0 | ||||||
|  |       // This code was used to check the mat mul on Sunspot/OneMKL | ||||||
|  |       std::cerr << " Called SYCL batched ZGEMM OpA "<< OpA << " OpB "<<OpB <<std::endl; | ||||||
|  |       std::vector<ComplexD> A(m*k);  // pointer list to matrices | ||||||
|  |       std::vector<ComplexD> B(k*n); | ||||||
|  |       std::vector<ComplexD> C(m*n); | ||||||
|  |       //      int sda = lda*k; | ||||||
|  |       //      int sdb = ldb*k; | ||||||
|  |       //      int sdc = ldc*n; | ||||||
|  |       std::cerr << " Checking the GEMM results "<<std::endl; | ||||||
|  |       for (int p = 0; p < 1; ++p) { | ||||||
|  | 	ComplexD * Amk_p;  // pointer list to matrices | ||||||
|  | 	ComplexD * Bkn_p;  // pointer list to matrices | ||||||
|  | 	ComplexD * Cmn_p;  // pointer list to matrices | ||||||
|  | 	acceleratorCopyFromDevice((void *)&Amk[p],(void *)&Amk_p,sizeof(ComplexD*)); | ||||||
|  | 	acceleratorCopyFromDevice((void *)&Bkn[p],(void *)&Bkn_p,sizeof(ComplexD*)); | ||||||
|  | 	acceleratorCopyFromDevice((void *)&Cmn[p],(void *)&Cmn_p,sizeof(ComplexD*)); | ||||||
|  | 	std::cerr << " p " << p << " copied pointers "<<std::endl; | ||||||
|  | 	acceleratorCopyFromDevice((void *)Amk_p,(void *)&A[0],m*k*sizeof(ComplexD)); | ||||||
|  | 	acceleratorCopyFromDevice((void *)Bkn_p,(void *)&B[0],k*n*sizeof(ComplexD)); | ||||||
|  | 	acceleratorCopyFromDevice((void *)Cmn_p,(void *)&C[0],m*n*sizeof(ComplexD)); | ||||||
|  | 	std::cerr << " p " << p << " copied matrices "<<std::endl; | ||||||
|  | 	std::cerr << " C[0] "<<C[0]<<std::endl; | ||||||
|  | 	std::cerr << " A[0] "<<A[0]<<std::endl; | ||||||
|  | 	std::cerr << " B[0] "<<B[0]<<std::endl; | ||||||
|  | 	std::cerr << " m "<<m<<std::endl; | ||||||
|  | 	std::cerr << " n "<<n<<std::endl; | ||||||
|  | 	std::cerr << " k "<<k<<std::endl; | ||||||
| 	for (int mm = 0; mm < m; ++mm) { | 	for (int mm = 0; mm < m; ++mm) { | ||||||
| 	  for (int nn = 0; nn < n; ++nn) { | 	  for (int nn = 0; nn < n; ++nn) { | ||||||
| 	    ComplexD c_mn(0.0); | 	    ComplexD c_mn(0.0); | ||||||
| 	  for (int kk = 0; kk < k; ++kk) | 	    for (int kk = 0; kk < k; ++kk) { | ||||||
| 	    c_mn += Amk[p][mm + kk*lda ] * Bkn[p][kk + nn*ldb]; | 	      int idx_a, idx_b; | ||||||
| 	  Cmn[p][mm + nn*ldc] =  (alpha)*c_mn + (beta)*Cmn[p][mm + nn*ldc ]; | 	      //    int lda = m; // m x k column major | ||||||
|  | 	      //    int ldb = k; // k x n column major | ||||||
|  | 	      //    int ldc = m; // m x b column major | ||||||
|  | 	      if(OpA!=GridBLAS_OP_N) { | ||||||
|  | 		idx_a =kk + mm*lda; | ||||||
|  | 	      } else { | ||||||
|  | 		idx_a =mm + kk*lda; | ||||||
|  | 	      } | ||||||
|  | 	      if(OpB!=GridBLAS_OP_N) { | ||||||
|  | 		idx_b =nn + kk*ldb; | ||||||
|  | 	      } else { | ||||||
|  | 		idx_b =kk + nn*ldb; | ||||||
|  | 	      } | ||||||
|  | 	      //	      std::cerr << " idx_a "<<idx_a<<" idx_b "<<idx_b<<std::endl; | ||||||
|  |  | ||||||
|  | 	      ComplexD Ac = A[idx_a]; | ||||||
|  | 	      ComplexD Bc = B[idx_b]; | ||||||
|  | 	      if(OpA==GridBLAS_OP_C) Ac = conjugate(Ac); | ||||||
|  | 	      if(OpB==GridBLAS_OP_C) Bc = conjugate(Bc); | ||||||
|  | 	       | ||||||
|  | 	      c_mn += Ac*Bc; | ||||||
|  | 	    } | ||||||
|  | 	    std::cerr << " beta "<<beta<<" alpha "<<alpha<<" C_"<<mm<<","<<nn<<" "<<c_mn<<" "<<C[mm + nn*ldc]<<std::endl; | ||||||
| 	  } | 	  } | ||||||
| 	} | 	} | ||||||
|       } |       } | ||||||
| #endif | #endif | ||||||
|     //    synchronise(); | #endif | ||||||
|  | #if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP) | ||||||
|  |     // Need a default/reference implementation; use Eigen | ||||||
|  |       if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_N) ) { | ||||||
|  | 	thread_for (p, batchCount, { | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eAmk(Amk[p],m,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eBkn(Bkn[p],k,n); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk * eBkn ; | ||||||
|  |         }); | ||||||
|  |       } else if ( (OpA == GridBLAS_OP_C ) && (OpB == GridBLAS_OP_N) ) { | ||||||
|  | 	thread_for (p, batchCount, { | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eAmk(Amk[p],k,m); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eBkn(Bkn[p],k,n); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk.adjoint() * eBkn ; | ||||||
|  | 	  }); | ||||||
|  |       } else if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_C) ) { | ||||||
|  | 	thread_for (p, batchCount, { | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eAmk(Amk[p],m,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eBkn(Bkn[p],n,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk * eBkn.adjoint() ; | ||||||
|  | 	  }); | ||||||
|  |       } else if ( (OpA == GridBLAS_OP_C ) && (OpB == GridBLAS_OP_C) ) { | ||||||
|  | 	thread_for (p, batchCount, { | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eAmk(Amk[p],k,m); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eBkn(Bkn[p],n,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcd> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk.adjoint() * eBkn.adjoint() ; | ||||||
|  | 	  } ); | ||||||
|  |       } else {  | ||||||
|  | 	assert(0); | ||||||
|  |       } | ||||||
|  | #endif | ||||||
|      RealD t1=usecond(); |      RealD t1=usecond(); | ||||||
|      RealD flops = 8.0*m*n*k*batchCount; |      RealD flops = 8.0*m*n*k*batchCount; | ||||||
|      RealD bytes = 1.0*sizeof(ComplexD)*(m*k+k*n+m*n)*batchCount; |      RealD bytes = 1.0*sizeof(ComplexD)*(m*k+k*n+m*n)*batchCount; | ||||||
| @@ -306,6 +415,9 @@ public: | |||||||
|     RealD t2=usecond(); |     RealD t2=usecond(); | ||||||
|     int32_t batchCount = Amk.size(); |     int32_t batchCount = Amk.size(); | ||||||
|  |  | ||||||
|  |     assert(OpA!=GridBLAS_OP_T); // Complex case expect no transpose | ||||||
|  |     assert(OpB!=GridBLAS_OP_T); | ||||||
|  |  | ||||||
|     int lda = m; // m x k column major |     int lda = m; // m x k column major | ||||||
|     int ldb = k; // k x n column major |     int ldb = k; // k x n column major | ||||||
|     int ldc = m; // m x b column major |     int ldc = m; // m x b column major | ||||||
| @@ -366,25 +478,68 @@ public: | |||||||
|     assert(err==CUBLAS_STATUS_SUCCESS); |     assert(err==CUBLAS_STATUS_SUCCESS); | ||||||
| #endif | #endif | ||||||
| #ifdef GRID_SYCL | #ifdef GRID_SYCL | ||||||
|     //MKL’s cblas_<T>gemm_batch & OneAPI |       int64_t m64=m; | ||||||
| #warning "oneMKL implementation not built " |       int64_t n64=n; | ||||||
|  |       int64_t k64=k; | ||||||
|  |       int64_t lda64=lda; | ||||||
|  |       int64_t ldb64=ldb; | ||||||
|  |       int64_t ldc64=ldc; | ||||||
|  |       int64_t batchCount64=batchCount; | ||||||
|  |  | ||||||
|  |       oneapi::mkl::transpose iOpA; | ||||||
|  |       oneapi::mkl::transpose iOpB; | ||||||
|  |        | ||||||
|  |       if ( OpA == GridBLAS_OP_N ) iOpA = oneapi::mkl::transpose::N; | ||||||
|  |       if ( OpA == GridBLAS_OP_T ) iOpA = oneapi::mkl::transpose::T; | ||||||
|  |       if ( OpA == GridBLAS_OP_C ) iOpA = oneapi::mkl::transpose::C; | ||||||
|  |       if ( OpB == GridBLAS_OP_N ) iOpB = oneapi::mkl::transpose::N; | ||||||
|  |       if ( OpB == GridBLAS_OP_T ) iOpB = oneapi::mkl::transpose::T; | ||||||
|  |       if ( OpB == GridBLAS_OP_C ) iOpB = oneapi::mkl::transpose::C; | ||||||
|  |  | ||||||
|  |       oneapi::mkl::blas::column_major::gemm_batch(*gridblasHandle, | ||||||
|  | 						  &iOpA, | ||||||
|  | 						  &iOpB, | ||||||
|  | 						  &m64,&n64,&k64, | ||||||
|  | 						  (ComplexF *) &alpha_p[0], | ||||||
|  | 						  (const ComplexF **)&Amk[0], (const int64_t *)&lda64, | ||||||
|  | 						  (const ComplexF **)&Bkn[0], (const int64_t *)&ldb64, | ||||||
|  | 						  (ComplexF *) &beta_p[0], | ||||||
|  | 						  (ComplexF **)&Cmn[0], (const int64_t *)&ldc64, | ||||||
|  | 						  (int64_t)1,&batchCount64,std::vector<sycl::event>()); | ||||||
|  |       synchronise(); | ||||||
| #endif | #endif | ||||||
| #if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP) | #if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP) | ||||||
|     int sda = lda*k; |     // Need a default/reference implementation; use Eigen | ||||||
|     int sdb = ldb*k; |       if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_N) ) { | ||||||
|     int sdc = ldc*n; | 	thread_for (p, batchCount, { | ||||||
|     ComplexF alphaf(real(alpha),imag(alpha)); | 	  Eigen::Map<Eigen::MatrixXcf> eAmk(Amk[p],m,k); | ||||||
|     ComplexF betaf(real(beta),imag(beta)); | 	  Eigen::Map<Eigen::MatrixXcf> eBkn(Bkn[p],k,n); | ||||||
|     // Need a default/reference implementation | 	  Eigen::Map<Eigen::MatrixXcf> eCmn(Cmn[p],m,n); | ||||||
|     for (int p = 0; p < batchCount; ++p) { | 	  eCmn = beta * eCmn + alpha * eAmk * eBkn ; | ||||||
|       for (int mm = 0; mm < m; ++mm) { | 	  }); | ||||||
| 	for (int nn = 0; nn < n; ++nn) { |       } else if ( (OpA == GridBLAS_OP_C ) && (OpB == GridBLAS_OP_N) ) { | ||||||
| 	  ComplexF c_mn(0.0); | 	thread_for (p, batchCount, { | ||||||
| 	  for (int kk = 0; kk < k; ++kk) | 	  Eigen::Map<Eigen::MatrixXcf> eAmk(Amk[p],k,m); | ||||||
| 	    c_mn += Amk[p][mm + kk*lda ] * Bkn[p][kk + nn*ldb]; | 	  Eigen::Map<Eigen::MatrixXcf> eBkn(Bkn[p],k,n); | ||||||
| 	  Cmn[p][mm + nn*ldc] =  (alphaf)*c_mn + (betaf)*Cmn[p][mm + nn*ldc ]; | 	  Eigen::Map<Eigen::MatrixXcf> eCmn(Cmn[p],m,n); | ||||||
| 	} | 	  eCmn = beta * eCmn + alpha * eAmk.adjoint() * eBkn ; | ||||||
|       } | 	  }); | ||||||
|  |       } else if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_C) ) { | ||||||
|  | 	thread_for (p, batchCount, { | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcf> eAmk(Amk[p],m,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcf> eBkn(Bkn[p],n,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcf> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk * eBkn.adjoint() ; | ||||||
|  | 	  }); | ||||||
|  |       } else if ( (OpA == GridBLAS_OP_C ) && (OpB == GridBLAS_OP_C) ) { | ||||||
|  | 	thread_for (p, batchCount, { | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcf> eAmk(Amk[p],k,m); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcf> eBkn(Bkn[p],n,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXcf> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk.adjoint() * eBkn.adjoint() ; | ||||||
|  | 	  } ); | ||||||
|  |       } else {  | ||||||
|  | 	assert(0); | ||||||
|       } |       } | ||||||
| #endif | #endif | ||||||
|      RealD t1=usecond(); |      RealD t1=usecond(); | ||||||
| @@ -408,6 +563,9 @@ public: | |||||||
|     RealD t2=usecond(); |     RealD t2=usecond(); | ||||||
|     int32_t batchCount = Amk.size(); |     int32_t batchCount = Amk.size(); | ||||||
|  |  | ||||||
|  |     assert(OpA!=GridBLAS_OP_C); // Real case no conjugate | ||||||
|  |     assert(OpB!=GridBLAS_OP_C); | ||||||
|  |  | ||||||
|     int lda = m; // m x k column major |     int lda = m; // m x k column major | ||||||
|     int ldb = k; // k x n column major |     int ldb = k; // k x n column major | ||||||
|     int ldc = m; // m x b column major |     int ldc = m; // m x b column major | ||||||
| @@ -467,23 +625,68 @@ public: | |||||||
|     assert(err==CUBLAS_STATUS_SUCCESS); |     assert(err==CUBLAS_STATUS_SUCCESS); | ||||||
| #endif | #endif | ||||||
| #ifdef GRID_SYCL | #ifdef GRID_SYCL | ||||||
|     //MKL’s cblas_<T>gemm_batch & OneAPI |       int64_t m64=m; | ||||||
| #warning "oneMKL implementation not built " |       int64_t n64=n; | ||||||
|  |       int64_t k64=k; | ||||||
|  |       int64_t lda64=lda; | ||||||
|  |       int64_t ldb64=ldb; | ||||||
|  |       int64_t ldc64=ldc; | ||||||
|  |       int64_t batchCount64=batchCount; | ||||||
|  |  | ||||||
|  |       oneapi::mkl::transpose iOpA; | ||||||
|  |       oneapi::mkl::transpose iOpB; | ||||||
|  |        | ||||||
|  |       if ( OpA == GridBLAS_OP_N ) iOpA = oneapi::mkl::transpose::N; | ||||||
|  |       if ( OpA == GridBLAS_OP_T ) iOpA = oneapi::mkl::transpose::T; | ||||||
|  |       if ( OpA == GridBLAS_OP_C ) iOpA = oneapi::mkl::transpose::C; | ||||||
|  |       if ( OpB == GridBLAS_OP_N ) iOpB = oneapi::mkl::transpose::N; | ||||||
|  |       if ( OpB == GridBLAS_OP_T ) iOpB = oneapi::mkl::transpose::T; | ||||||
|  |       if ( OpB == GridBLAS_OP_C ) iOpB = oneapi::mkl::transpose::C; | ||||||
|  |  | ||||||
|  |       oneapi::mkl::blas::column_major::gemm_batch(*gridblasHandle, | ||||||
|  | 						  &iOpA, | ||||||
|  | 						  &iOpB, | ||||||
|  | 						  &m64,&n64,&k64, | ||||||
|  | 						  (float *) &alpha_p[0], | ||||||
|  | 						  (const float **)&Amk[0], (const int64_t *)&lda64, | ||||||
|  | 						  (const float **)&Bkn[0], (const int64_t *)&ldb64, | ||||||
|  | 						  (float *) &beta_p[0], | ||||||
|  | 						  (float **)&Cmn[0], (const int64_t *)&ldc64, | ||||||
|  | 						  (int64_t)1,&batchCount64,std::vector<sycl::event>()); | ||||||
|  |       synchronise(); | ||||||
| #endif | #endif | ||||||
| #if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP) | #if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP) | ||||||
|     int sda = lda*k; |     // Need a default/reference implementation; use Eigen | ||||||
|     int sdb = ldb*k; |       if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_N) ) { | ||||||
|     int sdc = ldc*n; | 	thread_for (p, batchCount, { | ||||||
|     // Need a default/reference implementation | 	  Eigen::Map<Eigen::MatrixXf> eAmk(Amk[p],m,k); | ||||||
|     for (int p = 0; p < batchCount; ++p) { | 	  Eigen::Map<Eigen::MatrixXf> eBkn(Bkn[p],k,n); | ||||||
|       for (int mm = 0; mm < m; ++mm) { | 	  Eigen::Map<Eigen::MatrixXf> eCmn(Cmn[p],m,n); | ||||||
| 	for (int nn = 0; nn < n; ++nn) { | 	  eCmn = beta * eCmn + alpha * eAmk * eBkn ; | ||||||
| 	  RealD c_mn(0.0); | 	  }); | ||||||
| 	  for (int kk = 0; kk < k; ++kk) |       } else if ( (OpA == GridBLAS_OP_T ) && (OpB == GridBLAS_OP_N) ) { | ||||||
| 	    c_mn += Amk[p][mm + kk*lda ] * Bkn[p][kk + nn*ldb]; | 	thread_for (p, batchCount, { | ||||||
| 	  Cmn[p][mm + nn*ldc] =  (alpha)*c_mn + (beta)*Cmn[p][mm + nn*ldc ]; | 	  Eigen::Map<Eigen::MatrixXf> eAmk(Amk[p],k,m); | ||||||
| 	} | 	  Eigen::Map<Eigen::MatrixXf> eBkn(Bkn[p],k,n); | ||||||
|       } | 	  Eigen::Map<Eigen::MatrixXf> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk.transpose() * eBkn ; | ||||||
|  | 	  }); | ||||||
|  |       } else if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_T) ) { | ||||||
|  | 	thread_for (p, batchCount, { | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXf> eAmk(Amk[p],m,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXf> eBkn(Bkn[p],n,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXf> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk * eBkn.transpose() ; | ||||||
|  | 	  }); | ||||||
|  |       } else if ( (OpA == GridBLAS_OP_T ) && (OpB == GridBLAS_OP_T) ) { | ||||||
|  | 	thread_for (p, batchCount, { | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXf> eAmk(Amk[p],k,m); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXf> eBkn(Bkn[p],n,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXf> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk.transpose() * eBkn.transpose() ; | ||||||
|  | 	  } ); | ||||||
|  |       } else {  | ||||||
|  | 	assert(0); | ||||||
|       } |       } | ||||||
| #endif | #endif | ||||||
|      RealD t1=usecond(); |      RealD t1=usecond(); | ||||||
| @@ -495,7 +698,6 @@ public: | |||||||
|   /////////////////////////////////////////////////////////////////////////// |   /////////////////////////////////////////////////////////////////////////// | ||||||
|   // Double precision real GEMM |   // Double precision real GEMM | ||||||
|   /////////////////////////////////////////////////////////////////////////// |   /////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|   void gemmBatched(GridBLASOperation_t OpA, |   void gemmBatched(GridBLASOperation_t OpA, | ||||||
| 		   GridBLASOperation_t OpB, | 		   GridBLASOperation_t OpB, | ||||||
| 		   int m,int n, int k, | 		   int m,int n, int k, | ||||||
| @@ -508,6 +710,9 @@ public: | |||||||
|     RealD t2=usecond(); |     RealD t2=usecond(); | ||||||
|     int32_t batchCount = Amk.size(); |     int32_t batchCount = Amk.size(); | ||||||
|  |  | ||||||
|  |     assert(OpA!=GridBLAS_OP_C); // Real case no conjugate | ||||||
|  |     assert(OpB!=GridBLAS_OP_C); | ||||||
|  |  | ||||||
|     int lda = m; // m x k column major |     int lda = m; // m x k column major | ||||||
|     int ldb = k; // k x n column major |     int ldb = k; // k x n column major | ||||||
|     int ldc = m; // m x b column major |     int ldc = m; // m x b column major | ||||||
| @@ -568,39 +773,68 @@ public: | |||||||
|     assert(err==CUBLAS_STATUS_SUCCESS); |     assert(err==CUBLAS_STATUS_SUCCESS); | ||||||
| #endif | #endif | ||||||
| #ifdef GRID_SYCL | #ifdef GRID_SYCL | ||||||
|     /* |  | ||||||
|       int64_t m64=m; |       int64_t m64=m; | ||||||
|       int64_t n64=n; |       int64_t n64=n; | ||||||
|       int64_t k64=k; |       int64_t k64=k; | ||||||
|  |       int64_t lda64=lda; | ||||||
|  |       int64_t ldb64=ldb; | ||||||
|  |       int64_t ldc64=ldc; | ||||||
|       int64_t batchCount64=batchCount; |       int64_t batchCount64=batchCount; | ||||||
|       oneapi::mkl::blas::column_major::gemm_batch(*theGridAccelerator, |  | ||||||
|       onemkl::transpose::N, |       oneapi::mkl::transpose iOpA; | ||||||
|       onemkl::transpose::N, |       oneapi::mkl::transpose iOpB; | ||||||
|  |        | ||||||
|  |       if ( OpA == GridBLAS_OP_N ) iOpA = oneapi::mkl::transpose::N; | ||||||
|  |       if ( OpA == GridBLAS_OP_T ) iOpA = oneapi::mkl::transpose::T; | ||||||
|  |       if ( OpA == GridBLAS_OP_C ) iOpA = oneapi::mkl::transpose::C; | ||||||
|  |       if ( OpB == GridBLAS_OP_N ) iOpB = oneapi::mkl::transpose::N; | ||||||
|  |       if ( OpB == GridBLAS_OP_T ) iOpB = oneapi::mkl::transpose::T; | ||||||
|  |       if ( OpB == GridBLAS_OP_C ) iOpB = oneapi::mkl::transpose::C; | ||||||
|  |  | ||||||
|  |       oneapi::mkl::blas::column_major::gemm_batch(*gridblasHandle, | ||||||
|  | 						  &iOpA, | ||||||
|  | 						  &iOpB, | ||||||
| 						  &m64,&n64,&k64, | 						  &m64,&n64,&k64, | ||||||
| 						  (double *) &alpha_p[0], | 						  (double *) &alpha_p[0], | ||||||
|       (double **)&Amk[0], lda, | 						  (const double **)&Amk[0], (const int64_t *)&lda64, | ||||||
|       (double **)&Bkn[0], ldb, | 						  (const double **)&Bkn[0], (const int64_t *)&ldb64, | ||||||
| 						  (double *) &beta_p[0], | 						  (double *) &beta_p[0], | ||||||
|       (double **)&Cmn[0], ldc, | 						  (double **)&Cmn[0], (const int64_t *)&ldc64, | ||||||
|       1,&batchCount64); | 						  (int64_t)1,&batchCount64,std::vector<sycl::event>()); | ||||||
|      */ |       synchronise(); | ||||||
|     //MKL’s cblas_<T>gemm_batch & OneAPI |  | ||||||
| #warning "oneMKL implementation not built " |  | ||||||
| #endif | #endif | ||||||
| #if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP) | #if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP) | ||||||
|     int sda = lda*k; |     // Need a default/reference implementation; use Eigen | ||||||
|     int sdb = ldb*k; |       if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_N) ) { | ||||||
|     int sdc = ldc*n; | 	thread_for (p, batchCount, { | ||||||
|     // Need a default/reference implementation | 	  Eigen::Map<Eigen::MatrixXd> eAmk(Amk[p],m,k); | ||||||
|     for (int p = 0; p < batchCount; ++p) { | 	  Eigen::Map<Eigen::MatrixXd> eBkn(Bkn[p],k,n); | ||||||
|       for (int mm = 0; mm < m; ++mm) { | 	  Eigen::Map<Eigen::MatrixXd> eCmn(Cmn[p],m,n); | ||||||
| 	for (int nn = 0; nn < n; ++nn) { | 	  eCmn = beta * eCmn + alpha * eAmk * eBkn ; | ||||||
| 	  RealD c_mn(0.0); | 	  }); | ||||||
| 	  for (int kk = 0; kk < k; ++kk) |       } else if ( (OpA == GridBLAS_OP_T ) && (OpB == GridBLAS_OP_N) ) { | ||||||
| 	    c_mn += Amk[p][mm + kk*lda ] * Bkn[p][kk + nn*ldb]; | 	thread_for (p, batchCount, { | ||||||
| 	  Cmn[p][mm + nn*ldc] =  (alpha)*c_mn + (beta)*Cmn[p][mm + nn*ldc ]; | 	  Eigen::Map<Eigen::MatrixXd> eAmk(Amk[p],k,m); | ||||||
| 	} | 	  Eigen::Map<Eigen::MatrixXd> eBkn(Bkn[p],k,n); | ||||||
|       } | 	  Eigen::Map<Eigen::MatrixXd> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk.transpose() * eBkn ; | ||||||
|  | 	  }); | ||||||
|  |       } else if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_T) ) { | ||||||
|  | 	thread_for (p, batchCount, { | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXd> eAmk(Amk[p],m,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXd> eBkn(Bkn[p],n,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXd> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk * eBkn.transpose() ; | ||||||
|  | 	  }); | ||||||
|  |       } else if ( (OpA == GridBLAS_OP_T ) && (OpB == GridBLAS_OP_T) ) { | ||||||
|  | 	thread_for (p, batchCount, { | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXd> eAmk(Amk[p],k,m); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXd> eBkn(Bkn[p],n,k); | ||||||
|  | 	  Eigen::Map<Eigen::MatrixXd> eCmn(Cmn[p],m,n); | ||||||
|  | 	  eCmn = beta * eCmn + alpha * eAmk.transpose() * eBkn.transpose() ; | ||||||
|  | 	  }); | ||||||
|  |       } else {  | ||||||
|  | 	assert(0); | ||||||
|       } |       } | ||||||
| #endif | #endif | ||||||
|      RealD t1=usecond(); |      RealD t1=usecond(); | ||||||
| @@ -608,120 +842,46 @@ public: | |||||||
|      RealD bytes = 1.0*sizeof(RealD)*(m*k+k*n+m*n)*batchCount; |      RealD bytes = 1.0*sizeof(RealD)*(m*k+k*n+m*n)*batchCount; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   template<class CComplex> | ||||||
|    |  | ||||||
|   //////////////////////////////////////////////////////////////////////////////////////////////// |  | ||||||
|   // Strided case used by benchmark, but generally unused in Grid |  | ||||||
|   // Keep a code example in double complex, but don't generate the single and real variants for now |  | ||||||
|   //////////////////////////////////////////////////////////////////////////////////////////////// |  | ||||||
|    |  | ||||||
|   void gemmStridedBatched(int m,int n, int k, |  | ||||||
| 			  ComplexD alpha, |  | ||||||
| 			  ComplexD* Amk,  // pointer list to matrices |  | ||||||
| 			  ComplexD* Bkn, |  | ||||||
| 			  ComplexD beta, |  | ||||||
| 			  ComplexD* Cmn, |  | ||||||
| 			  int batchCount) |  | ||||||
|   { |  | ||||||
|     // Use C-row major storage, so transpose calls |  | ||||||
|     int lda = m; // m x k column major |  | ||||||
|     int ldb = k; // k x n column major |  | ||||||
|     int ldc = m; // m x b column major |  | ||||||
|     int sda = m*k; |  | ||||||
|     int sdb = k*n; |  | ||||||
|     int sdc = m*n; |  | ||||||
|     deviceVector<ComplexD> alpha_p(1); |  | ||||||
|     deviceVector<ComplexD> beta_p(1); |  | ||||||
|     acceleratorCopyToDevice((void *)&alpha,(void *)&alpha_p[0],sizeof(ComplexD)); |  | ||||||
|     acceleratorCopyToDevice((void *)&beta ,(void *)&beta_p[0],sizeof(ComplexD)); |  | ||||||
|     //    std::cout << "blasZgemmStridedBatched mnk  "<<m<<","<<n<<","<<k<<" count "<<batchCount<<std::endl; |  | ||||||
|     //    std::cout << "blasZgemmStridedBatched ld   "<<lda<<","<<ldb<<","<<ldc<<std::endl; |  | ||||||
|     //    std::cout << "blasZgemmStridedBatched sd   "<<sda<<","<<sdb<<","<<sdc<<std::endl; |  | ||||||
| #ifdef GRID_HIP |  | ||||||
|     auto err = hipblasZgemmStridedBatched(gridblasHandle, |  | ||||||
| 					  HIPBLAS_OP_N, |  | ||||||
| 					  HIPBLAS_OP_N, |  | ||||||
| 					  m,n,k, |  | ||||||
| 					  (hipblasDoubleComplex *) &alpha_p[0], |  | ||||||
| 					  (hipblasDoubleComplex *) Amk, lda, sda, |  | ||||||
| 					  (hipblasDoubleComplex *) Bkn, ldb, sdb, |  | ||||||
| 					  (hipblasDoubleComplex *) &beta_p[0], |  | ||||||
| 					  (hipblasDoubleComplex *) Cmn, ldc, sdc, |  | ||||||
| 					  batchCount); |  | ||||||
|     assert(err==HIPBLAS_STATUS_SUCCESS); |  | ||||||
| #endif |  | ||||||
| #ifdef GRID_CUDA |  | ||||||
|     cublasZgemmStridedBatched(gridblasHandle, |  | ||||||
| 			      CUBLAS_OP_N, |  | ||||||
| 			      CUBLAS_OP_N, |  | ||||||
| 			      m,n,k, |  | ||||||
| 			      (cuDoubleComplex *) &alpha_p[0], |  | ||||||
| 			      (cuDoubleComplex *) Amk, lda, sda, |  | ||||||
| 			      (cuDoubleComplex *) Bkn, ldb, sdb, |  | ||||||
| 			      (cuDoubleComplex *) &beta_p[0], |  | ||||||
| 			      (cuDoubleComplex *) Cmn, ldc, sdc, |  | ||||||
| 			      batchCount); |  | ||||||
| #endif |  | ||||||
| #if defined(GRID_SYCL) || defined(GRID_ONE_MKL) |  | ||||||
|     oneapi::mkl::blas::column_major::gemm_batch(*gridblasHandle, |  | ||||||
| 						oneapi::mkl::transpose::N, |  | ||||||
| 						oneapi::mkl::transpose::N, |  | ||||||
| 						m,n,k, |  | ||||||
| 						alpha, |  | ||||||
| 						(const ComplexD *)Amk,lda,sda, |  | ||||||
| 						(const ComplexD *)Bkn,ldb,sdb, |  | ||||||
| 						beta, |  | ||||||
| 						(ComplexD *)Cmn,ldc,sdc, |  | ||||||
| 						batchCount); |  | ||||||
| #endif |  | ||||||
| #if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP) && !defined(GRID_ONE_MKL) |  | ||||||
|      // Need a default/reference implementation |  | ||||||
|      for (int p = 0; p < batchCount; ++p) { |  | ||||||
|        for (int mm = 0; mm < m; ++mm) { |  | ||||||
| 	 for (int nn = 0; nn < n; ++nn) { |  | ||||||
| 	   ComplexD c_mn(0.0); |  | ||||||
| 	   for (int kk = 0; kk < k; ++kk) |  | ||||||
| 	     c_mn += Amk[mm + kk*lda + p*sda] * Bkn[kk + nn*ldb + p*sdb]; |  | ||||||
| 	   Cmn[mm + nn*ldc + p*sdc] =  (alpha)*c_mn + (beta)*Cmn[mm + nn*ldc + p*sdc]; |  | ||||||
| 	 } |  | ||||||
|        } |  | ||||||
|      } |  | ||||||
| #endif |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   double benchmark(int M, int N, int K, int BATCH) |   double benchmark(int M, int N, int K, int BATCH) | ||||||
|   { |   { | ||||||
|     int32_t N_A = M*K*BATCH; |     int32_t N_A = M*K*BATCH; | ||||||
|     int32_t N_B = K*N*BATCH; |     int32_t N_B = K*N*BATCH; | ||||||
|     int32_t N_C = M*N*BATCH; |     int32_t N_C = M*N*BATCH; | ||||||
|     deviceVector<ComplexD> A(N_A); acceleratorMemSet(&A[0],0,N_A*sizeof(ComplexD)); |     deviceVector<CComplex> A(N_A); acceleratorMemSet(&A[0],0,N_A*sizeof(CComplex)); | ||||||
|     deviceVector<ComplexD> B(N_B); acceleratorMemSet(&B[0],0,N_B*sizeof(ComplexD)); |     deviceVector<CComplex> B(N_B); acceleratorMemSet(&B[0],0,N_B*sizeof(CComplex)); | ||||||
|     deviceVector<ComplexD> C(N_C); acceleratorMemSet(&C[0],0,N_C*sizeof(ComplexD)); |     deviceVector<CComplex> C(N_C); acceleratorMemSet(&C[0],0,N_C*sizeof(CComplex)); | ||||||
|     ComplexD alpha(1.0); |     CComplex alpha(1.0); | ||||||
|     ComplexD beta (1.0); |     CComplex beta (1.0); | ||||||
|     RealD flops = 8.0*M*N*K*BATCH; |     RealD flops = 8.0*M*N*K*BATCH; | ||||||
|     int ncall=10; |     int ncall=10; | ||||||
|     RealD t0 = usecond(); |     RealD t0 = usecond(); | ||||||
|  |     deviceVector<CComplex *> As(BATCH); | ||||||
|  |     deviceVector<CComplex *> Bs(BATCH); | ||||||
|  |     deviceVector<CComplex *> Cs(BATCH); | ||||||
|  |     for(int b = 0 ; b < BATCH;b++) { | ||||||
|  |       CComplex *ptr; | ||||||
|  |       ptr = &A[b*M*K];      acceleratorPut(As[b],ptr); | ||||||
|  |       ptr = &B[b*K*N];      acceleratorPut(Bs[b],ptr); | ||||||
|  |       ptr = &C[b*M*N];      acceleratorPut(Cs[b],ptr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     for(int i=0;i<ncall;i++){ |     for(int i=0;i<ncall;i++){ | ||||||
|       gemmStridedBatched(M,N,K, |       gemmBatched(M,N,K, | ||||||
| 		  alpha, | 		  alpha, | ||||||
| 			 &A[0], // m x k  | 		  As, // m x k  | ||||||
| 			 &B[0], // k x n | 		  Bs, // k x n | ||||||
| 		  beta,  | 		  beta,  | ||||||
| 			 &C[0], // m x n | 		  Cs); | ||||||
| 			 BATCH); |  | ||||||
|     } |     } | ||||||
|     synchronise(); |     synchronise(); | ||||||
|     RealD t1 = usecond(); |     RealD t1 = usecond(); | ||||||
|     RealD bytes = 1.0*sizeof(ComplexD)*(M*N*2+N*K+M*K)*BATCH; |     RealD bytes = 1.0*sizeof(CComplex)*(M*N*2+N*K+M*K)*BATCH; | ||||||
|     flops = 8.0*M*N*K*BATCH*ncall; |     flops = 8.0*M*N*K*BATCH*ncall; | ||||||
|     flops = flops/(t1-t0)/1.e3; |     flops = flops/(t1-t0)/1.e3; | ||||||
|     return flops; // Returns gigaflops |     return flops; // Returns gigaflops | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| NAMESPACE_END(Grid); | NAMESPACE_END(Grid); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user