-
Notifications
You must be signed in to change notification settings - Fork 57
Add LTimes tuning to represent Kripke LTimes #684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
7bdc07f
7a794c7
1147a77
d2f79aa
6c6c9de
351f2d8
3edfc3b
2037b48
dfb8ab5
02f78bc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,27 +27,60 @@ using namespace ltimes_idx; | |
| // | ||
| // Define thread block shape for CUDA execution | ||
| // | ||
| #define m_block_sz (32) | ||
| #define g_block_sz (integer::greater_of_squarest_factor_pair(block_size/m_block_sz)) | ||
| #define z_block_sz (integer::lesser_of_squarest_factor_pair(block_size/m_block_sz)) | ||
| #define block_moments_m_block_sz (block_size) | ||
| #define block_moments_g_block_sz (1) | ||
| #define block_moments_z_block_sz (1) | ||
|
|
||
| #define LTIMES_THREADS_PER_BLOCK_TEMPLATE_PARAMS_CUDA \ | ||
| m_block_sz, g_block_sz, z_block_sz | ||
| #define LTIMES_BLOCK_MOMENTS_THREADS_PER_BLOCK_TEMPLATE_PARAMS_CUDA \ | ||
| block_moments_m_block_sz, block_moments_g_block_sz, block_moments_z_block_sz | ||
|
|
||
| #define LTIMES_THREADS_PER_BLOCK_CUDA \ | ||
| dim3 nthreads_per_block(LTIMES_THREADS_PER_BLOCK_TEMPLATE_PARAMS_CUDA); \ | ||
| static_assert(m_block_sz*g_block_sz*z_block_sz == block_size, "Invalid block_size"); | ||
| #define LTIMES_BLOCK_MOMENTS_THREADS_PER_BLOCK_CUDA \ | ||
| dim3 nthreads_per_block(LTIMES_BLOCK_MOMENTS_THREADS_PER_BLOCK_TEMPLATE_PARAMS_CUDA); \ | ||
| static_assert(block_moments_m_block_sz*block_moments_g_block_sz*block_moments_z_block_sz == block_size, "Invalid block_size"); | ||
|
|
||
| #define LTIMES_NBLOCKS_CUDA \ | ||
| dim3 nblocks(static_cast<size_t>(RAJA_DIVIDE_CEILING_INT(*num_m, m_block_sz)), \ | ||
| static_cast<size_t>(RAJA_DIVIDE_CEILING_INT(*num_g, g_block_sz)), \ | ||
| static_cast<size_t>(RAJA_DIVIDE_CEILING_INT(*num_z, z_block_sz))); | ||
| #define LTIMES_BLOCK_MOMENTS_NBLOCKS_CUDA \ | ||
| dim3 nblocks(static_cast<size_t>(*num_z), \ | ||
| static_cast<size_t>(*num_g), \ | ||
| 1); | ||
|
|
||
| #define factorized_m_block_sz (32) | ||
| #define factorized_g_block_sz (integer::greater_of_squarest_factor_pair(block_size/factorized_m_block_sz)) | ||
| #define factorized_z_block_sz (integer::lesser_of_squarest_factor_pair(block_size/factorized_m_block_sz)) | ||
|
|
||
| #define LTIMES_FACTORIZED_THREADS_PER_BLOCK_TEMPLATE_PARAMS_CUDA \ | ||
| factorized_m_block_sz, factorized_g_block_sz, factorized_z_block_sz | ||
|
|
||
| #define LTIMES_FACTORIZED_THREADS_PER_BLOCK_CUDA \ | ||
| dim3 nthreads_per_block(LTIMES_FACTORIZED_THREADS_PER_BLOCK_TEMPLATE_PARAMS_CUDA); \ | ||
| static_assert(factorized_m_block_sz*factorized_g_block_sz*factorized_z_block_sz == block_size, "Invalid block_size"); | ||
|
|
||
| #define LTIMES_FACTORIZED_NBLOCKS_CUDA \ | ||
| dim3 nblocks(static_cast<size_t>(RAJA_DIVIDE_CEILING_INT(*num_m, factorized_m_block_sz)), \ | ||
| static_cast<size_t>(RAJA_DIVIDE_CEILING_INT(*num_g, factorized_g_block_sz)), \ | ||
| static_cast<size_t>(RAJA_DIVIDE_CEILING_INT(*num_z, factorized_z_block_sz))); | ||
|
|
||
|
|
||
| template < size_t block_size > | ||
| __launch_bounds__(block_size) | ||
| __global__ void ltimes_block_moments(PHI_VIEW phi, ELL_VIEW ell, PSI_VIEW psi, | ||
| ID num_d, IM num_m, IG num_g, IZ num_z) | ||
| { | ||
| IG g(blockIdx.y); | ||
| IZ z(blockIdx.x); | ||
|
|
||
| if (g < num_g && z < num_z) { | ||
| for (IM m(threadIdx.x); m < num_m; m += block_size) { | ||
| for (ID d(0); d < num_d; ++d ) { | ||
| LTIMES_BODY; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| template < size_t m_block_size, size_t g_block_size, size_t z_block_size > | ||
| __launch_bounds__(m_block_size*g_block_size*z_block_size) | ||
| __global__ void ltimes(PHI_VIEW phi, ELL_VIEW ell, PSI_VIEW psi, | ||
| ID num_d, IM num_m, IG num_g, IZ num_z) | ||
| __global__ void ltimes_factorized(PHI_VIEW phi, ELL_VIEW ell, PSI_VIEW psi, | ||
| ID num_d, IM num_m, IG num_g, IZ num_z) | ||
| { | ||
| IM m(blockIdx.x * m_block_size + threadIdx.x); | ||
| IG g(blockIdx.y * g_block_size + threadIdx.y); | ||
|
|
@@ -60,10 +93,25 @@ __global__ void ltimes(PHI_VIEW phi, ELL_VIEW ell, PSI_VIEW psi, | |
| } | ||
| } | ||
|
|
||
| template < size_t block_size, typename Lambda > | ||
| __launch_bounds__(block_size) | ||
| __global__ void ltimes_lam_block_moments(IM num_m, IG num_g, IZ num_z, | ||
| Lambda body) | ||
| { | ||
| IG g(blockIdx.y); | ||
| IZ z(blockIdx.x); | ||
|
|
||
| if (g < num_g && z < num_z) { | ||
| for (IM m(threadIdx.x); m < num_m; m += block_size) { | ||
| body(z, g, m); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| template < size_t m_block_size, size_t g_block_size, size_t z_block_size, typename Lambda > | ||
| __launch_bounds__(m_block_size*g_block_size*z_block_size) | ||
| __global__ void ltimes_lam(IM num_m, IG num_g, IZ num_z, | ||
| Lambda body) | ||
| __global__ void ltimes_lam_factorized(IM num_m, IG num_g, IZ num_z, | ||
| Lambda body) | ||
| { | ||
| IM m(blockIdx.x * m_block_size + threadIdx.x); | ||
| IG g(blockIdx.y * g_block_size + threadIdx.y); | ||
|
|
@@ -92,16 +140,29 @@ void LTIMES::runCudaVariantImpl(VariantID vid) | |
| // Loop counter increment uses macro to quiet C++20 compiler warning | ||
| for (RepIndex_type irep = 0; irep < run_reps; RP_REPCOUNTINC(irep)) { | ||
|
|
||
| LTIMES_THREADS_PER_BLOCK_CUDA; | ||
| LTIMES_NBLOCKS_CUDA; | ||
| constexpr size_t shmem = 0; | ||
|
|
||
| RPlaunchCudaKernel( | ||
| (ltimes<LTIMES_THREADS_PER_BLOCK_TEMPLATE_PARAMS_CUDA>), | ||
| nblocks, nthreads_per_block, | ||
| shmem, res.get_stream(), | ||
| phi, ell, psi, | ||
| num_d, num_m, num_g, num_z ); | ||
| if constexpr (tune_idx == 1) { | ||
| LTIMES_FACTORIZED_THREADS_PER_BLOCK_CUDA; | ||
| LTIMES_FACTORIZED_NBLOCKS_CUDA; | ||
|
|
||
| RPlaunchCudaKernel( | ||
| (ltimes_factorized<LTIMES_FACTORIZED_THREADS_PER_BLOCK_TEMPLATE_PARAMS_CUDA>), | ||
| nblocks, nthreads_per_block, | ||
| shmem, res.get_stream(), | ||
| phi, ell, psi, | ||
| num_d, num_m, num_g, num_z ); | ||
| } else { | ||
| LTIMES_BLOCK_MOMENTS_THREADS_PER_BLOCK_CUDA; | ||
| LTIMES_BLOCK_MOMENTS_NBLOCKS_CUDA; | ||
|
|
||
| RPlaunchCudaKernel( | ||
| (ltimes_block_moments<block_size>), | ||
| nblocks, nthreads_per_block, | ||
| shmem, res.get_stream(), | ||
| phi, ell, psi, | ||
| num_d, num_m, num_g, num_z ); | ||
| } | ||
|
|
||
| } | ||
| stopTimer(); | ||
|
|
@@ -118,17 +179,30 @@ void LTIMES::runCudaVariantImpl(VariantID vid) | |
| } | ||
| }; | ||
|
|
||
| LTIMES_THREADS_PER_BLOCK_CUDA; | ||
| LTIMES_NBLOCKS_CUDA; | ||
| constexpr size_t shmem = 0; | ||
|
|
||
| RPlaunchCudaKernel( | ||
| (ltimes_lam<LTIMES_THREADS_PER_BLOCK_TEMPLATE_PARAMS_CUDA, | ||
| decltype(ltimes_lambda)>), | ||
| nblocks, nthreads_per_block, | ||
| shmem, res.get_stream(), | ||
| num_m, num_g, num_z, | ||
| ltimes_lambda ); | ||
| if constexpr (tune_idx == 1) { | ||
| LTIMES_FACTORIZED_THREADS_PER_BLOCK_CUDA; | ||
| LTIMES_FACTORIZED_NBLOCKS_CUDA; | ||
|
|
||
| RPlaunchCudaKernel( | ||
| (ltimes_lam_factorized<LTIMES_FACTORIZED_THREADS_PER_BLOCK_TEMPLATE_PARAMS_CUDA, | ||
| decltype(ltimes_lambda)>), | ||
| nblocks, nthreads_per_block, | ||
| shmem, res.get_stream(), | ||
| num_m, num_g, num_z, | ||
| ltimes_lambda ); | ||
| } else { | ||
| LTIMES_BLOCK_MOMENTS_THREADS_PER_BLOCK_CUDA; | ||
| LTIMES_BLOCK_MOMENTS_NBLOCKS_CUDA; | ||
|
|
||
| RPlaunchCudaKernel( | ||
| (ltimes_lam_block_moments<block_size, decltype(ltimes_lambda)>), | ||
| nblocks, nthreads_per_block, | ||
| shmem, res.get_stream(), | ||
| num_m, num_g, num_z, | ||
| ltimes_lambda ); | ||
| } | ||
|
|
||
| } | ||
| stopTimer(); | ||
|
|
@@ -139,10 +213,10 @@ void LTIMES::runCudaVariantImpl(VariantID vid) | |
|
|
||
| using EXEC_POL = | ||
| RAJA::KernelPolicy< | ||
| RAJA::statement::CudaKernelFixedAsync<m_block_sz*g_block_sz*z_block_sz, | ||
| RAJA::statement::For<1, RAJA::cuda_global_size_z_direct<z_block_sz>, //z | ||
| RAJA::statement::For<2, RAJA::cuda_global_size_y_direct<g_block_sz>, //g | ||
| RAJA::statement::For<3, RAJA::cuda_global_size_x_direct<m_block_sz>, //m | ||
| RAJA::statement::CudaKernelAsync< | ||
| RAJA::statement::For<1, RAJA::cuda_block_x_loop, // z | ||
| RAJA::statement::For<2, RAJA::cuda_block_y_loop, // g | ||
| RAJA::statement::For<3, RAJA::cuda_thread_x_loop, // m | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume this is a non-size loop policy because it is in ltimes. Here we know the block size at compile time, is that also true in kripke?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Kripke, the block sizes are determined by parameters passed in at runtime. For example, like in this version of LTimes, it will be blocked on zones and groups. The exact parameters which will be blocked are not always the same for each Kripke run. For instance, if we use the DZG layout at runtime, then the loops will be blocked with directions and zones (while groups are threaded). |
||
| RAJA::statement::For<0, RAJA::seq_exec, //d | ||
| RAJA::statement::Lambda<0> | ||
| > | ||
|
|
@@ -172,31 +246,114 @@ void LTIMES::runCudaVariantImpl(VariantID vid) | |
|
|
||
| } else if constexpr (tune_idx == 1) { | ||
|
|
||
| using EXEC_POL = | ||
| RAJA::KernelPolicy< | ||
| RAJA::statement::CudaKernelFixedAsync<factorized_m_block_sz*factorized_g_block_sz*factorized_z_block_sz, | ||
| RAJA::statement::For<1, RAJA::cuda_global_size_z_direct<factorized_z_block_sz>, // z | ||
| RAJA::statement::For<2, RAJA::cuda_global_size_y_direct<factorized_g_block_sz>, // g | ||
| RAJA::statement::For<3, RAJA::cuda_global_size_x_direct<factorized_m_block_sz>, // m | ||
| RAJA::statement::For<0, RAJA::seq_exec, // d | ||
| RAJA::statement::Lambda<0> | ||
| > | ||
| > | ||
| > | ||
| > | ||
| > | ||
| >; | ||
|
|
||
| startTimer(); | ||
| // Loop counter increment uses macro to quiet C++20 compiler warning | ||
| for (RepIndex_type irep = 0; irep < run_reps; RP_REPCOUNTINC(irep)) { | ||
|
|
||
| RAJA::kernel_resource<EXEC_POL>( | ||
| RAJA::make_tuple(IDRange(0, *num_d), | ||
| IZRange(0, *num_z), | ||
| IGRange(0, *num_g), | ||
| IMRange(0, *num_m)), | ||
| res, | ||
| [=] __device__ (ID d, IZ z, IG g, IM m) { | ||
| LTIMES_BODY; | ||
| } | ||
| ); | ||
|
|
||
| } | ||
| stopTimer(); | ||
|
|
||
| } else if constexpr (tune_idx == 2) { | ||
|
|
||
| constexpr bool async = true; | ||
|
|
||
| using launch_policy = | ||
| RAJA::LaunchPolicy<RAJA::cuda_launch_t<async, block_size>>; | ||
|
|
||
| using z_policy = RAJA::LoopPolicy<RAJA::cuda_block_x_loop>; | ||
|
|
||
| using g_policy = RAJA::LoopPolicy<RAJA::cuda_block_y_loop>; | ||
|
|
||
| using m_policy = RAJA::LoopPolicy<RAJA::cuda_thread_x_loop>; | ||
|
|
||
| using d_policy = RAJA::LoopPolicy<RAJA::seq_exec>; | ||
|
|
||
| startTimer(); | ||
| // Loop counter increment uses macro to quiet C++20 compiler warning | ||
| for (RepIndex_type irep = 0; irep < run_reps; RP_REPCOUNTINC(irep)) { | ||
|
|
||
| RAJA::launch<launch_policy>( res, | ||
| RAJA::LaunchParams(RAJA::Teams(*num_z, *num_g, 1), | ||
| RAJA::Threads(block_size, 1, 1)), | ||
| [=] RAJA_HOST_DEVICE(RAJA::LaunchContext ctx) { | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be worth looking into the CachePolicy for the launch_context: https://github.com/llnl/RAJAPerf/blob/develop/src/apps/MASS3DEA-Cuda.cpp#L206-L209 We got some speedups here, this might help the nested loops |
||
| RAJA::loop<z_policy>(ctx, IZRange(0, *num_z), | ||
| [&](IZ z) { | ||
| RAJA::loop<g_policy>(ctx, IGRange(0, *num_g), | ||
| [&](IG g) { | ||
| RAJA::loop<m_policy>(ctx, IMRange(0, *num_m), | ||
| [&](IM m) { | ||
| RAJA::loop<d_policy>(ctx, IDRange(0, *num_d), | ||
| [&](ID d) { | ||
| LTIMES_BODY | ||
| } | ||
| ); // RAJA::loop<d_policy> | ||
| } | ||
| ); // RAJA::loop<m_policy> | ||
| } | ||
| ); // RAJA::loop<g_policy> | ||
| } | ||
| ); // RAJA::loop<z_policy> | ||
|
|
||
| } // outer lambda (ctx) | ||
| ); // RAJA::launch | ||
|
|
||
| } // loop over kernel reps | ||
| stopTimer(); | ||
| } else if constexpr (tune_idx == 3) { | ||
|
|
||
| constexpr bool async = true; | ||
|
|
||
| using launch_policy = RAJA::LaunchPolicy<RAJA::cuda_launch_t<async, m_block_sz*g_block_sz*z_block_sz>>; | ||
| using launch_policy = | ||
| RAJA::LaunchPolicy<RAJA::cuda_launch_t<async, factorized_m_block_sz*factorized_g_block_sz*factorized_z_block_sz>>; | ||
|
|
||
| using z_policy = RAJA::LoopPolicy<RAJA::cuda_global_size_z_loop<z_block_sz>>; | ||
| using z_policy = RAJA::LoopPolicy<RAJA::cuda_global_size_z_loop<factorized_z_block_sz>>; | ||
|
|
||
| using g_policy = RAJA::LoopPolicy<RAJA::cuda_global_size_y_loop<g_block_sz>>; | ||
| using g_policy = RAJA::LoopPolicy<RAJA::cuda_global_size_y_loop<factorized_g_block_sz>>; | ||
|
|
||
| using m_policy = RAJA::LoopPolicy<RAJA::cuda_global_size_x_loop<m_block_sz>>; | ||
| using m_policy = RAJA::LoopPolicy<RAJA::cuda_global_size_x_loop<factorized_m_block_sz>>; | ||
|
|
||
| using d_policy = RAJA::LoopPolicy<RAJA::seq_exec>; | ||
|
|
||
| const size_t z_grid_sz = RAJA_DIVIDE_CEILING_INT(*num_z, z_block_sz); | ||
| const size_t z_grid_sz = RAJA_DIVIDE_CEILING_INT(*num_z, factorized_z_block_sz); | ||
|
|
||
| const size_t g_grid_sz = RAJA_DIVIDE_CEILING_INT(*num_g, g_block_sz); | ||
| const size_t g_grid_sz = RAJA_DIVIDE_CEILING_INT(*num_g, factorized_g_block_sz); | ||
|
|
||
| const size_t m_grid_sz = RAJA_DIVIDE_CEILING_INT(*num_m, m_block_sz); | ||
| const size_t m_grid_sz = RAJA_DIVIDE_CEILING_INT(*num_m, factorized_m_block_sz); | ||
|
|
||
| startTimer(); | ||
| // Loop counter increment uses macro to quiet C++20 compiler warning | ||
| for (RepIndex_type irep = 0; irep < run_reps; RP_REPCOUNTINC(irep)) { | ||
|
|
||
| RAJA::launch<launch_policy>( res, | ||
| RAJA::LaunchParams(RAJA::Teams(m_grid_sz, g_grid_sz, z_grid_sz), | ||
| RAJA::Threads(m_block_sz, g_block_sz, z_block_sz)), | ||
| RAJA::Threads(factorized_m_block_sz, factorized_g_block_sz, factorized_z_block_sz)), | ||
| [=] RAJA_HOST_DEVICE(RAJA::LaunchContext ctx) { | ||
|
|
||
| RAJA::loop<z_policy>(ctx, IZRange(0, *num_z), | ||
|
|
@@ -242,12 +399,35 @@ void LTIMES::defineCudaVariantTunings() | |
|
|
||
| if (vid == RAJA_CUDA) { | ||
| addVariantTuning<<IMES::runCudaVariantImpl<block_size, 0>>( | ||
| vid, "kernel_"+std::to_string(block_size)); | ||
| addVariantTuning<<IMES::runCudaVariantImpl<block_size, 1>>( | ||
| vid, "launch_"+std::to_string(block_size)); | ||
| vid, "kernel_m"); | ||
| addVariantTuning<<IMES::runCudaVariantImpl<block_size, 2>>( | ||
| vid, "launch_m"); | ||
| } else { | ||
| addVariantTuning<<IMES::runCudaVariantImpl<block_size, 0>>( | ||
| vid, "block_"+std::to_string(block_size)); | ||
| vid, "block_m"); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| }); | ||
|
|
||
| } | ||
|
|
||
| for (VariantID vid : {Base_CUDA, Lambda_CUDA, RAJA_CUDA}) { | ||
|
|
||
| seq_for(factorized_gpu_block_sizes_type{}, [&](auto block_size) { | ||
|
|
||
| if (run_params.numValidGPUBlockSize() == 0u || | ||
| run_params.validGPUBlockSize(block_size)) { | ||
|
|
||
| if (vid == RAJA_CUDA) { | ||
| addVariantTuning<<IMES::runCudaVariantImpl<block_size, 1>>( | ||
| vid, "kernel_m32_gBigFact_zLowFact_"+std::to_string(block_size)); | ||
| addVariantTuning<<IMES::runCudaVariantImpl<block_size, 3>>( | ||
| vid, "launch_m32_gBigFact_zLowFact_"+std::to_string(block_size)); | ||
| } else { | ||
| addVariantTuning<<IMES::runCudaVariantImpl<block_size, 1>>( | ||
| vid, "block_m32_gBigFact_zLowFact_"+std::to_string(block_size)); | ||
| } | ||
|
|
||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that I've reverted LTimes to launch synchronously in Kripke, for correctness. This is fine though because the direction loop is inner-most, which should avoid race conditions.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has been async in RAJAPerf, I just changed it from
CudaKernelFixedAsynctoCudaKernelAsync, but for completeness I can make itCudaKernel. I don't this would matter for performance in RAJAPerf.