From 13034d67b74fb9c213a89347f49f600b3d9de3ad Mon Sep 17 00:00:00 2001 From: Josh Romero Date: Wed, 29 Apr 2026 08:13:19 -0700 Subject: [PATCH 1/6] Add rank order option to grid descriptor configuration. Signed-off-by: Josh Romero --- docs/api/c_api.rst | 8 +++++++ docs/api/f_api.rst | 9 ++++++++ docs/basic_usage.rst | 13 +++++++++++ docs/env_vars.rst | 7 ++++-- docs/overview.rst | 4 ++-- include/cudecomp.h | 18 ++++++++++++--- include/internal/common.h | 36 +++++++++++++++++++++--------- src/autotune.cc | 16 ++------------ src/cudecomp.cc | 46 +++++++++++++++++++++++++-------------- src/cudecomp_m.cuf | 8 +++++++ 10 files changed, 118 insertions(+), 47 deletions(-) diff --git a/docs/api/c_api.rst b/docs/api/c_api.rst index 4fdb343e..7145af8c 100644 --- a/docs/api/c_api.rst +++ b/docs/api/c_api.rst @@ -96,6 +96,14 @@ __________________________ ------ +.. _cudecompRankOrder_t-ref: + +cudecompRankOrder_t +__________________ +.. doxygenenum :: cudecompRankOrder_t + +------ + .. _cudecompResult_t-ref: cudecompResult_t diff --git a/docs/api/f_api.rst b/docs/api/f_api.rst index 7a3aa94f..eef2c985 100644 --- a/docs/api/f_api.rst +++ b/docs/api/f_api.rst @@ -47,6 +47,7 @@ ________________________ :f integer gdims(3): dimensions of global data grid :f integer gdims_dist(3): dimensions of global data grid to use for distribution :f integer pdims(2): dimensions of process grid + :f cudecompRankOrder rank_order: process grid rank assignment order (default: CUDECOMP_RANK_ORDER_DEFAULT) :f cudecompTransposeCommType transpose_comm_backend: communication backend to use for transpose communication (default: CUDECOMP_TRANSPOSE_COMM_MPI_P2P) :f logical transpose_axis_contiguous(3): flag (by axis) indicating if memory should be contiguous along pencil axis (default: [false, false, false]) :f integer transpose_mem_order(3, 3): user-specified memory ordering by axis, overrides transpose_axis_contiguous setting; second index specifies axis, @@ -145,6 +146,14 @@ See documention for equivalent C enumerator, :ref:`cudecompAutotuneGridMode_t-re ------ +.. _cudecompRankOrder_t-f-ref: + +cudecompRankOrder +__________________ +See documention for equivalent C enumerator, :ref:`cudecompRankOrder_t-ref`. + +------ + .. _cudecompResult_t-f-ref: cudecompResult diff --git a/docs/basic_usage.rst b/docs/basic_usage.rst index 7673d50a..4f9e7c92 100644 --- a/docs/basic_usage.rst +++ b/docs/basic_usage.rst @@ -85,6 +85,19 @@ and :code:`pdims[1]` corresponds to :math:`P_{\text{cols}}`. In this example, we config%pdims = [2, 2] ! [P_rows, P_cols] +By default, ranks are assigned to the process grid in row-major order. To use column-major rank assignment, set +:code:`rank_order` in the configuration structure. + +.. tabs:: + + .. code-tab:: c++ + + config.rank_order = CUDECOMP_RANK_ORDER_COL_MAJOR; + + .. code-tab:: fortran + + config%rank_order = CUDECOMP_RANK_ORDER_COL_MAJOR + Next, we set the :code:`gdims` (global grid) entries in the configuration struct. These values correspond to the :math:`X`, :math:`Y`, and :math:`Z` dimensions of the global grid. In this example, we use a global grid with dimensions :math:`64 \times 64 \times 64`. diff --git a/docs/env_vars.rst b/docs/env_vars.rst index 502858f4..9dd86e8c 100644 --- a/docs/env_vars.rst +++ b/docs/env_vars.rst @@ -95,6 +95,9 @@ CUDECOMP_USE_COL_MAJOR_RANK_ORDER -------------------------------------- (since v0.6.0) -:code:`CUDECOMP_USE_COL_MAJOR_RANK_ORDER` controls the rank assignment order in the process grid. By default, ranks are assigned in row-major order for consistency with :code:`MPI_Cart_*` routines. When enabled, ranks are assigned in column-major order. +:code:`CUDECOMP_USE_COL_MAJOR_RANK_ORDER` is deprecated. Use the :code:`rank_order` field in +:code:`cudecompGridDescConfig_t`/:code:`cudecompGridDescConfig` instead. -Default setting is off (:code:`0`). Setting this variable to :code:`1` will enable column-major rank assignment. \ No newline at end of file +When :code:`rank_order` is left at :code:`CUDECOMP_RANK_ORDER_DEFAULT`, this environment variable is still honored for +backward compatibility. Setting this variable to :code:`1` enables column-major rank assignment; otherwise rank assignment +is row-major. Explicit :code:`rank_order` settings take precedence over this environment variable. diff --git a/docs/overview.rst b/docs/overview.rst index 993d7ddb..64f8d560 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -34,7 +34,8 @@ the *global grid*. The global grid is decomposed across :math:`N_{\text{GPU}}` processes in a 2D **process grid** with dimensions :math:`P_{\text{row}} \times P_{\text{col}}`. The processes are logically grouped by column and row index into :math:`P_{\text{row}}` *row* communicators and :math:`P_{\text{col}}` *column* communicators. By default, for consistency with :code:`MPI_Cart_*` routines, the ranks are assigned in a row-major ordering (i.e. row communicators -are composed of sequential ranks). This can be changed to column-major ordering using the :code:`CUDECOMP_USE_COL_MAJOR_RANK_ORDER` environment variable (see :ref:`env-var-section-ref`). +are composed of sequential ranks). This can be changed to column-major ordering using the :code:`rank_order` field in +:code:`cudecompGridDescConfig_t`/:code:`cudecompGridDescConfig`. cuDecomp will distribute the global domain data so that each process is assigned a unique *pencil* of data, with three different pencil configurations corresponding to different transposed configurations of the global domain. The domain can be @@ -62,4 +63,3 @@ shows the :math:`X`-pencil, :math:`Y`-pencil, and :math:`Z`-pencil configuration .. figure:: images/decomposition.png :align: center - diff --git a/include/cudecomp.h b/include/cudecomp.h index 902a6285..300da231 100644 --- a/include/cudecomp.h +++ b/include/cudecomp.h @@ -81,6 +81,16 @@ typedef enum { CUDECOMP_AUTOTUNE_GRID_HALO = 1 ///< Use halo communication to autotune process grid dimensions } cudecompAutotuneGridMode_t; +/** + * @brief This enum defines rank assignment order options for the process grid. + */ +typedef enum { + CUDECOMP_RANK_ORDER_DEFAULT = 0, ///< Use the default rank order. This resolves to row-major unless the + ///< deprecated CUDECOMP_USE_COL_MAJOR_RANK_ORDER environment variable is set. + CUDECOMP_RANK_ORDER_ROW_MAJOR = 1, ///< Assign ranks in row-major order (default) + CUDECOMP_RANK_ORDER_COL_MAJOR = 2 ///< Assign ranks in column-major order +} cudecompRankOrder_t; + /** * @brief This enum defines the possible values return values from cuDecomp. Most functions in the cuDecomp library * will return one of these values to indicate if an operation has completed successfully or an error occured. @@ -113,9 +123,11 @@ typedef struct cudecompGridDesc* cudecompGridDesc_t; */ typedef struct { // Grid information - int32_t gdims[3]; ///< dimensions of global data grid - int32_t gdims_dist[3]; ///< dimensions of global data grid to use for distribution - int32_t pdims[2]; ///< dimensions of process grid + int32_t gdims[3]; ///< dimensions of global data grid + int32_t gdims_dist[3]; ///< dimensions of global data grid to use for distribution + int32_t pdims[2]; ///< dimensions of process grid + cudecompRankOrder_t rank_order; ///< process grid rank assignment order + ///< (default: CUDECOMP_RANK_ORDER_DEFAULT) // Transpose settings cudecompTransposeCommBackend_t transpose_comm_backend; ///< communication backend to use for transpose communication diff --git a/include/internal/common.h b/include/internal/common.h index ea52a739..694ad01e 100644 --- a/include/internal/common.h +++ b/include/internal/common.h @@ -113,10 +113,10 @@ struct cudecompHandle { ""; // directory to write CSV performance reports, empty means no file writing // Miscellaneous - int32_t device_p2p_ce_count = 0; // number of P2P CEs available - int32_t device_num_sms = 0; // number of SMs on the device - int32_t device_max_threads_per_sm = 0; // maximum threads per SM - bool use_col_major_rank_order = false; // Flag to control whether to use column-major rank order + int32_t device_p2p_ce_count = 0; // number of P2P CEs available + int32_t device_num_sms = 0; // number of SMs on the device + int32_t device_max_threads_per_sm = 0; // maximum threads per SM + bool col_major_rank_order_env_warning_issued = false; // Warn once for deprecated rank order env var }; // Structure with information about row/column communicator @@ -221,15 +221,31 @@ using comm_count_t = int64_t; enum cudecompCommAxis { CUDECOMP_COMM_COL = 0, CUDECOMP_COMM_ROW = 1 }; +static inline void setProcessGridIndex(const cudecompHandle_t handle, cudecompGridDesc_t grid_desc) { + switch (grid_desc->config.rank_order) { + case CUDECOMP_RANK_ORDER_COL_MAJOR: + grid_desc->pidx[0] = handle->rank % grid_desc->config.pdims[0]; + grid_desc->pidx[1] = handle->rank / grid_desc->config.pdims[0]; + break; + case CUDECOMP_RANK_ORDER_DEFAULT: + case CUDECOMP_RANK_ORDER_ROW_MAJOR: + default: + grid_desc->pidx[0] = handle->rank / grid_desc->config.pdims[1]; + grid_desc->pidx[1] = handle->rank % grid_desc->config.pdims[1]; + break; + } +} + // Helper function to convert row or column rank to global rank -static inline int getGlobalRank(const cudecompHandle_t handle, const cudecompGridDesc_t grid_desc, - cudecompCommAxis axis, int axis_rank) { - if (handle->use_col_major_rank_order) { - // Column-major rank order +static inline int getGlobalRank(const cudecompHandle_t, const cudecompGridDesc_t grid_desc, cudecompCommAxis axis, + int axis_rank) { + switch (grid_desc->config.rank_order) { + case CUDECOMP_RANK_ORDER_COL_MAJOR: return (axis == CUDECOMP_COMM_ROW) ? grid_desc->pidx[0] + axis_rank * grid_desc->config.pdims[0] : grid_desc->config.pdims[0] * grid_desc->pidx[1] + axis_rank; - } else { - // Row-major rank order (default) + case CUDECOMP_RANK_ORDER_DEFAULT: + case CUDECOMP_RANK_ORDER_ROW_MAJOR: + default: return (axis == CUDECOMP_COMM_ROW) ? grid_desc->config.pdims[1] * grid_desc->pidx[0] + axis_rank : grid_desc->pidx[1] + axis_rank * grid_desc->config.pdims[1]; } diff --git a/src/autotune.cc b/src/autotune.cc index 5f5fda48..79594ac0 100644 --- a/src/autotune.cc +++ b/src/autotune.cc @@ -145,13 +145,7 @@ void autotuneTransposeBackend(cudecompHandle_t handle, cudecompGridDesc_t grid_d for (auto& pdim1 : pdim1_list) { grid_desc->config.pdims[0] = handle->nranks / pdim1; grid_desc->config.pdims[1] = pdim1; - if (handle->use_col_major_rank_order) { - grid_desc->pidx[0] = handle->rank % grid_desc->config.pdims[0]; - grid_desc->pidx[1] = handle->rank / grid_desc->config.pdims[0]; - } else { - grid_desc->pidx[0] = handle->rank / grid_desc->config.pdims[1]; - grid_desc->pidx[1] = handle->rank % grid_desc->config.pdims[1]; - } + setProcessGridIndex(handle, grid_desc); cudecompPencilInfo_t pinfo_x0, pinfo_x3; cudecompPencilInfo_t pinfo_y0, pinfo_y1, pinfo_y2, pinfo_y3; @@ -626,13 +620,7 @@ void autotuneHaloBackend(cudecompHandle_t handle, cudecompGridDesc_t grid_desc, for (auto& pdim1 : pdim1_list) { grid_desc->config.pdims[0] = handle->nranks / pdim1; grid_desc->config.pdims[1] = pdim1; - if (handle->use_col_major_rank_order) { - grid_desc->pidx[0] = handle->rank % grid_desc->config.pdims[0]; - grid_desc->pidx[1] = handle->rank / grid_desc->config.pdims[0]; - } else { - grid_desc->pidx[0] = handle->rank / grid_desc->config.pdims[1]; - grid_desc->pidx[1] = handle->rank % grid_desc->config.pdims[1]; - } + setProcessGridIndex(handle, grid_desc); cudecompPencilInfo_t pinfo; CHECK_CUDECOMP(cudecompGetPencilInfo(handle, grid_desc, &pinfo, options->halo_axis, options->halo_extents, diff --git a/src/cudecomp.cc b/src/cudecomp.cc index 3df7755f..147c917c 100644 --- a/src/cudecomp.cc +++ b/src/cudecomp.cc @@ -142,6 +142,15 @@ static void checkDataType(cudecompDataType_t dtype) { } } +static void checkRankOrder(cudecompRankOrder_t rank_order) { + switch (rank_order) { + case CUDECOMP_RANK_ORDER_DEFAULT: + case CUDECOMP_RANK_ORDER_ROW_MAJOR: + case CUDECOMP_RANK_ORDER_COL_MAJOR: return; + default: THROW_INVALID_USAGE("unknown rank order"); + } +} + static void checkHandle(cudecompHandle_t handle) { if (!handle || !handle->initialized) { THROW_INVALID_USAGE("invalid handle"); } } @@ -154,6 +163,7 @@ static void checkConfig(cudecompHandle_t handle, const cudecompGridDescConfig_t* bool autotune_halos) { if (!autotune_transpose) { checkTransposeCommBackend(config->transpose_comm_backend); } if (!autotune_halos) { checkHaloCommBackend(config->halo_comm_backend); } + checkRankOrder(config->rank_order); int pdims_prod = config->pdims[0] * config->pdims[1]; if (pdims_prod == 0) { @@ -368,9 +378,23 @@ static void getCudecompEnvVars(cudecompHandle_t& handle) { // Check CUDECOMP_PERFORMANCE_REPORT_WRITE_DIR (Directory for CSV performance reports) const char* performance_write_dir_str = std::getenv("CUDECOMP_PERFORMANCE_REPORT_WRITE_DIR"); if (performance_write_dir_str) { handle->performance_report_write_dir = std::string(performance_write_dir_str); } +} - // Check CUDECOMP_USE_COL_MAJOR_RANK_ORDER (Column-major rank assignment) - handle->use_col_major_rank_order = checkEnvVar("CUDECOMP_USE_COL_MAJOR_RANK_ORDER"); +static void resolveRankOrder(cudecompHandle_t handle, cudecompGridDesc_t grid_desc) { + const char* env_val = std::getenv("CUDECOMP_USE_COL_MAJOR_RANK_ORDER"); + if (env_val && !handle->col_major_rank_order_env_warning_issued) { + if (handle->rank == 0) { + printf("CUDECOMP:WARN: CUDECOMP_USE_COL_MAJOR_RANK_ORDER is deprecated and will be removed in a future " + "release. Set cudecompGridDescConfig_t::rank_order instead.\n"); + } + handle->col_major_rank_order_env_warning_issued = true; + } + + if (grid_desc->config.rank_order == CUDECOMP_RANK_ORDER_DEFAULT) { + grid_desc->config.rank_order = (env_val && checkEnvVar("CUDECOMP_USE_COL_MAJOR_RANK_ORDER")) + ? CUDECOMP_RANK_ORDER_COL_MAJOR + : CUDECOMP_RANK_ORDER_ROW_MAJOR; + } } #ifdef ENABLE_NVSHMEM @@ -631,6 +655,7 @@ cudecompResult_t cudecompGridDescCreate(cudecompHandle_t handle, cudecompGridDes grid_desc = new cudecompGridDesc; grid_desc->initialized = true; grid_desc->config = *config; + resolveRankOrder(handle, grid_desc); auto comm_backend = grid_desc->config.transpose_comm_backend; auto halo_comm_backend = grid_desc->config.halo_comm_backend; @@ -676,13 +701,7 @@ cudecompResult_t cudecompGridDescCreate(cudecompHandle_t handle, cudecompGridDes if (grid_desc->config.pdims[0] > 0 && grid_desc->config.pdims[1] > 0) { // If pdims are set, temporarily set up comm info stuctures to determine if we need to create a local NCCL // communicator - if (handle->use_col_major_rank_order) { - grid_desc->pidx[0] = handle->rank % grid_desc->config.pdims[0]; - grid_desc->pidx[1] = handle->rank / grid_desc->config.pdims[0]; - } else { - grid_desc->pidx[0] = handle->rank / grid_desc->config.pdims[1]; - grid_desc->pidx[1] = handle->rank % grid_desc->config.pdims[1]; - } + setProcessGridIndex(handle, grid_desc); int color_row = grid_desc->pidx[0]; MPI_Comm row_comm; CHECK_MPI(MPI_Comm_split(handle->mpi_comm, color_row, handle->rank, &row_comm)); @@ -766,13 +785,7 @@ cudecompResult_t cudecompGridDescCreate(cudecompHandle_t handle, cudecompGridDes } } - if (handle->use_col_major_rank_order) { - grid_desc->pidx[0] = handle->rank % grid_desc->config.pdims[0]; - grid_desc->pidx[1] = handle->rank / grid_desc->config.pdims[0]; - } else { - grid_desc->pidx[0] = handle->rank / grid_desc->config.pdims[1]; - grid_desc->pidx[1] = handle->rank % grid_desc->config.pdims[1]; - } + setProcessGridIndex(handle, grid_desc); // Setup final row and column communicators int color_row = grid_desc->pidx[0]; @@ -969,6 +982,7 @@ cudecompResult_t cudecompGridDescConfigSetDefaults(cudecompGridDescConfig_t* con config->gdims[i] = 0; config->gdims_dist[i] = 0; } + config->rank_order = CUDECOMP_RANK_ORDER_DEFAULT; // Transpose Options config->transpose_comm_backend = CUDECOMP_TRANSPOSE_COMM_MPI_P2P; diff --git a/src/cudecomp_m.cuf b/src/cudecomp_m.cuf index fb7bb044..36765b7c 100644 --- a/src/cudecomp_m.cuf +++ b/src/cudecomp_m.cuf @@ -48,6 +48,13 @@ module cudecomp enumerator :: CUDECOMP_AUTOTUNE_GRID_HALO = 1 end enum + ! enum for cuDecomp process grid rank order options + enum, bind(c) ! cudecompRankOrder + enumerator :: CUDECOMP_RANK_ORDER_DEFAULT = 0 + enumerator :: CUDECOMP_RANK_ORDER_ROW_MAJOR = 1 + enumerator :: CUDECOMP_RANK_ORDER_COL_MAJOR = 2 + end enum + ! enum for cuDecomp supported data types enum, bind(c) ! cudecompDataType enumerator :: CUDECOMP_FLOAT = -1 @@ -88,6 +95,7 @@ module cudecomp integer(c_int32_t) :: gdims(3) ! dimensions of data grid integer(c_int32_t) :: gdims_dist(3) ! dimensions of data grid for distribution integer(c_int32_t) :: pdims(2) ! dimensions of process grid + integer(c_int32_t) :: rank_order ! process grid rank assignment order ! Transpose Options integer(c_int32_t) :: transpose_comm_backend From 7c38f1d7bb77180f946b6d62dfd0b7c162dcdd29 Mon Sep 17 00:00:00 2001 From: Josh Romero Date: Wed, 29 Apr 2026 09:31:40 -0700 Subject: [PATCH 2/6] Add rank order options to test binaries. Signed-off-by: Josh Romero --- tests/cc/halo_test.cc | 8 +++++++- tests/cc/transpose_test.cc | 8 +++++++- tests/fortran/halo_test.f90 | 8 +++++++- tests/fortran/transpose_test.f90 | 8 +++++++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/cc/halo_test.cc b/tests/cc/halo_test.cc index 639f5a9e..64a8f8d5 100644 --- a/tests/cc/halo_test.cc +++ b/tests/cc/halo_test.cc @@ -198,6 +198,8 @@ static void usage(const char* pname) { "\t\tRow dimension of process grid. (default: 0, autotune) \n" "\t--pc\n" "\t\tColumn dimension of process grid. (default: 0, autotune) \n" + "\t--rank-order\n" + "\t\tProcess grid rank order. 0=default, 1=row-major, 2=column-major. (default: 0) \n" "\t--backend" "\t\tHalo communication backend (default: 0, autotune) \n" "\t--ac\n" @@ -232,6 +234,7 @@ struct haloTestArgs { int gz = 256; int pr = 0; int pc = 0; + cudecompRankOrder_t rank_order = CUDECOMP_RANK_ORDER_DEFAULT; cudecompHaloCommBackend_t comm_backend = static_cast(0); bool axis_contiguous; std::array gdims_dist{}; @@ -259,6 +262,7 @@ static haloTestArgs parse_arguments(const std::string& arguments) { {"backend", required_argument, 0, 'b'}, {"pr", required_argument, 0, 'r'}, {"pc", required_argument, 0, 'c'}, + {"rank-order", required_argument, 0, 'R'}, {"ac", required_argument, 0, '3'}, {"gd", required_argument, 0, '4'}, {"hex", required_argument, 0, '7'}, @@ -277,7 +281,7 @@ static haloTestArgs parse_arguments(const std::string& arguments) { {0, 0, 0, 0}}; int option_index = 0; - int ch = getopt_long(argc, argv, "x:y:z:b:r:c:3:4:7:8:9:e:f:g:a:q:&:*:(:mh", long_options, &option_index); + int ch = getopt_long(argc, argv, "x:y:z:b:r:c:R:3:4:7:8:9:e:f:g:a:q:&:*:(:mh", long_options, &option_index); if (ch == -1) break; switch (ch) { @@ -288,6 +292,7 @@ static haloTestArgs parse_arguments(const std::string& arguments) { case 'b': args.comm_backend = static_cast(atoi(optarg)); break; case 'r': args.pr = atoi(optarg); break; case 'c': args.pc = atoi(optarg); break; + case 'R': args.rank_order = static_cast(atoi(optarg)); break; case '3': args.axis_contiguous = atoi(optarg); break; case '4': optind--; @@ -361,6 +366,7 @@ static int run_test(const std::string& arguments, bool silent) { CHECK_CUDECOMP(cudecompGridDescConfigSetDefaults(&config)); config.pdims[0] = pdims[0]; config.pdims[1] = pdims[1]; + config.rank_order = args.rank_order; config.gdims[0] = gdims[0]; config.gdims[1] = gdims[1]; config.gdims[2] = gdims[2]; diff --git a/tests/cc/transpose_test.cc b/tests/cc/transpose_test.cc index d928385a..5b0a414e 100644 --- a/tests/cc/transpose_test.cc +++ b/tests/cc/transpose_test.cc @@ -176,6 +176,8 @@ static void usage(const char* pname) { "\t\tRow dimension of process grid. (default: 0, autotune) \n" "\t--pc\n" "\t\tColumn dimension of process grid. (default: 0, autotune) \n" + "\t--rank-order\n" + "\t\tProcess grid rank order. 0=default, 1=row-major, 2=column-major. (default: 0) \n" "\t--backend" "\t\tTranspose communication backend (default: 0, autotune) \n" "\t--acx\n" @@ -214,6 +216,7 @@ struct transposeTestArgs { int gz = 256; int pr = 0; int pc = 0; + cudecompRankOrder_t rank_order = CUDECOMP_RANK_ORDER_DEFAULT; cudecompTransposeCommBackend_t comm_backend = static_cast(0); std::array axis_contiguous{}; std::array gdims_dist{}; @@ -244,6 +247,7 @@ static transposeTestArgs parse_arguments(const std::string& arguments) { {"backend", required_argument, 0, 'b'}, {"pr", required_argument, 0, 'r'}, {"pc", required_argument, 0, 'c'}, + {"rank-order", required_argument, 0, 'R'}, {"acx", required_argument, 0, '1'}, {"acy", required_argument, 0, '2'}, {"acz", required_argument, 0, '3'}, @@ -261,7 +265,7 @@ static transposeTestArgs parse_arguments(const std::string& arguments) { {0, 0, 0, 0}}; int option_index = 0; - int ch = getopt_long(argc, argv, "x:y:z:b:r:c:1:2:3:4:7:8:9:&:*:(:q:omh", long_options, &option_index); + int ch = getopt_long(argc, argv, "x:y:z:b:r:c:R:1:2:3:4:7:8:9:&:*:(:q:omh", long_options, &option_index); if (ch == -1) break; switch (ch) { @@ -272,6 +276,7 @@ static transposeTestArgs parse_arguments(const std::string& arguments) { case 'b': args.comm_backend = static_cast(atoi(optarg)); break; case 'r': args.pr = atoi(optarg); break; case 'c': args.pc = atoi(optarg); break; + case 'R': args.rank_order = static_cast(atoi(optarg)); break; case '1': args.axis_contiguous[0] = atoi(optarg); break; case '2': args.axis_contiguous[1] = atoi(optarg); break; case '3': args.axis_contiguous[2] = atoi(optarg); break; @@ -380,6 +385,7 @@ static int run_test(const std::string& arguments, bool silent) { CHECK_CUDECOMP(cudecompGridDescConfigSetDefaults(&config)); config.pdims[0] = pdims[0]; config.pdims[1] = pdims[1]; + config.rank_order = args.rank_order; config.gdims[0] = gdims[0]; config.gdims[1] = gdims[1]; config.gdims[2] = gdims[2]; diff --git a/tests/fortran/halo_test.f90 b/tests/fortran/halo_test.f90 index ec606acf..ce29191d 100644 --- a/tests/fortran/halo_test.f90 +++ b/tests/fortran/halo_test.f90 @@ -216,7 +216,7 @@ function run_test(arguments, silent) result(res) integer :: padding(3) integer :: mem_order(3) logical :: use_managed_memory - integer :: pr, pc + integer :: pr, pc, rank_order integer :: axis ! MPI @@ -261,6 +261,7 @@ function run_test(arguments, silent) result(res) gz = 256 pr = 0 pc = 0 + rank_order = CUDECOMP_RANK_ORDER_DEFAULT comm_backend = 0 axis_contiguous = .false. gdims_dist(:) = 0 @@ -303,6 +304,10 @@ function run_test(arguments, silent) result(res) read(args(i+1), *) arg read(arg, *) pc skip_count = 1 + case('--rank-order') + read(args(i+1), *) arg + read(arg, *) rank_order + skip_count = 1 case('--ac') read(args(i+1), *) arg read(arg, *) iarg @@ -391,6 +396,7 @@ function run_test(arguments, silent) result(res) ! Setup grid descriptor CHECK_CUDECOMP(cudecompGridDescConfigSetDefaults(config)) config%pdims = pdims + config%rank_order = rank_order gdims = [gx, gy, gz] config%gdims = gdims config%gdims_dist = gdims_dist diff --git a/tests/fortran/transpose_test.f90 b/tests/fortran/transpose_test.f90 index 7060d993..ac65d513 100644 --- a/tests/fortran/transpose_test.f90 +++ b/tests/fortran/transpose_test.f90 @@ -166,7 +166,7 @@ function run_test(arguments, silent) result(res) integer :: padding_x(3), padding_y(3), padding_z(3) integer :: mem_order(3, 3) logical :: out_of_place, use_managed_memory - integer :: pr, pc + integer :: pr, pc, rank_order ! MPI integer :: local_rank, ierr @@ -214,6 +214,7 @@ function run_test(arguments, silent) result(res) gz = 256 pr = 0 pc = 0 + rank_order = CUDECOMP_RANK_ORDER_DEFAULT comm_backend = 0 axis_contiguous(:) = .false. gdims_dist(:) = 0 @@ -259,6 +260,10 @@ function run_test(arguments, silent) result(res) read(args(i+1), *) arg read(arg, *) pc skip_count = 1 + case('--rank-order') + read(args(i+1), *) arg + read(arg, *) rank_order + skip_count = 1 case('--acx') read(args(i+1), *) arg read(arg, *) iarg @@ -353,6 +358,7 @@ function run_test(arguments, silent) result(res) ! Setup grid descriptor CHECK_CUDECOMP(cudecompGridDescConfigSetDefaults(config)) config%pdims = pdims + config%rank_order = rank_order gdims = [gx, gy, gz] config%gdims = gdims config%gdims_dist = gdims_dist From 1ce60e21c6e217a22e2dc43690c7800c1caed88e Mon Sep 17 00:00:00 2001 From: Josh Romero Date: Wed, 29 Apr 2026 10:23:25 -0700 Subject: [PATCH 3/6] Set autotuning pdim traversal order based on rank order setting. Signed-off-by: Josh Romero --- src/autotune.cc | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/autotune.cc b/src/autotune.cc index 79594ac0..01c9c668 100644 --- a/src/autotune.cc +++ b/src/autotune.cc @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -50,6 +51,20 @@ static std::vector getFactors(int N) { return factors; } +static std::vector> getPdimCandidates(int nranks, cudecompRankOrder_t rank_order) { + std::vector> pdim_list; + auto factors = getFactors(nranks); + for (auto& factor : factors) { + // Grow the process-grid dimension mapped to contiguous ranks first, preserving the locality-first traversal. + if (rank_order == CUDECOMP_RANK_ORDER_COL_MAJOR) { + pdim_list.push_back({factor, nranks / factor}); + } else { + pdim_list.push_back({nranks / factor, factor}); + } + } + return pdim_list; +} + template static std::vector processTimings(cudecompHandle_t handle, std::vector times, T scale = 1) { std::sort(times.begin(), times.end()); double t_min = times[0]; @@ -122,11 +137,11 @@ void autotuneTransposeBackend(cudecompHandle_t handle, cudecompGridDesc_t grid_d if (!options->transpose_use_inplace_buffers[i]) need_data2 = true; } - std::vector pdim1_list; + std::vector> pdim_list; if (autotune_pdims) { - pdim1_list = getFactors(handle->nranks); + pdim_list = getPdimCandidates(handle->nranks, grid_desc->config.rank_order); } else { - pdim1_list = {grid_desc->config.pdims[1]}; + pdim_list.push_back({grid_desc->config.pdims[0], grid_desc->config.pdims[1]}); } int32_t pdims_best[2]{grid_desc->config.pdims[0], grid_desc->config.pdims[1]}; @@ -142,9 +157,9 @@ void autotuneTransposeBackend(cudecompHandle_t handle, cudecompGridDesc_t grid_d int64_t work_sz = 0; bool valid = false; - for (auto& pdim1 : pdim1_list) { - grid_desc->config.pdims[0] = handle->nranks / pdim1; - grid_desc->config.pdims[1] = pdim1; + for (auto& pdims : pdim_list) { + grid_desc->config.pdims[0] = pdims[0]; + grid_desc->config.pdims[1] = pdims[1]; setProcessGridIndex(handle, grid_desc); cudecompPencilInfo_t pinfo_x0, pinfo_x3; @@ -598,11 +613,11 @@ void autotuneHaloBackend(cudecompHandle_t handle, cudecompGridDesc_t grid_desc, #endif } - std::vector pdim1_list; + std::vector> pdim_list; if (autotune_pdims) { - pdim1_list = getFactors(handle->nranks); + pdim_list = getPdimCandidates(handle->nranks, grid_desc->config.rank_order); } else { - pdim1_list = {grid_desc->config.pdims[1]}; + pdim_list.push_back({grid_desc->config.pdims[0], grid_desc->config.pdims[1]}); } int32_t pdims_best[2]{grid_desc->config.pdims[0], grid_desc->config.pdims[1]}; @@ -617,9 +632,9 @@ void autotuneHaloBackend(cudecompHandle_t handle, cudecompGridDesc_t grid_desc, int64_t work_sz = 0; bool valid = false; - for (auto& pdim1 : pdim1_list) { - grid_desc->config.pdims[0] = handle->nranks / pdim1; - grid_desc->config.pdims[1] = pdim1; + for (auto& pdims : pdim_list) { + grid_desc->config.pdims[0] = pdims[0]; + grid_desc->config.pdims[1] = pdims[1]; setProcessGridIndex(handle, grid_desc); cudecompPencilInfo_t pinfo; From 6caf44dfbcc1934b2a4fe27689c641c360ec392f Mon Sep 17 00:00:00 2001 From: Josh Romero Date: Wed, 29 Apr 2026 14:20:51 -0700 Subject: [PATCH 4/6] Add short rank order test configs. Signed-off-by: Josh Romero --- tests/test_config.yaml | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/test_config.yaml b/tests/test_config.yaml index f1a94d54..667cc1fb 100644 --- a/tests/test_config.yaml +++ b/tests/test_config.yaml @@ -107,6 +107,23 @@ transpose_test_ac: &transpose_test_ac test_mem_order: False +transpose_test_rank_order: &transpose_test_rank_order + <<: *transpose_test_base + args : ['backend', + 'gx', 'gy', 'gz', + 'gd', + 'hex' ,'hey', 'hez', + 'pdx', 'pdy', 'pdz', + 'rank-order'] + + backend: [1] # Limit this testing to one backend + dtypes: ['R32'] # Limit to one data type + rank-order: [0, 1, 2] + out_of_place: [False] + managed_memory : [False] + + test_mem_order: False + transpose_test_cc: <<: *transpose_test executable_prefix: 'cc/transpose_test' @@ -131,6 +148,10 @@ transpose_test_ac_cc: <<: *transpose_test_ac executable_prefix: 'cc/transpose_test' +transpose_test_rank_order_cc: + <<: *transpose_test_rank_order + executable_prefix: 'cc/transpose_test' + transpose_test_fortran: <<: *transpose_test executable_prefix: 'fortran/transpose_test' @@ -161,6 +182,11 @@ transpose_test_ac_fortran: executable_prefix: 'fortran/transpose_test' fortran_indexing: true +transpose_test_rank_order_fortran: + <<: *transpose_test_rank_order + executable_prefix: 'fortran/transpose_test' + fortran_indexing: true + halo_test_base: &halo_test_base <<: *base @@ -276,6 +302,24 @@ halo_test_ac: &halo_test_ac ac: [0, 1] + test_mem_order: False + +halo_test_rank_order: &halo_test_rank_order + <<: *halo_test_base + args : ['backend', + 'gx', 'gy', 'gz', + 'gd', + 'hex' ,'hey', 'hez', + 'hpx', 'hpy', 'hpz', + 'pdx', 'pdy', 'pdz', + 'ax', + 'rank-order'] + + backend: [1] # Limit this testing to one backend + dtypes: ['R32'] # Limit to one data type + rank-order: [0, 1, 2] + + test_mem_order: False halo_test_cc: @@ -302,6 +346,10 @@ halo_test_ac_cc: <<: *halo_test_ac executable_prefix: 'cc/halo_test' +halo_test_rank_order_cc: + <<: *halo_test_rank_order + executable_prefix: 'cc/halo_test' + halo_test_fortran: <<: *halo_test ax: [1, 2, 3] @@ -337,3 +385,8 @@ halo_test_ac_fortran: ax: [1, 2, 3] executable_prefix: 'fortran/halo_test' fortran_indexing: true + +halo_test_rank_order_fortran: + <<: *halo_test_rank_order + executable_prefix: 'fortran/halo_test' + fortran_indexing: true From 4d1433cc66fd52336b7103b770f234edda3ff311 Mon Sep 17 00:00:00 2001 From: Josh Romero Date: Wed, 29 Apr 2026 14:31:32 -0700 Subject: [PATCH 5/6] Fix halo test configuration. Signed-off-by: Josh Romero --- tests/test_config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_config.yaml b/tests/test_config.yaml index 667cc1fb..e70c92c4 100644 --- a/tests/test_config.yaml +++ b/tests/test_config.yaml @@ -388,5 +388,6 @@ halo_test_ac_fortran: halo_test_rank_order_fortran: <<: *halo_test_rank_order + ax: [1, 2, 3] executable_prefix: 'fortran/halo_test' fortran_indexing: true From 7c40441a6f6e5b68aed6098aea7f06fab7f919ab Mon Sep 17 00:00:00 2001 From: Josh Romero Date: Wed, 29 Apr 2026 14:39:42 -0700 Subject: [PATCH 6/6] Further adjustments to halo rank order tests. Signed-off-by: Josh Romero --- tests/test_config.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_config.yaml b/tests/test_config.yaml index e70c92c4..5fd14893 100644 --- a/tests/test_config.yaml +++ b/tests/test_config.yaml @@ -318,7 +318,8 @@ halo_test_rank_order: &halo_test_rank_order backend: [1] # Limit this testing to one backend dtypes: ['R32'] # Limit to one data type rank-order: [0, 1, 2] - + managed_memory : [False] + out_of_place : [False] test_mem_order: False