diff --git a/CHANGELOG.md b/CHANGELOG.md index e051e312..3f882886 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ Documentation for TransferBench is available at - Added new bmasweep preset that compares DMA to batched DMA execution for parallel transfers to other GPUs - Added new wallclock preset that compares wallclock counters across XCCs within a GPU - Added new smoketest preset that runs a variety of DMA/GFX tests for simple correctness tests +- Added new help preset to show config file examples +- Added new presets preset to show available presets and their descriptions +- Added new envvars preset to show environment variables that can change TransferBench behavior +- Adding information on how to run multi-rank with TransferBench, when run with no args ### Modified - DMA-BUF support enablement in CMake changed to ENABLE_DMA_BUF to be more similar to other compile-time options @@ -30,6 +34,7 @@ Documentation for TransferBench is available at - Dynamically size CQs for NIC transfers in high QPs case - Switch to using hipMemcpyDeviceToDeviceNoCU instead of hipMemcpyDefault for DMA Executor if available (requires HIP >= 6.0) - Allow for multiple destination memory locations for DMA/Batched-DMA Transfers +- Removed env vars printing and preset print when running TransferBench with no args ## v1.66.02 ### Added diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 26433500..8c20a3f9 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -43,7 +43,6 @@ int main(int argc, char **argv) if (!ev.outputToCsv) { DisplayVersion(); DisplayUsage(argv[0]); - DisplayPresets(); } DisplayTopology(ev.outputToCsv, ev.showBorders); } @@ -258,14 +257,26 @@ void DisplayUsage(char const* cmdName) Print("Usage: %s config \n", cmdName); Print(" config: Either:\n"); - Print(" - Filename of configFile containing Transfers to execute (see example.cfg for format)\n"); - Print(" - Name of preset config:\n"); + Print(" - Filename of config file containing Transfers to execute\n"); + Print(" - Name of preset config\n"); + Print(" - 'cmdline' followed by one transfer expression\n"); + Print(" - 'dryrun' followed by one transfer expression (prints parsed transfers only)\n"); Print(" N : (Optional) Number of bytes to copy per Transfer.\n"); - Print(" If not specified, defaults to %lu bytes. Must be a multiple of 4 bytes\n", - DEFAULT_BYTES_PER_TRANSFER); + Print(" If not specified, defaults to %lu. Must be a multiple of 4 bytes\n", DEFAULT_BYTES_PER_TRANSFER); Print(" If 0 is specified, a range of Ns will be benchmarked\n"); Print(" May append a suffix ('K', 'M', 'G') for kilobytes / megabytes / gigabytes\n"); Print("\n"); - - EnvVars::DisplayUsage(); + Print("- Use \"%s help\" for more information about how to create config files / describe Transfers\n", cmdName); + Print("- Use \"%s envvars\" for more information about environment variables that customize behavior\n", cmdName); + Print("- Use \"%s presets\" to display list of available presets\n", cmdName); + Print("\n"); + Print("For multi-rank usage, TransferBench must either be compiled with MPI support or rely on sockets\n"); + Print("It is recommended to only run one process per node\n"); + Print(" - MPI approach:\n"); + Print(" Node 0> mpirun -np 4 -host node0,node1,node2,node3 ./TransferBench a2a\n"); + Print(" - Socket approach:\n"); + Print(" Node 0> TB_RANK=0 TB_NUM_RANKS=4 TB_MASTER_ADDR=X.X.X.X ./TransferBench a2a\n"); + Print(" Node 1> TB_RANK=1 TB_NUM_RANKS=4 TB_MASTER_ADDR=X.X.X.X ./TransferBench a2a\n"); + Print(" Node 2> TB_RANK=2 TB_NUM_RANKS=4 TB_MASTER_ADDR=X.X.X.X ./TransferBench a2a\n"); + Print(" Node 3> TB_RANK=3 TB_NUM_RANKS=4 TB_MASTER_ADDR=X.X.X.X ./TransferBench a2a\n"); }; diff --git a/src/client/EnvVars.hpp b/src/client/EnvVars.hpp index 4f76ea23..e4459c8a 100644 --- a/src/client/EnvVars.hpp +++ b/src/client/EnvVars.hpp @@ -314,56 +314,70 @@ class EnvVars } // Display info on the env vars that can be used - static void DisplayUsage() + static void DisplayEnvVarsList() { - printf("Environment variables:\n"); + printf("Environment variables (client):\n"); printf("======================\n"); - printf(" ALWAYS_VALIDATE - Validate after each iteration instead of once after all iterations\n"); - printf(" BLOCK_BYTES - Controls granularity of how work is divided across subExecutors\n"); - printf(" BYTE_OFFSET - Initial byte-offset for memory allocations. Must be multiple of 4\n"); - printf(" CU_MASK - CU mask for streams. Can specify ranges e.g '5,10-12,14'\n"); - printf(" FILL_COMPRESS - Percentages of 64B lines to be filled by random/1B0/2B0/4B0/32B0\n"); - printf(" FILL_PATTERN - Big-endian pattern for source data, specified in hex digits. Must be even # of digits\n"); - printf(" GFX_BLOCK_ORDER - How blocks for transfers are ordered. 0=sequential, 1=interleaved\n"); - printf(" GFX_BLOCK_SIZE - # of threads per threadblock (Must be multiple of 64)\n"); - printf(" GFX_SE_TYPE - SubExecutor granularity type (0=threadblock, 1=warp)\n"); - printf(" GFX_TEMPORAL - Use of non-temporal loads or stores (0=none 1=loads 2=stores 3=both)\n"); - printf(" GFX_UNROLL - Unroll factor for GFX kernel (0=auto), must be less than %d\n", TransferBench::GetIntAttribute(ATR_GFX_MAX_UNROLL)); - printf(" GFX_SINGLE_TEAM - Have subexecutors work together on full array instead of working on disjoint subarrays\n"); - printf(" GFX_WAVE_ORDER - Stride pattern for GFX kernel (0=UWC,1=UCW,2=WUC,3=WCU,4=CUW,5=CWU)\n"); - printf(" GFX_WORD_SIZE - GFX kernel packed data size (4=DWORDx4, 2=DWORDx2, 1=DWORDx1)\n"); - printf(" HIDE_ENV - Hide environment variable value listing\n"); + printf(" ALWAYS_VALIDATE - Validate after each iteration instead of once after all iterations\n"); + printf(" BLOCK_BYTES - Controls granularity of how work is divided across subExecutors\n"); + printf(" BYTE_OFFSET - Initial byte-offset for memory allocations. Must be multiple of 4\n"); + printf(" CU_MASK - CU mask for streams. Can specify ranges e.g '5,10-12,14'\n"); + printf(" FILL_COMPRESS - Percentages of 64B lines to be filled by random/1B0/2B0/4B0/32B0\n"); + printf(" FILL_PATTERN - Big-endian pattern for source data, specified in hex digits. Must be even # of digits\n"); + printf(" GFX_BLOCK_ORDER - How blocks for transfers are ordered. 0=sequential, 1=interleaved\n"); + printf(" GFX_BLOCK_SIZE - # of threads per threadblock (Must be multiple of 64)\n"); + printf(" GFX_SE_TYPE - SubExecutor granularity type (0=threadblock, 1=warp)\n"); + printf(" GFX_TEMPORAL - Use of non-temporal loads or stores (0=none 1=loads 2=stores 3=both)\n"); + printf(" GFX_UNROLL - Unroll factor for GFX kernel (0=auto), must be less than %d\n", TransferBench::GetIntAttribute(ATR_GFX_MAX_UNROLL)); + printf(" GFX_SINGLE_TEAM - Have subexecutors work together on full array instead of working on disjoint subarrays\n"); + printf(" GFX_WAVE_ORDER - Stride pattern for GFX kernel (0=UWC,1=UCW,2=WUC,3=WCU,4=CUW,5=CWU)\n"); + printf(" GFX_WORD_SIZE - GFX kernel packed data size (4=DWORDx4, 2=DWORDx2, 1=DWORDx1)\n"); + printf(" HIDE_ENV - Hide environment variable value listing\n"); #if NIC_EXEC_ENABLED - printf(" IB_GID_INDEX - Required for RoCE NICs (default=-1/auto)\n"); - printf(" IB_PORT_NUMBER - RDMA port count for RDMA NIC (default=1)\n"); - printf(" IP_ADDRESS_FAMILY - IP address family (4=v4, 6=v6, default=v4)\n"); + printf(" IB_GID_INDEX - Required for RoCE NICs (default=-1/auto)\n"); + printf(" IB_PORT_NUMBER - RDMA port count for RDMA NIC (default=1)\n"); + printf(" IP_ADDRESS_FAMILY - IP address family (4=v4, 6=v6, default=v4)\n"); #endif - printf(" MIN_VAR_SUBEXEC - Minumum # of subexecutors to use for variable subExec Transfers\n"); - printf(" MAX_VAR_SUBEXEC - Maximum # of subexecutors to use for variable subExec Transfers (0 for device limits)\n"); + printf(" MIN_VAR_SUBEXEC - Minimum # of subexecutors to use for variable subExec Transfers\n"); + printf(" MAX_VAR_SUBEXEC - Maximum # of subexecutors to use for variable subExec Transfers (0 for device limits)\n"); #if NIC_EXEC_ENABLED - printf(" NIC_CHUNK_BYTES - Number of bytes to send at a time using NIC (default = 1GB)\n"); - printf(" NIC_CQ_POLL_BATCH - Number of CQ entries to poll per ibv_poll_cq call (default = 4)\n"); - printf(" NIC_RELAX_ORDER - Set to non-zero to use relaxed ordering"); + printf(" NIC_CHUNK_BYTES - Number of bytes to send at a time using NIC (default = 1GB)\n"); + printf(" NIC_CQ_POLL_BATCH - Number of CQ entries to poll per ibv_poll_cq call (default = 4)\n"); + printf(" NIC_RELAX_ORDER - Set to non-zero to use relaxed ordering\n"); #endif - printf(" NUM_ITERATIONS - # of timed iterations per test. If negative, run for this many seconds instead\n"); - printf(" NUM_SUBITERATIONS - # of sub-iterations to run per iteration. Must be non-negative\n"); - printf(" NUM_WARMUPS - # of untimed warmup iterations per test\n"); - printf(" OUTPUT_TO_CSV - Outputs to CSV format if set\n"); + printf(" NUM_ITERATIONS - # of timed iterations per test. If negative, run for this many seconds instead\n"); + printf(" NUM_SUBITERATIONS - # of sub-iterations to run per iteration. Must be non-negative\n"); + printf(" NUM_WARMUPS - # of untimed warmup iterations per test\n"); + printf(" OUTPUT_TO_CSV - Outputs to CSV format if set\n"); #if NIC_EXEC_ENABLED - printf(" ROCE_VERSION - RoCE version (default=2)\n"); + printf(" ROCE_VERSION - RoCE version (default=2)\n"); #endif - printf(" SAMPLING_FACTOR - Add this many samples (when possible) between powers of 2 when auto-generating data sizes\n"); - printf(" SHOW_BORDERS - Show ASCII box-drawing characaters in tables\n"); - printf(" SHOW_ITERATIONS - Show per-iteration timing info\n"); - printf(" USE_HIP_EVENTS - Use HIP events for GFX executor timing\n"); - printf(" USE_HSA_DMA - Use hsa_amd_async_copy instead of hipMemcpy for non-targeted DMA execution\n"); - printf(" USE_INTERACTIVE - Pause for user-input before starting transfer loop\n"); - printf(" USE_SINGLE_STREAM - Use a single stream per GPU GFX executor instead of stream per Transfer\n"); - printf(" VALIDATE_DIRECT - Validate GPU destination memory directly instead of staging GPU memory on host\n"); - printf(" VALIDATE_SOURCE - Validate GPU src memory immediately after preparation\n"); + printf(" SAMPLING_FACTOR - Add this many samples (when possible) between powers of 2 when auto-generating data sizes\n"); + printf(" SHOW_BORDERS - Show ASCII box-drawing characters in tables\n"); + printf(" SHOW_ITERATIONS - Show per-iteration timing info\n"); + printf(" USE_HIP_EVENTS - Use HIP events for GFX executor timing\n"); + printf(" USE_HSA_DMA - Use hsa_amd_async_copy instead of hipMemcpy for non-targeted DMA execution\n"); + printf(" USE_INTERACTIVE - Pause for user-input before starting transfer loop\n"); + printf(" USE_SINGLE_STREAM - Use a single stream per GPU GFX executor instead of stream per Transfer\n"); + printf(" VALIDATE_DIRECT - Validate GPU destination memory directly instead of staging GPU memory on host\n"); + printf(" VALIDATE_SOURCE - Validate GPU src memory immediately after preparation\n"); + printf("\n"); + printf("Environment variables (back-end):\n"); + printf("====================================\n"); + printf(" TB_RANK - Used to specify the rank of this process (0-based, socket communicator)\n"); + printf(" TB_NUM_RANKS - Used to specify the total number of ranks (socket communicator)\n"); + printf(" TB_MASTER_ADDR - Used to set Rank 0 IP/hostname for socket communicator\n"); + printf(" TB_MASTER_PORT - Used to set Rank 0 port for socket communicator (default: 29500)\n"); + printf(" TB_SINGLE_LOG - In socket mode, only rank 0 logs when set\n"); + printf(" TB_VERBOSE - Enables additional internal logging\n"); + printf(" TB_DUMP_CFG_FILE - Writes executed transfers to a config file\n"); + printf(" TB_DUMP_LINES - Dumps randomized input-line statistics for FILL_COMPRESS setup\n"); + printf(" TB_NIC_FILTER - Regex filter to limit NIC visibility for NIC executors\n"); + printf(" TB_FORCE_SINGLE_POD - Forces all ranks into one pod (skips pod query)\n"); + printf(" TB_WALLCLOCK_RATE - Overrides queried GPU wallclock rate if needed\n"); + printf(" TB_PAUSE - Pauses startup for debugger attachment\n"); } - void Print(std::string const& name, int32_t const value, const char* format, ...) const { printf("%-20s%s%12d%s", name.c_str(), outputToCsv ? "," : " = ", value, outputToCsv ? "," : " : "); diff --git a/src/client/Presets/EnvVarsList.hpp b/src/client/Presets/EnvVarsList.hpp new file mode 100644 index 00000000..90fbcd39 --- /dev/null +++ b/src/client/Presets/EnvVarsList.hpp @@ -0,0 +1,31 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +int EnvVarsPreset([[maybe_unused]] EnvVars& ev, + [[maybe_unused]] size_t const numBytesPerTransfer, + [[maybe_unused]] std::string const presetName, + [[maybe_unused]] bool const bytesSpecified) +{ + if (!Utils::RankDoesOutput()) return 0; + EnvVars::DisplayEnvVarsList(); + return 0; +} diff --git a/src/client/Presets/Help.hpp b/src/client/Presets/Help.hpp new file mode 100644 index 00000000..26ede846 --- /dev/null +++ b/src/client/Presets/Help.hpp @@ -0,0 +1,123 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +int HelpPreset([[maybe_unused]] EnvVars& ev, + [[maybe_unused]] size_t const numBytesPerTransfer, + [[maybe_unused]] std::string const presetName, + [[maybe_unused]] bool const bytesSpecified) +{ + if (!Utils::RankDoesOutput()) return 0; + + printf("# ConfigFile Format:\n"); + printf("# ==================\n"); + printf("# A Transfer is defined as a single operation where an Executor reads and adds together\n"); + printf("# values from Source (SRC) memory locations, then writes the sum to destination (DST) memory locations.\n"); + printf("# This simplifies to a simple copy operation when dealing with single SRC/DST.\n"); + printf("#\n"); + printf("# SRC 0 DST 0\n"); + printf("# SRC 1 -> Executor -> DST 1\n"); + printf("# SRC X DST Y\n"); + printf("\n"); + printf("# Five Executors are supported by TransferBench\n"); + printf("# Executor: SubExecutor:\n"); + printf("# 1) CPU CPU thread\n"); + printf("# 2) GPU GPU threadblock/Compute Unit (CU)\n"); + printf("# 3) DMA N/A. (Must have single SRC, at least one DST)\n"); + printf("# 4) NIC Queue Pair\n"); + printf("# 5) Batched-DMA Batch item (Must have single SRC, at least one DST)\n"); + printf("\n"); + printf("# Each single line in the configuration file defines a set of Transfers (a Test) to run in parallel\n"); + printf("\n"); + printf("# There are two ways to specify a Test:\n"); + printf("\n"); + printf("# 1) Basic\n"); + printf("# The basic specification assumes the same number of SubExecutors (SE) used per Transfer\n"); + printf("# A positive number of Transfers is specified followed by that number of triplets describing each Transfer\n"); + printf("\n"); + printf("# #Transfers #SEs (srcMem1->Executor1->dstMem1) ... (srcMemL->ExecutorL->dstMemL)\n"); + printf("\n"); + printf("# 2) Advanced\n"); + printf("# A negative number of Transfers is specified, followed by quintuplets describing each Transfer\n"); + printf("# A non-zero number of bytes specified will override any provided value\n"); + printf("# -#Transfers (srcMem1->Executor1->dstMem1 #SEs1 Bytes1) ... (srcMemL->ExecutorL->dstMemL #SEsL BytesL)\n"); + printf("\n"); + printf("# Argument Details:\n"); + printf("# #Transfers: Number of Transfers to be run in parallel\n"); + printf("# #SEs : Number of SubExecutors to use (CPU threads/ GPU threadblocks)\n"); + printf("# srcMemL : Source memory locations (Where the data is to be read from)\n"); + printf("# Executor : Executor is specified by a character indicating type, followed by device index (0-indexed)\n"); + printf("# - C: CPU-executed (Indexed from 0 to # NUMA nodes - 1)\n"); + printf("# - G: GPU-executed (Indexed from 0 to # GPUs - 1)\n"); + printf("# - D: DMA-executor (Indexed from 0 to # GPUs - 1)\n"); + printf("# - B: Batched-DMA-executor (Indexed from 0 to # GPUs - 1)\n"); + printf("# - I#.#: NIC executor (Indexed from 0 to # NICs - 1)\n"); + printf("# - N#.#: Nearest NIC executor (Indexed from 0 to # GPUs - 1)\n"); + printf("# dstMemL : Destination memory locations (Where the data is to be written to)\n"); + printf("# bytesL : Number of bytes to copy (0 means use command-line specified size)\n"); + printf("# Must be a multiple of 4 and may be suffixed with ('K','M', or 'G')\n"); + printf("#\n"); + printf("# Memory locations are specified by one or more (device character / device index) pairs\n"); + printf("# Character indicating memory type followed by device index (0-indexed)\n"); + printf("# Supported memory locations are:\n"); + printf("# - C: Pinned host memory (on NUMA node, indexed from 0 to [# NUMA nodes-1])\n"); + printf("# - P: Pinned host memory (on NUMA node, indexed by closest GPU [# GPUs -1])\n"); + printf("# - B: Coherent pinned host memory (on NUMA node, indexed from 0 to [# NUMA nodes-1])\n"); + printf("# - D: Non-coherent pinned host memory (on NUMA node, indexed from 0 to [# NUMA nodes-1])\n"); + printf("# - K: Uncached pinned host memory (on NUMA node, indexed from 0 to [# NUMA nodes-1])\n"); + printf("# - H: Unpinned host memory (on NUMA node, indexed from 0 to [# NUMA nodes-1])\n"); + printf("# - G: Global device memory (on GPU device indexed from 0 to [# GPUs - 1])\n"); + printf("# - F: Fine-grain device memory (on GPU device indexed from 0 to [# GPUs - 1])\n"); + printf("# - U: Uncached device memory (on GPU device indexed from 0 to [# GPUs - 1])\n"); + printf("# - N: Null memory (index ignored)\n"); + printf("\n"); + printf("\n"); + printf("# Examples:\n"); + printf("# 1 4 (G0->G0->G1) Uses 4 CUs on GPU0 to copy from GPU0 to GPU1\n"); + printf("# 1 4 (C1->G2->G0) Uses 4 CUs on GPU2 to copy from CPU1 to GPU0\n"); + printf("# 2 4 G0->G0->G1 G1->G1->G0 Copies from GPU0 to GPU1, and GPU1 to GPU0, each with 4 SEs\n"); + printf("# -2 (G0 G0 G1 4 1M) (G1 G1 G0 2 2M) Copies 1Mb from GPU0 to GPU1 with 4 SEs, and 2Mb from GPU1 to GPU0 with 2 SEs\n"); + printf("# 1 2 (F0->I0.2->F1) Uses 2 QPs to transfer data from GPU0 via NIC0 to GPU1 via NIC2\n"); + printf("# 1 1 (F0->N0.1->F1) Uses 1 QP to transfer data from GPU0 via GPU0's closest NIC to GPU1 via GPU1's closest NIC\n"); + printf("# -2 (G0->N0.1->G1 2 128M) (G1->N1.0->G0 1 256M) Uses Nearest NIC executor to copy 128Mb from GPU0 to GPU1 with 2 QPs,\n"); + printf("# and 256Mb from GPU1 to GPU0 with 1 QP\n"); + printf("# Round brackets and arrows' ->' may be included for human clarity, but will be ignored and are unnecessary\n"); + printf("# Lines starting with # will be ignored. Lines starting with ## will be echoed to output\n"); + printf("\n"); + printf("## Single GPU-executed Transfer between GPUs 0 and 1 using 4 CUs\n"); + printf("1 4 (G0->G0->G1)\n"); + printf("\n"); + printf("## Single DMA executed Transfer between GPUs 0 and 1\n"); + printf("1 1 (G0->D0->G1)\n"); + printf("\n"); + printf("## Copy 1Mb from GPU0 to GPU1 with 4 CUs, and 2Mb from GPU1 to GPU0 with 8 CUs\n"); + printf("-2 (G0->G0->G1 4 1M) (G1->G1->G0 8 2M)\n"); + printf("\n"); + printf("## \"Memset\" by GPU 0 to GPU 0 memory\n"); + printf("1 32 (N0->G0->G0)\n"); + printf("\n"); + printf("## \"Read-only\" by CPU 0\n"); + printf("1 4 (C0->C0->N0)\n"); + printf("\n"); + printf("## Broadcast from GPU 0 to GPU 0 and GPU 1\n"); + printf("1 16 (G0->G0->G0G1)\n"); + return 0; +} diff --git a/src/client/Presets/Presets.hpp b/src/client/Presets/Presets.hpp index 5e3869bd..8354208d 100644 --- a/src/client/Presets/Presets.hpp +++ b/src/client/Presets/Presets.hpp @@ -22,6 +22,7 @@ THE SOFTWARE. #pragma once #include +#include // EnvVars is available to all presets #include "EnvVars.hpp" @@ -31,9 +32,11 @@ THE SOFTWARE. #include "AllToAllN.hpp" #include "AllToAllSweep.hpp" #include "BmaSweep.hpp" +#include "EnvVarsList.hpp" #include "GfxSweep.hpp" #include "HbmBandwidth.hpp" #include "HealthCheck.hpp" +#include "Help.hpp" #include "NicRings.hpp" #include "NicPeerToPeer.hpp" #include "OneToAll.hpp" @@ -51,15 +54,23 @@ typedef int (*PresetFunc)(EnvVars& ev, std::string const presetName, [[maybe_unused]] bool const bytesSpecified); -std::map> presetFuncMap = +struct PresetInfo +{ + PresetFunc func; + std::string description; +}; + +std::map presetFuncMap = { {"a2a", {AllToAllPreset, "Tests parallel transfers between all pairs of GPU devices"}}, {"a2a_n", {AllToAllRdmaPreset, "Tests parallel transfers between all pairs of GPU devices using Nearest NIC RDMA transfers"}}, {"a2asweep", {AllToAllSweepPreset, "Test GFX-based all-to-all transfers swept across different CU and GFX unroll counts"}}, {"bmasweep", {BmaSweepPreset, "Test and compare batched DMA executor for multi destination copies"}}, + {"envvars", {EnvVarsPreset, "Show list of environment variables that can be used to modify behavior"}}, {"gfxsweep", {GfxSweepPreset, "Sweep over various GFX kernel options for a given GFX Transfer"}}, {"hbm", {HbmBandwidthPreset, "Tests HBM bandwidth"}}, {"healthcheck", {HealthCheckPreset, "Simple bandwidth health check (MI300X series only)"}}, + {"help", {HelpPreset, "Shows example usage details"}}, {"nicrings", {NicRingsPreset, "Tests NIC rings created across identical NIC indices across ranks"}}, {"nicp2p", {NicPeerToPeerPreset, "Multi-node peer-to-peer RDMA transfer test between all NICs"}}, {"one2all", {OneToAllPreset, "Test all subsets of parallel transfers from one GPU to all others"}}, @@ -76,10 +87,15 @@ std::map> presetFuncMap = void DisplayPresets() { - printf("\nAvailable Preset Benchmarks:\n"); - printf("============================\n"); - for (auto const& x : presetFuncMap) - printf(" %15s - %s\n", x.first.c_str(), x.second.second.c_str()); + if (!Utils::RankDoesOutput()) return; + printf(" %-12s | %-56s\n", "Preset", "Description"); + printf("=============================================================================================================\n"); + for (auto const& x : presetFuncMap) { + printf(" %-12s | %-56s\n", + x.first.c_str(), + x.second.description.c_str()); + } + printf("=============================================================================================================\n"); } int RunPreset(EnvVars& ev, @@ -90,8 +106,14 @@ int RunPreset(EnvVars& ev, { std::string preset = (argc > 1 ? argv[1] : ""); bool bytesSpecified = (argc > 2); + + if (preset == "presets") { + DisplayPresets(); + retCode = 0; + return 1; + } if (presetFuncMap.count(preset)) { - retCode = (presetFuncMap[preset].first)(ev, numBytesPerTransfer, preset, bytesSpecified); + retCode = (presetFuncMap[preset].func)(ev, numBytesPerTransfer, preset, bytesSpecified); return 1; } return 0;