diff --git a/tools/TransferBench/EnvVars.hpp b/tools/TransferBench/EnvVars.hpp index 1020fae2d2..f8aaaf41e4 100644 --- a/tools/TransferBench/EnvVars.hpp +++ b/tools/TransferBench/EnvVars.hpp @@ -28,6 +28,7 @@ public: int samplingFactor; // Affects how many different values of N are generated (when N set to 0) int numCpuPerLink; // Number of CPU child threads to use per CPU link int sharedMemBytes; // Amount of shared memory to use per threadblock + int blockBytes; // Each CU, except the last, gets a multiple of this many bytes to copy std::vector fillPattern; // Pattern of floats used to fill source data @@ -51,6 +52,7 @@ public: samplingFactor = GetEnvVar("SAMPLING_FACTOR" , DEFAULT_SAMPLING_FACTOR); numCpuPerLink = GetEnvVar("NUM_CPU_PER_LINK" , DEFAULT_NUM_CPU_PER_LINK); sharedMemBytes = GetEnvVar("SHARED_MEM_BYTES" , maxSharedMemBytes / 2 + 1); + blockBytes = GetEnvVar("BLOCK_BYTES" , 256); // Check for fill pattern char* pattern = getenv("FILL_PATTERN"); @@ -141,6 +143,11 @@ public: printf("[ERROR] SHARED_MEM_BYTES must be between 0 and %d\n", maxSharedMemBytes); exit(1); } + if (blockBytes <= 0 || blockBytes % 4) + { + printf("[ERROR] BLOCK_BYTES must be a positive multiple of 4\n"); + exit(1); + } } // Display info on the env vars that can be used @@ -162,6 +169,7 @@ public: printf(" NUM_CPU_PER_LINK=C - Use C threads per Link for CPU-executed copies\n"); printf(" FILL_PATTERN=STR - Fill input buffer with pattern specified in hex digits (0-9,a-f,A-F). Must be even number of digits, (byte-level big-endian)\n"); printf(" SHARED_MEM_BYTES=X - Use X shared mem bytes per threadblock, potentially to avoid multiple threadblocks per CU\n"); + printf(" BLOCK_BYTES=B - Each CU (except the last) receives a multiple of BLOCK_BYTES to copy\n"); } // Display env var settings @@ -206,7 +214,8 @@ public: } printf("\n"); printf("%-20s = %12s : Using %d shared mem per threadblock\n", "SHARED_MEM_BYTES", - getenv("SHARED_MEM_BYTES") ? "(specified)" : "(unspecified)", sharedMemBytes); + getenv("SHARED_MEM_BYTES") ? "(specified)" : "(unset)", sharedMemBytes); + printf("%-20s = %12d : Each CU gets a multiple of %d bytes to copy\n", "BLOCK_BYTES", blockBytes, blockBytes); printf("\n"); } }; diff --git a/tools/TransferBench/TransferBench.cpp b/tools/TransferBench/TransferBench.cpp index 8c07732df8..cc5b368125 100644 --- a/tools/TransferBench/TransferBench.cpp +++ b/tools/TransferBench/TransferBench.cpp @@ -202,21 +202,23 @@ int main(int argc, char **argv) // Initialize source memory with patterned data CheckOrFill(MODE_FILL, N, ev.useMemset, ev.useHipCall, ev.fillPattern, links[i].srcMem + initOffset); + // Each block needs to know src/dst pointers and how many elements to transfer // Figure out the sub-array each block does for this Link - // - Partition N as evenly as posible, but try to keep blocks as multiples of 32, + // - Partition N as evenly as posible, but try to keep blocks as multiples of BLOCK_BYTES bytes, // except the very last one, for alignment reasons + int targetMultiple = ev.blockBytes / sizeof(float); if (links[i].exeMemType == MEM_GPU) { size_t assigned = 0; - int maxNumBlocksToUse = std::min((N + 31) / 32, (size_t)links[i].numBlocksToUse); + int maxNumBlocksToUse = std::min((N + targetMultiple - 1) / targetMultiple, (size_t)links[i].numBlocksToUse); for (int j = 0; j < links[i].numBlocksToUse; j++) { BlockParam param; int blocksLeft = std::max(0, maxNumBlocksToUse - j); size_t leftover = N - assigned; - size_t roundedN = (leftover + 31) / 32; - param.N = blocksLeft ? std::min(leftover, ((roundedN / blocksLeft) * 32)) : 0; + size_t roundedN = (leftover + targetMultiple - 1) / targetMultiple; + param.N = blocksLeft ? std::min(leftover, ((roundedN / blocksLeft) * targetMultiple)) : 0; param.src = links[i].srcMem + assigned + initOffset; param.dst = links[i].dstMem + assigned + initOffset; assigned += param.N; @@ -228,13 +230,13 @@ int main(int argc, char **argv) { // For CPU-based copy, divded based on the number of child threads size_t assigned = 0; - int maxNumBlocksToUse = std::min((N + 31) / 32, (size_t)ev.numCpuPerLink); + int maxNumBlocksToUse = std::min((N + targetMultiple - 1) / targetMultiple, (size_t)ev.numCpuPerLink); for (int j = 0; j < ev.numCpuPerLink; j++) { int blocksLeft = std::max(0, maxNumBlocksToUse - j); size_t leftover = N - assigned; - size_t roundedN = (leftover + 31) / 32; - links[i].blockParam[j].N = blocksLeft ? std::min(leftover, ((roundedN / blocksLeft) * 32)) : 0; + size_t roundedN = (leftover + targetMultiple - 1) / targetMultiple; + links[i].blockParam[j].N = blocksLeft ? std::min(leftover, ((roundedN / blocksLeft) * targetMultiple)) : 0; links[i].blockParam[j].src = links[i].srcMem + assigned + initOffset; links[i].blockParam[j].dst = links[i].dstMem + assigned + initOffset; assigned += links[i].blockParam[j].N; @@ -1158,7 +1160,7 @@ double GetPeakBandwidth(EnvVars const& ev, size_t N, int isBidirectional, // Skip bidirectional on same device if (isBidirectional && srcMemType == dstMemType && srcIndex == dstIndex) return 0.0f; - + // Prepare Links links[0].srcMemType = links[0].exeMemType = links[1].dstMemType = srcMemType; links[0].srcIndex = links[0].exeIndex = links[1].dstIndex = srcIndex;