Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/README_BUILD_PACKAGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ sudo -E BUILD_TYPE=Debug ./build_packages_local.sh
After the script completes, packages live under `build/`:

```
build/amdrocm7-transferbench_1.66.02-<release>_amd64.deb
build/amdrocm7-transferbench-1.66.02-<release>.x86_64.rpm
build/amdrocm7-transferbench-1.66.02-Linux.tar.gz
build/amdrocm7-transferbench_1.71.00-<release>_amd64.deb
build/amdrocm7-transferbench-1.71.00-<release>.x86_64.rpm
build/amdrocm7-transferbench-1.71.00-Linux.tar.gz
```

## Installing built packages
Expand Down
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,34 @@
Documentation for TransferBench is available at
[https://rocm.docs.amd.com/projects/TransferBench](https://rocm.docs.amd.com/projects/TransferBench).

## v1.71.00
### Added
- Added PingPong operations to measure latency between two GPU Executors. A PingPong joins a Ping and a Pong triplet
with `+` and an optional lap count, e.g. `(N->G0->F1)+1000(N->G1->F0)`. Each lap, the Ping Executor writes a
1-byte flag to its DST and waits for the Pong Executor to write one back to the Pong DST. Results report the
GPU-timed round-trip latency per lap
- PingPongs can run in parallel with regular Transfers in the same Test, and do not count toward Executor bandwidth
- Each Ping and Pong uses a single threadblock; the number of SubExecutors and bytes to transfer are ignored
- Currently supported on GFX Executors only
- Ping and Pong may run on different ranks within the same pod (requires pod communication support)
- Added `PINGPONG_FLAG_BUFFER` and `PINGPONG_STRIDE` to spread PingPong flags across a buffer, moving by the stride each lap
- Added latency presets built on PingPong operations:
- "p2p_latency": latency between pairs of GPU Executors, run serially
- "one2all_latency": latency from one GPU Executor to all others, run in parallel
- "a2a_latency": latency between all pairs of GPU Executors, run in parallel
- Behavior can be modified with `NUM_LAPS`, `GPU_MEM_TYPE`, `USE_REMOTE_READ`, `NUM_GPU_DEVICES` and, for a2a_latency, `A2A_LOCAL`
- Added gfx1250-strict to the default GPU targets for CMake builds
- NIC topology output now shows each NIC's IBV max_msg_sz
### Modified
- When GFX Executor timing does not use HIP events (multi-stream mode or `USE_HIP_EVENTS=0`), it now spans from the first
Transfer launch to the last Transfer completion, excluding executor dispatch overhead
### Fixed
- CU IDs reported with `SHOW_ITERATIONS` now match `CU_MASK` indices on gfx90a, gfx942, gfx950 and gfx1250
- GFX kernel launch failures are now reported instead of being ignored
- RoCE / GID index fields are now initialized for NICs that are not RoCE or have no active port
- NIC Transfers are now rejected during validation if a queue pair's work request (the smaller of `NIC_CHUNK_BYTES` and
the bytes assigned to that queue pair) exceeds the IBV max_msg_sz of either NIC

## v1.70.02
### Modified
- rings preset defaults `NUM_SUB_EXEC` to 0, which uses all available subexecutors per Transfer
Expand Down
7 changes: 4 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ set(ENV{ROCM_PATH} "${ROCM_PATH}")
# TransferBench project definitions
#==================================================================================================
set(TRANSFERBENCH_VERSION_MAJOR 1)
set(TRANSFERBENCH_VERSION_MINOR 70)
set(TRANSFERBENCH_VERSION_PATCH_FALLBACK "02")
set(TRANSFERBENCH_VERSION_MINOR 71)
set(TRANSFERBENCH_VERSION_PATCH_FALLBACK "00")

# Auto-compute patch from git: count commits since the last v<MAJOR>.<MINOR>.* tag.
# Falls back to TRANSFERBENCH_VERSION_PATCH_FALLBACK when git is unavailable,
Expand Down Expand Up @@ -220,7 +220,8 @@ set(DEFAULT_GPUS
gfx1151
gfx1200
gfx1201
gfx1250)
gfx1250
gfx1250-strict)

if(BUILD_LOCAL_GPU_TARGET_ONLY)
message(STATUS "Building only for local GPU target")
Expand Down
2 changes: 1 addition & 1 deletion docs/install/build_from_source.rst
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ To modify the CMake behavior, use the following environment variables:
<td rowspan="3"><b>CMake cache variables</b></td>
<td><code>GPU_TARGETS</code></td>
<td>Semicolon-separated GPU architectures. Overridden if <code>BUILD_LOCAL_GPU_TARGET_ONLY</code> is <code>ON</code></td>
<td><code style="word-break: break-all;">gfx906;gfx908;gfx90a;gfx942;gfx950;gfx1030;gfx1100;gfx1101;gfx1102;gfx1150;gfx1151;gfx1200;gfx1201;gfx1250</code></td>
<td><code style="word-break: break-all;">gfx906;gfx908;gfx90a;gfx942;gfx950;gfx1030;gfx1100;gfx1101;gfx1102;gfx1150;gfx1151;gfx1200;gfx1201;gfx1250;gfx1250-strict</code></td>
</tr>
<tr>
<td><code>AMD_SMI_EXECUTABLE</code></td>
Expand Down
24 changes: 16 additions & 8 deletions src/client/Client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,24 @@ int main(int argc, char **argv)
if (transfers.empty()) {
Print("<none>\n");
} else {
bool isMultiNode = GetNumRanks() > 1;
for (size_t i = 0; i < transfers.size(); i++) {
Transfer const& t = transfers[i];
Print("Transfer %5lu: (%s->", i, MemDevicesToStr(t.srcs).c_str());
if (isMultiNode) Print("R%d", t.exeDevice.exeRank);
Print("%c%d", ExeTypeStr[t.exeDevice.exeType], t.exeDevice.exeIndex);
if (t.exeDevice.exeSlot) Print("%c", 'A' + t.exeDevice.exeSlot);
if (t.exeSubIndex != -1) Print(".%d", t.exeSubIndex);
if (t.exeSubSlot != 0) Print("%c", 'A' + t.exeSubSlot);
Print("->%s)\n", MemDevicesToStr(t.dsts).c_str());
if (t.numLaps > 0) {
Print("Transfer %5lu: PingPong +%d: (%s->%s->%s) <+> (%s->%s->%s)\n",
i, t.numLaps,
MemDeviceToStr(t.srcs[0]).c_str(),
ExeDeviceToStr(t.exeDevice, t.exeSubIndex, t.exeSubSlot).c_str(),
MemDeviceToStr(t.dsts[0]).c_str(),
MemDeviceToStr(t.srcs[1]).c_str(),
ExeDeviceToStr(t.exeDevicePong, t.exeSubIndexPong, t.exeSubSlotPong).c_str(),
MemDeviceToStr(t.dsts[1]).c_str());
} else {
Print("Transfer %5lu: (%s->%s->%s)\n",
i,
MemDevicesToStr(t.srcs).c_str(),
ExeDeviceToStr(t.exeDevice, t.exeSubIndex, t.exeSubSlot).c_str(),
MemDevicesToStr(t.dsts).c_str());
}
}
}
return 0;
Expand Down
110 changes: 61 additions & 49 deletions src/client/EnvVars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ THE SOFTWARE.
#include <random>
#include <time.h>

#define CLIENT_VERSION "02"
#define CLIENT_VERSION "00"

#include "TransferBench.hpp"
using namespace TransferBench;
Expand Down Expand Up @@ -74,6 +74,8 @@ class EnvVars
int numIterations; // Number of timed iterations to perform. If negative, run for -numIterations seconds instead
int numSubIterations; // Number of subiterations to perform
int numWarmups; // Number of un-timed warmup iterations to perform
int pingpongFlagBuffer; // Size in bytes of the pingpong flag buffer (must be positive)
int pingpongStride; // Stride in bytes between flag slots for pingpong laps (wraps within the flag buffer)
int showBorders; // Show ASCII box-drawing characaters in tables
int showIterations; // Show per-iteration timing info
int useInteractive; // Pause for user-input before starting transfer loop
Expand Down Expand Up @@ -158,55 +160,57 @@ class EnvVars
else if (archName == "gfx950") defaultGfxUnroll = 4;
else if (archName == "gfx1250") defaultGfxUnroll = 32;

alwaysValidate = GetEnvVar("ALWAYS_VALIDATE", 0);
blockBytes = GetEnvVar("BLOCK_BYTES" , 256);
byteOffset = GetEnvVar("BYTE_OFFSET" , 0);
fillCompress = GetEnvVarArray("FILL_COMPRESS" , {});
gfxBlockOrder = GetEnvVar("GFX_BLOCK_ORDER" , 0);
gfxBlockSize = GetEnvVar("GFX_BLOCK_SIZE" , 256);
gfxKernel = GetEnvVar("GFX_KERNEL" , 0);
gfxSeType = GetEnvVar("GFX_SE_TYPE" , 0);
gfxSingleTeam = GetEnvVar("GFX_SINGLE_TEAM" , 0);
gfxTemporal = GetEnvVar("GFX_TEMPORAL" , 0);
gfxUnroll = GetEnvVar("GFX_UNROLL" , defaultGfxUnroll);
gfxWaveOrder = GetEnvVar("GFX_WAVE_ORDER" , 0);
gfxWordSize = GetEnvVar("GFX_WORD_SIZE" , 4);
hideEnv = GetEnvVar("HIDE_ENV" , 0);
minNumVarSubExec = GetEnvVar("MIN_VAR_SUBEXEC" , 1);
maxNumVarSubExec = GetEnvVar("MAX_VAR_SUBEXEC" , 0);
numIterations = GetEnvVar("NUM_ITERATIONS" , 10);
numSubIterations = GetEnvVar("NUM_SUBITERATIONS" , 1);
numWarmups = GetEnvVar("NUM_WARMUPS" , 3);
outputToCsv = GetEnvVar("OUTPUT_TO_CSV" , 0);
samplingFactor = GetEnvVar("SAMPLING_FACTOR" , 1);
showBorders = GetEnvVar("SHOW_BORDERS" , 1);
showIterations = GetEnvVar("SHOW_ITERATIONS" , 0);
showPercentiles = GetEnvVarArray("SHOW_PERCENTILES", {});
sweepMaxPow2 = GetEnvVar("SWEEP_MAX_POW2" , 29);
sweepMinPow2 = GetEnvVar("SWEEP_MIN_POW2" , 10);
sweepMinPow2 = std::clamp(sweepMinPow2, 0, 62);
sweepMaxPow2 = std::clamp(sweepMaxPow2, 0, 62);
alwaysValidate = GetEnvVar("ALWAYS_VALIDATE", 0);
blockBytes = GetEnvVar("BLOCK_BYTES" , 256);
byteOffset = GetEnvVar("BYTE_OFFSET" , 0);
fillCompress = GetEnvVarArray("FILL_COMPRESS" , {});
gfxBlockOrder = GetEnvVar("GFX_BLOCK_ORDER" , 0);
gfxBlockSize = GetEnvVar("GFX_BLOCK_SIZE" , 256);
gfxKernel = GetEnvVar("GFX_KERNEL" , 0);
gfxSeType = GetEnvVar("GFX_SE_TYPE" , 0);
gfxSingleTeam = GetEnvVar("GFX_SINGLE_TEAM" , 0);
gfxTemporal = GetEnvVar("GFX_TEMPORAL" , 0);
gfxUnroll = GetEnvVar("GFX_UNROLL" , defaultGfxUnroll);
gfxWaveOrder = GetEnvVar("GFX_WAVE_ORDER" , 0);
gfxWordSize = GetEnvVar("GFX_WORD_SIZE" , 4);
hideEnv = GetEnvVar("HIDE_ENV" , 0);
minNumVarSubExec = GetEnvVar("MIN_VAR_SUBEXEC" , 1);
maxNumVarSubExec = GetEnvVar("MAX_VAR_SUBEXEC" , 0);
numIterations = GetEnvVar("NUM_ITERATIONS" , 10);
numSubIterations = GetEnvVar("NUM_SUBITERATIONS" , 1);
numWarmups = GetEnvVar("NUM_WARMUPS" , 3);
pingpongFlagBuffer = GetEnvVar("PINGPONG_FLAG_BUFFER", 1);
pingpongStride = GetEnvVar("PINGPONG_STRIDE" , 1);
outputToCsv = GetEnvVar("OUTPUT_TO_CSV" , 0);
samplingFactor = GetEnvVar("SAMPLING_FACTOR" , 1);
showBorders = GetEnvVar("SHOW_BORDERS" , 1);
showIterations = GetEnvVar("SHOW_ITERATIONS" , 0);
showPercentiles = GetEnvVarArray("SHOW_PERCENTILES", {});
sweepMaxPow2 = GetEnvVar("SWEEP_MAX_POW2" , 29);
sweepMinPow2 = GetEnvVar("SWEEP_MIN_POW2" , 10);
sweepMinPow2 = std::clamp(sweepMinPow2, 0, 62);
sweepMaxPow2 = std::clamp(sweepMaxPow2, 0, 62);
if (sweepMinPow2 > sweepMaxPow2) std::swap(sweepMinPow2, sweepMaxPow2);
tdmBlockOrder = GetEnvVar("TDM_BLOCK_ORDER" , 0);
tdmBlockSize = GetEnvVar("TDM_BLOCK_SIZE" , 256);
tdmLdsBytes = GetEnvVar("TDM_LDS_BYTES" , 0);
useHipEvents = GetEnvVar("USE_HIP_EVENTS" , 1);
useHsaDma = GetEnvVar("USE_HSA_DMA" , 0);
useInteractive = GetEnvVar("USE_INTERACTIVE" , 0);
useSingleStream = GetEnvVar("USE_SINGLE_STREAM" , 1);
validateDirect = GetEnvVar("VALIDATE_DIRECT" , 0);
validateOnDevice = GetEnvVar("VALIDATE_ON_DEVICE" , 0);
validateSource = GetEnvVar("VALIDATE_SOURCE" , 0);

ibGidIndex = GetEnvVar("IB_GID_INDEX" ,-1);
ibPort = GetEnvVar("IB_PORT_NUMBER" , 1);
roceVersion = GetEnvVar("ROCE_VERSION" , 2);
ipAddressFamily = GetEnvVar("IP_ADDRESS_FAMILY" , 4);
nicChunkBytes = GetEnvVar("NIC_CHUNK_BYTES" , 1073741824);
nicCqPollBatch = GetEnvVar("NIC_CQ_POLL_BATCH" , 4);
nicRelaxedOrder = GetEnvVar("NIC_RELAX_ORDER" , 1);
nicServiceLevel = GetEnvVar("NIC_SERVICE_LEVEL" , 0);
nicTrafficClass = GetEnvVar("NIC_TRAFFIC_CLASS" , 0);
tdmBlockOrder = GetEnvVar("TDM_BLOCK_ORDER" , 0);
tdmBlockSize = GetEnvVar("TDM_BLOCK_SIZE" , 256);
tdmLdsBytes = GetEnvVar("TDM_LDS_BYTES" , 0);
useHipEvents = GetEnvVar("USE_HIP_EVENTS" , 1);
useHsaDma = GetEnvVar("USE_HSA_DMA" , 0);
useInteractive = GetEnvVar("USE_INTERACTIVE" , 0);
useSingleStream = GetEnvVar("USE_SINGLE_STREAM" , 1);
validateDirect = GetEnvVar("VALIDATE_DIRECT" , 0);
validateOnDevice = GetEnvVar("VALIDATE_ON_DEVICE" , 0);
validateSource = GetEnvVar("VALIDATE_SOURCE" , 0);

ibGidIndex = GetEnvVar("IB_GID_INDEX" ,-1);
ibPort = GetEnvVar("IB_PORT_NUMBER" , 1);
roceVersion = GetEnvVar("ROCE_VERSION" , 2);
ipAddressFamily = GetEnvVar("IP_ADDRESS_FAMILY" , 4);
nicChunkBytes = GetEnvVar("NIC_CHUNK_BYTES" , 1073741824);
nicCqPollBatch = GetEnvVar("NIC_CQ_POLL_BATCH" , 4);
nicRelaxedOrder = GetEnvVar("NIC_RELAX_ORDER" , 1);
nicServiceLevel = GetEnvVar("NIC_SERVICE_LEVEL" , 0);
nicTrafficClass = GetEnvVar("NIC_TRAFFIC_CLASS" , 0);

// Check that NIC service level and traffic class are in valid ranges
if (nicServiceLevel < 0 || nicServiceLevel > 15) {
Expand Down Expand Up @@ -404,6 +408,8 @@ class EnvVars
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(" PINGPONG_FLAG_BUFFER - Size in bytes of the pingpong flag buffer (default 1, must be positive). Each flag slot is 1 byte\n");
printf(" PINGPONG_STRIDE - Stride in bytes between flag slots for pingpong laps (default 1, must be positive unless the flag buffer is 1 byte, wraps within the flag buffer)\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");
Expand Down Expand Up @@ -555,6 +561,10 @@ class EnvVars
"Running %s subiterations", (numSubIterations == 0 ? "infinite" : std::to_string(numSubIterations)).c_str());
Print("NUM_WARMUPS", numWarmups,
"Running %d warmup iteration(s) per Test", numWarmups);
Print("PINGPONG_FLAG_BUFFER", pingpongFlagBuffer,
"Pingpong flag buffer of %d bytes", pingpongFlagBuffer);
Print("PINGPONG_STRIDE", pingpongStride,
"Pingpong flag stride %d bytes per lap", pingpongStride);
Print("SHOW_BORDERS", showBorders, "%s ASCII box-drawing characaters in tables", showBorders ? "Showing" : "Hiding");
Print("SHOW_ITERATIONS", showIterations,
"%s per-iteration timing", showIterations ? "Showing" : "Hiding");
Expand Down Expand Up @@ -738,6 +748,8 @@ class EnvVars
cfg.general.numIterations = numIterations;
cfg.general.numSubIterations = numSubIterations;
cfg.general.numWarmups = numWarmups;
cfg.general.pingpongFlagBuffer = pingpongFlagBuffer;
cfg.general.pingpongStride = pingpongStride;
cfg.general.recordPerIteration = ((showIterations != 0) || !showPercentiles.empty()) ? 1 : 0;
cfg.general.useHipEvents = useHipEvents;
cfg.general.useInteractive = useInteractive;
Expand Down
Loading
Loading