Skip to content

Commit 94a37bb

Browse files
committed
Adding word_rank and word_size env options
1 parent 0d7e6e9 commit 94a37bb

File tree

3 files changed

+154
-46
lines changed

3 files changed

+154
-46
lines changed

projects/rocprofiler-sdk/source/bin/rocprofv3.py

Lines changed: 115 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -123,29 +123,59 @@ def strtobool(val):
123123
raise ValueError(f"invalid truth value {val} (type={val_type})")
124124

125125

126-
def get_mpi_rank():
127-
"""Detect MPI rank from various MPI implementation environment variables.
128-
Returns the rank as an integer, or None if not running under MPI.
126+
def get_mpi_rank_and_size(custom_rank_env=None, custom_size_env=None):
127+
"""Detect MPI rank and size from the same MPI implementation's environment variables.
128+
129+
This ensures that rank and size come from the same source (e.g., both from OpenMPI,
130+
not mixing OpenMPI rank with SLURM size).
131+
132+
Args:
133+
custom_rank_env: Optional custom environment variable name for rank detection.
134+
custom_size_env: Optional custom environment variable name for size detection.
135+
136+
Returns:
137+
Tuple of (rank, size) as integers, or (None, None) if not running under MPI.
129138
"""
139+
# If custom environment variables are specified, use them exclusively
140+
if custom_rank_env is not None and custom_size_env is not None:
141+
rank = int(os.environ[custom_rank_env]) if custom_rank_env in os.environ else None
142+
size = int(os.environ[custom_size_env]) if custom_size_env in os.environ else None
143+
return (rank, size)
144+
145+
# Try each MPI implementation in order, ensuring both rank and size come from the same source
130146
# OpenMPI
131-
if "OMPI_COMM_WORLD_RANK" in os.environ:
132-
return int(os.environ["OMPI_COMM_WORLD_RANK"])
147+
if "OMPI_COMM_WORLD_RANK" in os.environ and "OMPI_COMM_WORLD_SIZE" in os.environ:
148+
return (
149+
int(os.environ["OMPI_COMM_WORLD_RANK"]),
150+
int(os.environ["OMPI_COMM_WORLD_SIZE"]),
151+
)
152+
133153
# MVAPICH2
134-
elif "MV2_COMM_WORLD_RANK" in os.environ:
135-
return int(os.environ["MV2_COMM_WORLD_RANK"])
136-
# SLURM
137-
elif "SLURM_PROCID" in os.environ:
138-
return int(os.environ["SLURM_PROCID"])
154+
if "MV2_COMM_WORLD_RANK" in os.environ and "MV2_COMM_WORLD_SIZE" in os.environ:
155+
return (
156+
int(os.environ["MV2_COMM_WORLD_RANK"]),
157+
int(os.environ["MV2_COMM_WORLD_SIZE"]),
158+
)
159+
160+
# SLURM (try SLURM_PROCID with both SLURM_NPROCS and SLURM_NTASKS)
161+
if "SLURM_PROCID" in os.environ:
162+
if "SLURM_NPROCS" in os.environ:
163+
return (int(os.environ["SLURM_PROCID"]), int(os.environ["SLURM_NPROCS"]))
164+
elif "SLURM_NTASKS" in os.environ:
165+
return (int(os.environ["SLURM_PROCID"]), int(os.environ["SLURM_NTASKS"]))
166+
139167
# PMI (used by some MPI implementations)
140-
elif "PMI_RANK" in os.environ:
141-
return int(os.environ["PMI_RANK"])
168+
if "PMI_RANK" in os.environ and "PMI_SIZE" in os.environ:
169+
return (int(os.environ["PMI_RANK"]), int(os.environ["PMI_SIZE"]))
170+
142171
# Flux
143-
elif "FLUX_TASK_RANK" in os.environ:
144-
return int(os.environ["FLUX_TASK_RANK"])
145-
# MPICH
146-
elif "PMI_ID" in os.environ:
147-
return int(os.environ["PMI_ID"])
148-
return None
172+
if "FLUX_TASK_RANK" in os.environ and "FLUX_JOB_SIZE" in os.environ:
173+
return (int(os.environ["FLUX_TASK_RANK"]), int(os.environ["FLUX_JOB_SIZE"]))
174+
175+
# MPICH (PMI_ID is rank-like, but no corresponding size variable in this check)
176+
# Skip this to avoid returning incomplete information
177+
178+
return (None, None)
149179

150180

151181
def parse_rank_specification(rank_spec):
@@ -181,19 +211,24 @@ def parse_rank_specification(rank_spec):
181211
return ranks
182212

183213

184-
def should_rank_provide_output(mpi_ranks_spec=None):
214+
def should_rank_provide_output(
215+
mpi_ranks_spec=None, custom_rank_env=None, custom_size_env=None
216+
):
185217
"""Check if the current MPI rank should provide profile/trace output.
186218
Args:
187219
mpi_ranks_spec: String specification of ranks (e.g., "0-3,8,10-15")
188220
If None, all ranks provide output (default behavior).
221+
custom_rank_env: Optional custom environment variable name for rank detection.
222+
custom_size_env: Optional custom environment variable name for world size detection.
189223
Returns:
190224
True if this rank should provide output, False otherwise.
191225
"""
192226
# If no specification provided, all ranks provide output (default)
193227
if not mpi_ranks_spec:
194228
return True
195229

196-
current_rank = get_mpi_rank()
230+
# Get both rank and size from the same source
231+
current_rank, world_size = get_mpi_rank_and_size(custom_rank_env, custom_size_env)
197232

198233
# If we can't detect the rank, assume we should provide output
199234
if current_rank is None:
@@ -202,6 +237,15 @@ def should_rank_provide_output(mpi_ranks_spec=None):
202237
# Parse the rank specification
203238
selected_ranks = parse_rank_specification(mpi_ranks_spec)
204239

240+
# Validate that selected ranks are within the valid range
241+
if world_size is not None and selected_ranks:
242+
max_selected_rank = max(selected_ranks)
243+
if max_selected_rank >= world_size:
244+
fatal_error(
245+
f"Invalid rank specification: rank {max_selected_rank} is out of range. "
246+
f"MPI world size is {world_size} (valid ranks: 0-{world_size-1})"
247+
)
248+
205249
# Check if current rank is in the selected set
206250
return current_rank in selected_ranks
207251

@@ -315,8 +359,8 @@ def parse_arguments(args=None):
315359
316360
For MPI applications, select specific ranks to provide profile/trace output:
317361
318-
$ mpirun -n 16 rocprofv3 --hip-trace --mpi-ranks 0-3,8 -- ./mympiapp
319-
$ srun -n 32 rocprofv3 --hip-trace --mpi-ranks 0 -- ./myapp
362+
$ mpirun -n 16 rocprofv3 --hip-trace --profile-mpi-ranks 0-3,8 -- ./mympiapp
363+
$ srun -n 32 rocprofv3 --hip-trace --profile-mpi-ranks 0 -- ./myapp
320364
321365
For attachment profiling of running processes:
322366
@@ -624,12 +668,26 @@ def add_parser_bool_argument(gparser, *args, **kwargs):
624668
filter_options = parser.add_argument_group("Filtering options")
625669

626670
filter_options.add_argument(
627-
"--mpi-ranks",
671+
"--profile-mpi-ranks",
628672
help="Specify which MPI ranks should provide profile/trace output using comma-separated ranges and individual ranks (e.g., '0-3,8,10-15'). If not specified, all ranks provide output. The tool runs on all ranks but only selected ranks generate output files.",
629673
default=os.environ.get("ROCPROF_MPI_RANKS", None),
630674
type=str,
631675
metavar="RANK_SPECIFICATION",
632676
)
677+
filter_options.add_argument(
678+
"--mpi-world-rank-var",
679+
help="Specify the environment variable to use for determining the MPI rank (e.g., 'MY_CUSTOM_RANK_VAR'). If not specified, the tool will automatically detect the rank from common MPI environment variables.",
680+
default=None,
681+
type=str,
682+
metavar="ENVIRONMENT_VARIABLE",
683+
)
684+
filter_options.add_argument(
685+
"--mpi-world-size-var",
686+
help="Specify the environment variable to use for determining the MPI world size (e.g., 'MY_CUSTOM_SIZE_VAR'). If not specified, the tool will automatically detect the world size from common MPI environment variables.",
687+
default=None,
688+
type=str,
689+
metavar="ENVIRONMENT_VARIABLE",
690+
)
633691
filter_options.add_argument(
634692
"--kernel-include-regex",
635693
help="Include the kernels matching this filter from counter-collection and thread-trace data (non-matching kernels will be excluded)",
@@ -1167,15 +1225,43 @@ def run(app_args, args, **kwargs):
11671225
use_execv = kwargs.get("use_execv", True)
11681226
app_pass = kwargs.get("pass_id", None)
11691227

1228+
# Validate custom MPI environment variables
1229+
# If one custom variable is specified, both must be provided
1230+
custom_rank_env = (
1231+
args.mpi_world_rank_var if has_set_attr(args, "mpi_world_rank_var") else None
1232+
)
1233+
custom_size_env = (
1234+
args.mpi_world_size_var if has_set_attr(args, "mpi_world_size_var") else None
1235+
)
1236+
1237+
if (custom_rank_env is not None and custom_size_env is None) or (
1238+
custom_rank_env is None and custom_size_env is not None
1239+
):
1240+
fatal_error(
1241+
"When using custom MPI environment variables, "
1242+
"both --mpi-world-rank-var and --mpi-world-size-var must be specified"
1243+
)
1244+
1245+
# Set MPI_RANK and MPI_SIZE environment variables for use by the C++ code
1246+
# These variables are used for %rank% and %size% expansion in output paths
1247+
# Use get_mpi_rank_and_size to ensure rank and size come from the same source
1248+
mpi_rank, mpi_size = get_mpi_rank_and_size(custom_rank_env, custom_size_env)
1249+
if mpi_rank is not None:
1250+
app_env["MPI_RANK"] = str(mpi_rank)
1251+
if mpi_size is not None:
1252+
app_env["MPI_SIZE"] = str(mpi_size)
1253+
11701254
# Check if this MPI rank should provide profile/trace output
11711255
# If not, run the application without profiling instrumentation
1172-
if has_set_attr(args, "mpi_ranks"):
1173-
if not should_rank_provide_output(args.mpi_ranks):
1174-
current_rank = get_mpi_rank()
1175-
if current_rank is not None and args.log_level in ("info", "trace"):
1256+
if has_set_attr(args, "profile_mpi_ranks"):
1257+
if not should_rank_provide_output(
1258+
args.profile_mpi_ranks, custom_rank_env, custom_size_env
1259+
):
1260+
# We already have mpi_rank from above, just use it for logging
1261+
if mpi_rank is not None and args.log_level in ("info", "trace"):
11761262
sys.stderr.write(
1177-
f"[rocprofv3] MPI rank {current_rank} not in selected ranks "
1178-
f"({args.mpi_ranks}), running application without profiling\n"
1263+
f"[rocprofv3] MPI rank {mpi_rank} not in selected ranks "
1264+
f"({args.profile_mpi_ranks}), running application without profiling\n"
11791265
)
11801266
sys.stderr.flush()
11811267
# Execute application without profiling

projects/rocprofiler-sdk/source/docs/how-to/using-rocprofv3-with-mpi.rst

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -172,26 +172,26 @@ Assuming the hostname as `ubuntu-latest`, the process IDs as 3000020 and 3000019
172172
Selective rank profiling
173173
==========================
174174

175-
When running large-scale MPI jobs, collecting profiling data from all ranks can generate excessive output and may not be necessary. The ``--mpi-ranks`` option allows you to specify which MPI ranks should provide profile and trace output, while the tool still runs on all ranks to maintain program correctness.
175+
When running large-scale MPI jobs, collecting profiling data from all ranks can generate excessive output and may not be necessary. The ``--profile-mpi-ranks`` option allows you to specify which MPI ranks should provide profile and trace output, while the tool still runs on all ranks to maintain program correctness.
176176

177177
Specifying ranks to profile
178178
-----------------------------
179179

180-
Use the ``--mpi-ranks`` option with a comma-separated list of ranks and ranges:
180+
Use the ``--profile-mpi-ranks`` option with a comma-separated list of ranks and ranges:
181181

182182
.. code-block:: bash
183183
184184
# Profile only rank 0
185-
mpirun -n 16 rocprofv3 --hip-trace --mpi-ranks 0 -- <application_path>
185+
mpirun -n 16 rocprofv3 --hip-trace --profile-mpi-ranks 0 -- <application_path>
186186
187187
# Profile ranks 0-3 and rank 8
188-
mpirun -n 16 rocprofv3 --hip-trace --mpi-ranks 0-3,8 -- <application_path>
188+
mpirun -n 16 rocprofv3 --hip-trace --profile-mpi-ranks 0-3,8 -- <application_path>
189189
190190
# Profile ranks 0, 4, 8, and 12
191-
mpirun -n 16 rocprofv3 --hip-trace --mpi-ranks 0,4,8,12 -- <application_path>
191+
mpirun -n 16 rocprofv3 --hip-trace --profile-mpi-ranks 0,4,8,12 -- <application_path>
192192
193193
# Profile a range of ranks (10 through 15)
194-
srun -n 32 rocprofv3 --kernel-trace --mpi-ranks 10-15 -- <application_path>
194+
srun -n 32 rocprofv3 --kernel-trace --profile-mpi-ranks 10-15 -- <application_path>
195195
196196
The rank specification syntax supports:
197197

@@ -202,7 +202,7 @@ The rank specification syntax supports:
202202
Behavior
203203
---------
204204

205-
When using ``--mpi-ranks``:
205+
When using ``--profile-mpi-ranks``:
206206

207207
- The ``rocprofv3`` tool runs on **all** MPI ranks to avoid disrupting the application's execution
208208
- Only the specified ranks collect and output profiling/trace data
@@ -212,15 +212,35 @@ When using ``--mpi-ranks``:
212212
Default behavior
213213
-----------------
214214

215-
If ``--mpi-ranks`` is not specified, all ranks provide output (default behavior), which is equivalent to running without rank filtering.
215+
If ``--profile-mpi-ranks`` is not specified, all ranks provide output (default behavior), which is equivalent to running without rank filtering.
216216

217217
Supported MPI implementations
218218
-------------------------------
219219

220-
The rank detection supports the following MPI implementations and job launchers:
220+
The rank and world size detection automatically supports the following MPI implementations and job launchers:
221221

222-
- OpenMPI (``OMPI_COMM_WORLD_RANK``)
223-
- MVAPICH2 (``MV2_COMM_WORLD_RANK``)
224-
- MPICH (``PMI_ID``, ``PMI_RANK``)
225-
- SLURM (``SLURM_PROCID``)
226-
- Flux (``FLUX_TASK_RANK``)
222+
- OpenMPI (``OMPI_COMM_WORLD_RANK``, ``OMPI_COMM_WORLD_SIZE``)
223+
- MVAPICH2 (``MV2_COMM_WORLD_RANK``, ``MV2_COMM_WORLD_SIZE``)
224+
- MPICH (``PMI_ID``/``PMI_RANK``, ``PMI_SIZE``)
225+
- SLURM (``SLURM_PROCID``, ``SLURM_NPROCS``/``SLURM_NTASKS``)
226+
- Flux (``FLUX_TASK_RANK``, ``FLUX_JOB_SIZE``)
227+
228+
Custom MPI environment variables
229+
----------------------------------
230+
231+
For mixed environments or non-standard MPI configurations (such as interactive SLURM jobs using mpirun), you can specify custom environment variables for rank and world size detection:
232+
233+
.. code-block:: bash
234+
235+
# Use custom environment variables for rank and world size detection
236+
mpirun -n 16 rocprofv3 --hip-trace --profile-mpi-ranks 0-3 \
237+
--mpi-world-rank-var MY_CUSTOM_RANK \
238+
--mpi-world-size-var MY_CUSTOM_SIZE -- <application_path>
239+
240+
When ``--mpi-world-rank-var`` and/or ``--mpi-world-size-var`` are specified, they take precedence over automatic detection. These options are useful when:
241+
242+
- The MPI implementation uses non-standard environment variable names
243+
- You want to ensure specific environment variables are used instead of relying on auto-detection
244+
- Working in mixed MPI environments where multiple MPI-related variables might be present
245+
246+
The ``--mpi-world-size-var`` option is particularly useful when using ``--profile-mpi-ranks`` to ensure that the specified rank ranges are validated against the actual MPI world size, preventing out-of-range errors.

projects/rocprofiler-sdk/tests/rocprofv3/mpi-ranks/CMakeLists.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ if(MPIRUN_EXECUTABLE)
3434
$<TARGET_FILE:rocprofiler-sdk::rocprofv3> --hip-trace --kernel-trace
3535
--output-format csv json -d
3636
${CMAKE_CURRENT_BINARY_DIR}/mpi-ranks-trace/rank.%env{OMPI_COMM_WORLD_RANK}%
37-
-o out --mpi-ranks 0 ${PRELOAD_ARGS} -- $<TARGET_FILE:simple-transpose>
37+
-o out --profile-mpi-ranks 0 ${PRELOAD_ARGS} --
38+
$<TARGET_FILE:simple-transpose>
3839
DEPENDS simple-transpose
3940
TIMEOUT 120
4041
LABELS "integration-tests" "mpi-tests"
@@ -50,7 +51,8 @@ if(MPIRUN_EXECUTABLE)
5051
$<TARGET_FILE:rocprofiler-sdk::rocprofv3> --hip-trace --kernel-trace
5152
--output-format csv json -d
5253
${CMAKE_CURRENT_BINARY_DIR}/mpi-ranks-multiple-trace/rank.%env{OMPI_COMM_WORLD_RANK}%
53-
-o out --mpi-ranks 0-1,3 ${PRELOAD_ARGS} -- $<TARGET_FILE:simple-transpose>
54+
-o out --profile-mpi-ranks 0-1,3 ${PRELOAD_ARGS} --
55+
$<TARGET_FILE:simple-transpose>
5456
DEPENDS simple-transpose
5557
TIMEOUT 120
5658
LABELS "integration-tests" "mpi-tests"
@@ -86,7 +88,7 @@ rocprofiler_add_integration_execute_test(
8688
COMMAND
8789
$<TARGET_FILE:rocprofiler-sdk::rocprofv3> --hip-trace --kernel-trace
8890
--output-format csv json -d ${CMAKE_CURRENT_BINARY_DIR}/no-mpi-trace -o out
89-
--mpi-ranks 0 ${PRELOAD_ARGS} -- $<TARGET_FILE:simple-transpose>
91+
--profile-mpi-ranks 0 ${PRELOAD_ARGS} -- $<TARGET_FILE:simple-transpose>
9092
DEPENDS simple-transpose
9193
TIMEOUT 120
9294
LABELS "integration-tests"

0 commit comments

Comments
 (0)