From d3c78dfa6933fd30471a75a33c33a24d35e75972 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Fri, 24 Oct 2025 13:44:14 -0400 Subject: [PATCH 01/24] First draft and TODOs for notified comm Signed-off-by: Joseph Schuchart --- ompi/mca/osc/osc.h | 2 ++ ompi/mca/osc/sm/osc_sm.h | 4 ++++ ompi/mca/osc/sm/osc_sm_comm.c | 35 ++++++++++++++++++++++++++++++ ompi/mca/osc/sm/osc_sm_component.c | 2 ++ 4 files changed, 43 insertions(+) diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index 39063ef0914..c8f77404c1c 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -370,6 +370,8 @@ typedef int (*ompi_osc_base_module_flush_local_all_fn_t)(struct ompi_win_t *win) * free to create a structure that inherits this one for use as the * module structure. */ + + // TODO: extend the struct and add pointers to put/get_with_notify functions struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_win_shared_query_fn_t osc_win_shared_query; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index 363d3429a63..23afacd7d49 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -79,6 +79,8 @@ struct ompi_osc_sm_module_t { size_t *sizes; void **bases; ptrdiff_t *disp_units; + uint64_t **notify_counters; + ompi_group_t *start_group; ompi_group_t *post_group; @@ -105,6 +107,8 @@ int ompi_osc_sm_detach(struct ompi_win_t *win, const void *base); int ompi_osc_sm_free(struct ompi_win_t *win); +// TODO: add put/get_with_notify prototypes + int ompi_osc_sm_put(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index bbd5873bf96..f9bae370870 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -267,6 +267,41 @@ ompi_osc_sm_get(void *origin_addr, } +int +ompi_osc_sm_get_with_notify(void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win) +{ + int ret; + ompi_osc_sm_module_t *module = + (ompi_osc_sm_module_t*) win->w_osc_module; + void *remote_address; + + OPAL_OUTPUT_VERBOSE((50, ompi_osc_base_framework.framework_output, + "get: 0x%lx, %zu, %s, %d, %d, %zu, %s, 0x%lx", + (unsigned long) origin_addr, origin_count, + origin_dt->name, target, (int) target_disp, + target_count, target_dt->name, + (unsigned long) win)); + + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; + + ret = ompi_datatype_sndrcv(remote_address, target_count, target_dt, + origin_addr, origin_count, origin_dt); + // TODO: do the same for put_with_notify + opal_atomic_rmb(); + opal_atomic_add(&module->notify_counters[target][notify], 1); + + return ret; +} + + int ompi_osc_sm_accumulate(const void *origin_addr, size_t origin_count, diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index ad2b3cae25a..1ad9a48cfd2 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -70,6 +70,8 @@ ompi_osc_sm_component_t mca_osc_sm_component = { MCA_BASE_COMPONENT_INIT(ompi, osc, sm) +// TODO: extend the struct and add pointers to put/get_with_notify functions +// TODO: extend it to rput/rget_with_notify as well ompi_osc_sm_module_t ompi_osc_sm_module_template = { { .osc_win_shared_query = ompi_osc_sm_shared_query, From 152c28ca7c6e47373770e5ef0ce2fea4a27ba9ab Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Tue, 4 Nov 2025 04:42:00 +0000 Subject: [PATCH 02/24] osc/sm: Add notification support for put/get operations This commit adds notification support to the OSC SM component by implementing the put_with_notify, get_with_notify, rput_with_notify, and rget_with_notify functions. These functions perform the same operations as their non-notify counterparts but also increment notification counters after the data transfer completes. The changes include: - Added function pointer types for notify variants in osc.h - Added function prototypes in osc_sm.h - Implemented the notify functions in osc_sm_comm.c - Updated the module template to register the new functions - Removed TODO comments that have been addressed Signed-off-by: Joseph Antony --- ompi/mca/osc/osc.h | 44 +++++++++- ompi/mca/osc/sm/osc_sm.h | 42 ++++++++++ ompi/mca/osc/sm/osc_sm_comm.c | 130 ++++++++++++++++++++++++++++- ompi/mca/osc/sm/osc_sm_component.c | 6 +- 4 files changed, 217 insertions(+), 5 deletions(-) diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index c8f77404c1c..bd05a6f11b7 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -216,6 +216,15 @@ typedef int (*ompi_osc_base_module_put_fn_t)(const void *origin_addr, struct ompi_datatype_t *target_dt, struct ompi_win_t *win); +typedef int (*ompi_osc_base_module_put_with_notify_fn_t)(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win); typedef int (*ompi_osc_base_module_get_fn_t)(void *origin_addr, size_t origin_count, @@ -226,6 +235,15 @@ typedef int (*ompi_osc_base_module_get_fn_t)(void *origin_addr, struct ompi_datatype_t *target_dt, struct ompi_win_t *win); +typedef int (*ompi_osc_base_module_get_with_notify_fn_t)(void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win); typedef int (*ompi_osc_base_module_accumulate_fn_t)(const void *origin_addr, size_t origin_count, @@ -276,6 +294,17 @@ typedef int (*ompi_osc_base_module_rput_fn_t)(const void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); +typedef int (*ompi_osc_base_module_rput_with_notify_fn_t)(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **request); + typedef int (*ompi_osc_base_module_rget_fn_t)(void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, @@ -286,6 +315,16 @@ typedef int (*ompi_osc_base_module_rget_fn_t)(void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); +typedef int (*ompi_osc_base_module_rget_with_notify_fn_t)(void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **request); typedef int (*ompi_osc_base_module_raccumulate_fn_t)(const void *origin_addr, size_t origin_count, @@ -371,7 +410,6 @@ typedef int (*ompi_osc_base_module_flush_local_all_fn_t)(struct ompi_win_t *win) * module structure. */ - // TODO: extend the struct and add pointers to put/get_with_notify functions struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_win_shared_query_fn_t osc_win_shared_query; @@ -380,14 +418,18 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_free_fn_t osc_free; ompi_osc_base_module_put_fn_t osc_put; + ompi_osc_base_module_put_with_notify_fn_t osc_put_with_notify; ompi_osc_base_module_get_fn_t osc_get; + ompi_osc_base_module_get_with_notify_fn_t osc_get_with_notify; ompi_osc_base_module_accumulate_fn_t osc_accumulate; ompi_osc_base_module_compare_and_swap_fn_t osc_compare_and_swap; ompi_osc_base_module_fetch_and_op_fn_t osc_fetch_and_op; ompi_osc_base_module_get_accumulate_fn_t osc_get_accumulate; ompi_osc_base_module_rput_fn_t osc_rput; + ompi_osc_base_module_rput_with_notify_fn_t osc_rput_with_notify; ompi_osc_base_module_rget_fn_t osc_rget; + ompi_osc_base_module_rget_with_notify_fn_t osc_rget_with_notify; ompi_osc_base_module_raccumulate_fn_t osc_raccumulate; ompi_osc_base_module_rget_accumulate_fn_t osc_rget_accumulate; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index 23afacd7d49..b7d6dadfd49 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -118,6 +118,16 @@ int ompi_osc_sm_put(const void *origin_addr, struct ompi_datatype_t *target_dt, struct ompi_win_t *win); + int ompi_osc_sm_put_with_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win); + int ompi_osc_sm_get(void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, @@ -127,6 +137,16 @@ int ompi_osc_sm_get(void *origin_addr, struct ompi_datatype_t *target_dt, struct ompi_win_t *win); +int ompi_osc_sm_get_with_notify(void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win); + int ompi_osc_sm_accumulate(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, @@ -176,6 +196,17 @@ int ompi_osc_sm_rput(const void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); +int ompi_osc_sm_rput_with_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **request); + int ompi_osc_sm_rget(void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, @@ -186,6 +217,17 @@ int ompi_osc_sm_rget(void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); +int ompi_osc_sm_rget_with_notify(void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **request); + int ompi_osc_sm_raccumulate(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index f9bae370870..a2e3a5cce1f 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -59,6 +59,49 @@ ompi_osc_sm_rput(const void *origin_addr, return OMPI_SUCCESS; } +int +ompi_osc_sm_rput_with_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **ompi_req) +{ + int ret; + ompi_osc_sm_module_t *module = + (ompi_osc_sm_module_t*) win->w_osc_module; + void *remote_address; + + OPAL_OUTPUT_VERBOSE((50, ompi_osc_base_framework.framework_output, + "rput_notify: 0x%lx, %zu, %s, %d, %d, %zu, %s, %d, 0x%lx", + (unsigned long) origin_addr, origin_count, + origin_dt->name, target, (int) target_disp, + target_count, target_dt->name, + notify, + (unsigned long) win)); + + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; + + ret = ompi_datatype_sndrcv((void *)origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt); + if (OMPI_SUCCESS != ret) { + return ret; + } + + /* the only valid field of RMA request status is the MPI_ERROR field. + * ompi_request_empty has status MPI_SUCCESS and indicates the request is + * complete. */ + *ompi_req = &ompi_request_empty; + + opal_atomic_wmb(); + opal_atomic_add(&module->notify_counters[target][notify], 1); + + return OMPI_SUCCESS; +} int ompi_osc_sm_rget(void *origin_addr, @@ -99,6 +142,49 @@ ompi_osc_sm_rget(void *origin_addr, return OMPI_SUCCESS; } +int +ompi_osc_sm_rget_with_notify(void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **ompi_req) +{ + int ret; + ompi_osc_sm_module_t *module = + (ompi_osc_sm_module_t*) win->w_osc_module; + void *remote_address; + + OPAL_OUTPUT_VERBOSE((50, ompi_osc_base_framework.framework_output, + "rget_notify: 0x%lx, %zu, %s, %d, %d, %zu, %s, %d, 0x%lx", + (unsigned long) origin_addr, origin_count, + origin_dt->name, target, (int) target_disp, + target_count, target_dt->name, + notify, + (unsigned long) win)); + + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; + + ret = ompi_datatype_sndrcv(remote_address, target_count, target_dt, + origin_addr, origin_count, origin_dt); + if (OMPI_SUCCESS != ret) { + return ret; + } + + /* the only valid field of RMA request status is the MPI_ERROR field. + * ompi_request_empty has status MPI_SUCCESS and indicates the request is + * complete. */ + *ompi_req = &ompi_request_empty; + + opal_atomic_rmb(); + opal_atomic_add(&module->notify_counters[target][notify], 1); + + return OMPI_SUCCESS; +} int ompi_osc_sm_raccumulate(const void *origin_addr, @@ -236,6 +322,44 @@ ompi_osc_sm_put(const void *origin_addr, } +int +ompi_osc_sm_put_with_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + int notify, + struct ompi_win_t *win) +{ +int ret; +ompi_osc_sm_module_t *module = + (ompi_osc_sm_module_t*) win->w_osc_module; +void *remote_address; + +OPAL_OUTPUT_VERBOSE((50, ompi_osc_base_framework.framework_output, + "put_notify: 0x%lx, %zu, %s, %d, %d, %zu, %s, %d, 0x%lx", + (unsigned long) origin_addr, origin_count, + origin_dt->name, target, (int) target_disp, + target_count, target_dt->name, + notify, + (unsigned long) win)); + +remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; + +ret = ompi_datatype_sndrcv((void *)origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt); +if (OMPI_SUCCESS != ret) { + return ret; +} + +opal_atomic_wmb(); +opal_atomic_add(&module->notify_counters[target][notify], 1); + +return ret; +} + int ompi_osc_sm_get(void *origin_addr, size_t origin_count, @@ -294,7 +418,9 @@ ompi_osc_sm_get_with_notify(void *origin_addr, ret = ompi_datatype_sndrcv(remote_address, target_count, target_dt, origin_addr, origin_count, origin_dt); - // TODO: do the same for put_with_notify + if (OMPI_SUCCESS != ret) { + return ret; + } opal_atomic_rmb(); opal_atomic_add(&module->notify_counters[target][notify], 1); @@ -473,4 +599,4 @@ ompi_osc_sm_fetch_and_op(const void *origin_addr, opal_atomic_unlock(&module->node_states[target].accumulate_lock); return OMPI_SUCCESS;; -} +} \ No newline at end of file diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index 1ad9a48cfd2..11f0ccc2e47 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -70,8 +70,6 @@ ompi_osc_sm_component_t mca_osc_sm_component = { MCA_BASE_COMPONENT_INIT(ompi, osc, sm) -// TODO: extend the struct and add pointers to put/get_with_notify functions -// TODO: extend it to rput/rget_with_notify as well ompi_osc_sm_module_t ompi_osc_sm_module_template = { { .osc_win_shared_query = ompi_osc_sm_shared_query, @@ -81,14 +79,18 @@ ompi_osc_sm_module_t ompi_osc_sm_module_template = { .osc_free = ompi_osc_sm_free, .osc_put = ompi_osc_sm_put, + .osc_put_with_notify = ompi_osc_sm_put_with_notify, .osc_get = ompi_osc_sm_get, + .osc_get_with_notify = ompi_osc_sm_get_with_notify, .osc_accumulate = ompi_osc_sm_accumulate, .osc_compare_and_swap = ompi_osc_sm_compare_and_swap, .osc_fetch_and_op = ompi_osc_sm_fetch_and_op, .osc_get_accumulate = ompi_osc_sm_get_accumulate, .osc_rput = ompi_osc_sm_rput, + .osc_rput_with_notify = ompi_osc_sm_rput_with_notify, .osc_rget = ompi_osc_sm_rget, + .osc_rget_with_notify = ompi_osc_sm_rget_with_notify, .osc_raccumulate = ompi_osc_sm_raccumulate, .osc_rget_accumulate = ompi_osc_sm_rget_accumulate, From f1e07c8db42207bd888a89fcd531f1962cdc81a8 Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Tue, 4 Nov 2025 17:03:59 +0000 Subject: [PATCH 03/24] osc/sm: Nit picking edits Signed-off-by: Joseph Antony --- ompi/mca/osc/sm/osc_sm_comm.c | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index a2e3a5cce1f..ba19d8c08cf 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -333,31 +333,31 @@ ompi_osc_sm_put_with_notify(const void *origin_addr, int notify, struct ompi_win_t *win) { -int ret; -ompi_osc_sm_module_t *module = - (ompi_osc_sm_module_t*) win->w_osc_module; -void *remote_address; - -OPAL_OUTPUT_VERBOSE((50, ompi_osc_base_framework.framework_output, - "put_notify: 0x%lx, %zu, %s, %d, %d, %zu, %s, %d, 0x%lx", - (unsigned long) origin_addr, origin_count, - origin_dt->name, target, (int) target_disp, - target_count, target_dt->name, - notify, - (unsigned long) win)); - -remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; - -ret = ompi_datatype_sndrcv((void *)origin_addr, origin_count, origin_dt, - remote_address, target_count, target_dt); -if (OMPI_SUCCESS != ret) { - return ret; -} + int ret; + ompi_osc_sm_module_t *module = + (ompi_osc_sm_module_t*) win->w_osc_module; + void *remote_address; + + OPAL_OUTPUT_VERBOSE((50, ompi_osc_base_framework.framework_output, + "put_notify: 0x%lx, %zu, %s, %d, %d, %zu, %s, %d, 0x%lx", + (unsigned long) origin_addr, origin_count, + origin_dt->name, target, (int) target_disp, + target_count, target_dt->name, + notify, + (unsigned long) win)); + + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; + + ret = ompi_datatype_sndrcv((void *)origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt); + if (OMPI_SUCCESS != ret) { + return ret; + } -opal_atomic_wmb(); -opal_atomic_add(&module->notify_counters[target][notify], 1); + opal_atomic_wmb(); + opal_atomic_add(&module->notify_counters[target][notify], 1); -return ret; + return ret; } int @@ -419,7 +419,7 @@ ompi_osc_sm_get_with_notify(void *origin_addr, ret = ompi_datatype_sndrcv(remote_address, target_count, target_dt, origin_addr, origin_count, origin_dt); if (OMPI_SUCCESS != ret) { - return ret; + return ret; } opal_atomic_rmb(); opal_atomic_add(&module->notify_counters[target][notify], 1); @@ -598,5 +598,5 @@ ompi_osc_sm_fetch_and_op(const void *origin_addr, done: opal_atomic_unlock(&module->node_states[target].accumulate_lock); - return OMPI_SUCCESS;; -} \ No newline at end of file + return OMPI_SUCCESS; +} From 06d61ed8d36dded674f9789928a831ae954cdaaa Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Wed, 19 Nov 2025 12:29:14 -0500 Subject: [PATCH 04/24] Public APIs for: put_with_notify get_with_notify Signed-off-by: Joseph Antony --- ompi/include/mpi.h.in | 29 ++++++++ ompi/include/mpif-values.py | 1 + ompi/mca/osc/osc.h | 16 ++--- ompi/mca/osc/sm/osc_sm.h | 10 +-- ompi/mca/osc/sm/osc_sm_comm.c | 8 +-- ompi/mca/osc/sm/osc_sm_component.c | 8 +-- ompi/mpi/bindings/ompi_bindings/consts.py | 1 + ompi/mpi/c/Makefile.am | 2 + ompi/mpi/c/get_notify.c.in | 77 ++++++++++++++++++++++ ompi/mpi/c/put_notify.c.in | 80 +++++++++++++++++++++++ ompi/runtime/ompi_spc.c | 2 + ompi/runtime/ompi_spc.h | 2 + 12 files changed, 215 insertions(+), 21 deletions(-) create mode 100644 ompi/mpi/c/get_notify.c.in create mode 100644 ompi/mpi/c/put_notify.c.in diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index 43e9006257e..1e5d56d9f91 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -767,6 +767,7 @@ enum { #define MPI_ERR_ERRHANDLER 80 #define MPI_T_ERR_NOT_ACCESSIBLE 81 #define MPI_T_ERR_NOT_SUPPORTED 82 +#define MPI_ERR_NOTIFY_IDX 83 /* Per MPI-3 p349 47, MPI_ERR_LASTCODE must be >= the last predefined MPI_ERR_ code. Set the last code to allow some room for adding @@ -1921,6 +1922,14 @@ OMPI_DECLSPEC int MPI_Get_c(void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Win win); +OMPI_DECLSPEC int MPI_Get_notify(void *origin_addr, int origin_count, + MPI_Datatype origin_datatype, int target_rank, + MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, int notification_idx, MPI_Win win); +OMPI_DECLSPEC int MPI_Get_notify_c(void *origin_addr, MPI_Count origin_count, + MPI_Datatype origin_datatype, int target_rank, + MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, int notification_idx, MPI_Win win); OMPI_DECLSPEC int MPI_Get_accumulate(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, void *result_addr, int result_count, MPI_Datatype result_datatype, int target_rank, MPI_Aint target_disp, int target_count, @@ -2184,6 +2193,12 @@ OMPI_DECLSPEC int MPI_Put(const void *origin_addr, int origin_count, MPI_Dataty OMPI_DECLSPEC int MPI_Put_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Win win); +OMPI_DECLSPEC int MPI_Put_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, int notification_idx, MPI_Win win); +OMPI_DECLSPEC int MPI_Put_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, int notification_idx, MPI_Win win); OMPI_DECLSPEC int MPI_Query_thread(int *provided); OMPI_DECLSPEC int MPI_Raccumulate(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_count, @@ -3095,6 +3110,14 @@ OMPI_DECLSPEC int PMPI_Get_c(void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Win win); +OMPI_DECLSPEC int PMPI_Get_notify(void *origin_addr, int origin_count, + MPI_Datatype origin_datatype, int target_rank, + MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, int notification_idx, MPI_Win win); +OMPI_DECLSPEC int PMPI_Get_notify_c(void *origin_addr, MPI_Count origin_count, + MPI_Datatype origin_datatype, int target_rank, + MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, int notification_idx, MPI_Win win); OMPI_DECLSPEC int PMPI_Get_accumulate(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, void *result_addr, int result_count, MPI_Datatype result_datatype, int target_rank, MPI_Aint target_disp, int target_count, @@ -3358,6 +3381,12 @@ OMPI_DECLSPEC int PMPI_Put(const void *origin_addr, int origin_count, MPI_Datat OMPI_DECLSPEC int PMPI_Put_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Win win); +OMPI_DECLSPEC int PMPI_Put_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, int notification_idx, MPI_Win win); +OMPI_DECLSPEC int PMPI_Put_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, int notification_idx, MPI_Win win); OMPI_DECLSPEC int PMPI_Query_thread(int *provided); OMPI_DECLSPEC int PMPI_Raccumulate(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_count, diff --git a/ompi/include/mpif-values.py b/ompi/include/mpif-values.py index 7cd50d7e9e4..af55b87baee 100755 --- a/ompi/include/mpif-values.py +++ b/ompi/include/mpif-values.py @@ -304,6 +304,7 @@ 'MPI_ERR_ERRHANDLER': 80, 'MPI_T_ERR_NOT_ACCESSIBLE': 81, 'MPI_T_ERR_NOT_SUPPORTED': 82, + 'MPI_ERR_NOTIFY_IDX': 83, 'MPI_ERR_LASTCODE': 92, 'MPI_IDENT': 0, 'MPI_CONGRUENT': 1, diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index bd05a6f11b7..83c7af9305e 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -216,7 +216,7 @@ typedef int (*ompi_osc_base_module_put_fn_t)(const void *origin_addr, struct ompi_datatype_t *target_dt, struct ompi_win_t *win); -typedef int (*ompi_osc_base_module_put_with_notify_fn_t)(const void *origin_addr, +typedef int (*ompi_osc_base_module_put_notify_fn_t)(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, @@ -235,7 +235,7 @@ typedef int (*ompi_osc_base_module_get_fn_t)(void *origin_addr, struct ompi_datatype_t *target_dt, struct ompi_win_t *win); -typedef int (*ompi_osc_base_module_get_with_notify_fn_t)(void *origin_addr, +typedef int (*ompi_osc_base_module_get_notify_fn_t)(void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, @@ -294,7 +294,7 @@ typedef int (*ompi_osc_base_module_rput_fn_t)(const void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); -typedef int (*ompi_osc_base_module_rput_with_notify_fn_t)(const void *origin_addr, +typedef int (*ompi_osc_base_module_rput_notify_fn_t)(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, @@ -315,7 +315,7 @@ typedef int (*ompi_osc_base_module_rget_fn_t)(void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); -typedef int (*ompi_osc_base_module_rget_with_notify_fn_t)(void *origin_addr, +typedef int (*ompi_osc_base_module_rget_notify_fn_t)(void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, @@ -418,18 +418,18 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_free_fn_t osc_free; ompi_osc_base_module_put_fn_t osc_put; - ompi_osc_base_module_put_with_notify_fn_t osc_put_with_notify; + ompi_osc_base_module_put_notify_fn_t osc_put_notify; ompi_osc_base_module_get_fn_t osc_get; - ompi_osc_base_module_get_with_notify_fn_t osc_get_with_notify; + ompi_osc_base_module_get_notify_fn_t osc_get_notify; ompi_osc_base_module_accumulate_fn_t osc_accumulate; ompi_osc_base_module_compare_and_swap_fn_t osc_compare_and_swap; ompi_osc_base_module_fetch_and_op_fn_t osc_fetch_and_op; ompi_osc_base_module_get_accumulate_fn_t osc_get_accumulate; ompi_osc_base_module_rput_fn_t osc_rput; - ompi_osc_base_module_rput_with_notify_fn_t osc_rput_with_notify; + ompi_osc_base_module_rput_notify_fn_t osc_rput_notify; ompi_osc_base_module_rget_fn_t osc_rget; - ompi_osc_base_module_rget_with_notify_fn_t osc_rget_with_notify; + ompi_osc_base_module_rget_notify_fn_t osc_rget_notify; ompi_osc_base_module_raccumulate_fn_t osc_raccumulate; ompi_osc_base_module_rget_accumulate_fn_t osc_rget_accumulate; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index b7d6dadfd49..200ec8b3de8 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -107,7 +107,7 @@ int ompi_osc_sm_detach(struct ompi_win_t *win, const void *base); int ompi_osc_sm_free(struct ompi_win_t *win); -// TODO: add put/get_with_notify prototypes +// TODO: add put/get_notify prototypes int ompi_osc_sm_put(const void *origin_addr, size_t origin_count, @@ -118,7 +118,7 @@ int ompi_osc_sm_put(const void *origin_addr, struct ompi_datatype_t *target_dt, struct ompi_win_t *win); - int ompi_osc_sm_put_with_notify(const void *origin_addr, + int ompi_osc_sm_put_notify(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, @@ -137,7 +137,7 @@ int ompi_osc_sm_get(void *origin_addr, struct ompi_datatype_t *target_dt, struct ompi_win_t *win); -int ompi_osc_sm_get_with_notify(void *origin_addr, +int ompi_osc_sm_get_notify(void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, @@ -196,7 +196,7 @@ int ompi_osc_sm_rput(const void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); -int ompi_osc_sm_rput_with_notify(const void *origin_addr, +int ompi_osc_sm_rput_notify(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, @@ -217,7 +217,7 @@ int ompi_osc_sm_rget(void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); -int ompi_osc_sm_rget_with_notify(void *origin_addr, +int ompi_osc_sm_rget_notify(void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index ba19d8c08cf..4391a375ebc 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -60,7 +60,7 @@ ompi_osc_sm_rput(const void *origin_addr, } int -ompi_osc_sm_rput_with_notify(const void *origin_addr, +ompi_osc_sm_rput_notify(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, @@ -143,7 +143,7 @@ ompi_osc_sm_rget(void *origin_addr, } int -ompi_osc_sm_rget_with_notify(void *origin_addr, +ompi_osc_sm_rget_notify(void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, @@ -323,7 +323,7 @@ ompi_osc_sm_put(const void *origin_addr, int -ompi_osc_sm_put_with_notify(const void *origin_addr, +ompi_osc_sm_put_notify(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, @@ -392,7 +392,7 @@ ompi_osc_sm_get(void *origin_addr, int -ompi_osc_sm_get_with_notify(void *origin_addr, +ompi_osc_sm_get_notify(void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, int target, diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index 11f0ccc2e47..e7613c86f6e 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -79,18 +79,18 @@ ompi_osc_sm_module_t ompi_osc_sm_module_template = { .osc_free = ompi_osc_sm_free, .osc_put = ompi_osc_sm_put, - .osc_put_with_notify = ompi_osc_sm_put_with_notify, + .osc_put_notify = ompi_osc_sm_put_notify, .osc_get = ompi_osc_sm_get, - .osc_get_with_notify = ompi_osc_sm_get_with_notify, + .osc_get_notify = ompi_osc_sm_get_notify, .osc_accumulate = ompi_osc_sm_accumulate, .osc_compare_and_swap = ompi_osc_sm_compare_and_swap, .osc_fetch_and_op = ompi_osc_sm_fetch_and_op, .osc_get_accumulate = ompi_osc_sm_get_accumulate, .osc_rput = ompi_osc_sm_rput, - .osc_rput_with_notify = ompi_osc_sm_rput_with_notify, + .osc_rput_notify = ompi_osc_sm_rput_notify, .osc_rget = ompi_osc_sm_rget, - .osc_rget_with_notify = ompi_osc_sm_rget_with_notify, + .osc_rget_notify = ompi_osc_sm_rget_notify, .osc_raccumulate = ompi_osc_sm_raccumulate, .osc_rget_accumulate = ompi_osc_sm_rget_accumulate, diff --git a/ompi/mpi/bindings/ompi_bindings/consts.py b/ompi/mpi/bindings/ompi_bindings/consts.py index 7a523d7670d..1477956ae83 100644 --- a/ompi/mpi/bindings/ompi_bindings/consts.py +++ b/ompi/mpi/bindings/ompi_bindings/consts.py @@ -23,6 +23,7 @@ 'MPI_SUCCESS', 'MPI_ERR_BUFFER', 'MPI_ERR_COUNT', + 'MPI_ERR_NOTIFY_IDX' 'MPI_ERR_TYPE', 'MPI_ERR_TAG', 'MPI_ERR_COMM', diff --git a/ompi/mpi/c/Makefile.am b/ompi/mpi/c/Makefile.am index f532121bf28..8e4c2bcd388 100644 --- a/ompi/mpi/c/Makefile.am +++ b/ompi/mpi/c/Makefile.am @@ -223,6 +223,7 @@ prototype_sources = \ get_accumulate.c.in \ get_address.c.in \ get.c.in \ + get_notify.c.in \ get_count.c.in \ get_elements.c.in \ get_elements_x.c.in \ @@ -341,6 +342,7 @@ prototype_sources = \ psend_init.c.in \ publish_name.c.in \ put.c.in \ + put_notify.c.in \ query_thread.c.in \ raccumulate.c.in \ recv.c.in \ diff --git a/ompi/mpi/c/get_notify.c.in b/ompi/mpi/c/get_notify.c.in new file mode 100644 index 00000000000..1bad16944ab --- /dev/null +++ b/ompi/mpi/c/get_notify.c.in @@ -0,0 +1,77 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2004-2020 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + * Copyright (c) 2004-2008 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * Copyright (c) 2004-2005 The Regents of the University of California. + * All rights reserved. + * Copyright (c) 2015 Los Alamos National Security, LLC. All rights + * reserved. + * Copyright (c) 2015 Research Organization for Information Science + * and Technology (RIST). All rights reserved. + * Copyright (c) 2024 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" +#include + +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/communicator/communicator.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" +#include "ompi/datatype/ompi_datatype.h" +#include "ompi/runtime/ompi_spc.h" + +PROTOTYPE ERROR_CLASS get_notify(BUFFER_OUT origin_addr, COUNT origin_count, + DATATYPE origin_datatype, INT target_rank, + AINT target_disp, COUNT target_count, + DATATYPE target_datatype, INT notification_idx, WIN win) +{ + int rc; + + SPC_RECORD(OMPI_SPC_GET_NOTIFY, 1); + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (origin_count < 0 || target_count < 0) { + rc = MPI_ERR_COUNT; + } else if (ompi_win_peer_invalid(win, target_rank) && + (MPI_PROC_NULL != target_rank)) { + rc = MPI_ERR_RANK; + } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) { + rc = MPI_ERR_DISP; + } else if (notification_idx < 0) { + rc = MPI_ERR_NOTIFY_IDX; + } else { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count); + if (OMPI_SUCCESS == rc) { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, target_datatype, target_count); + } + } + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + if (MPI_PROC_NULL == target_rank) return MPI_SUCCESS; + + rc = win->w_osc_module->osc_get_notify(origin_addr, origin_count, origin_datatype, + target_rank, target_disp, target_count, + target_datatype, notification_idx, win); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} diff --git a/ompi/mpi/c/put_notify.c.in b/ompi/mpi/c/put_notify.c.in new file mode 100644 index 00000000000..14ee5c7e365 --- /dev/null +++ b/ompi/mpi/c/put_notify.c.in @@ -0,0 +1,80 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2004-2020 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + * Copyright (c) 2004-2008 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * Copyright (c) 2004-2005 The Regents of the University of California. + * All rights reserved. + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2013-2015 Los Alamos National Security, LLC. All rights + * reserved. + * Copyright (c) 2015 Research Organization for Information Science + * and Technology (RIST). All rights reserved. + * Copyright (c) 2024 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" +#include + +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/communicator/communicator.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" +#include "ompi/datatype/ompi_datatype.h" +#include "ompi/runtime/ompi_spc.h" + +PROTOTYPE ERROR_CLASS put_notify(BUFFER origin_addr, COUNT origin_count, DATATYPE origin_datatype, + INT target_rank, AINT target_disp, COUNT target_count, + DATATYPE target_datatype, INT notification_idx, WIN win) +{ + int rc; + + SPC_RECORD(OMPI_SPC_PUT_NOTIFY, 1); + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (origin_count < 0 || target_count < 0) { + rc = MPI_ERR_COUNT; + } else if (ompi_win_peer_invalid(win, target_rank) && + (MPI_PROC_NULL != target_rank)) { + rc = MPI_ERR_RANK; + } else if (NULL == target_datatype || + MPI_DATATYPE_NULL == target_datatype) { + rc = MPI_ERR_TYPE; + } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) { + rc = MPI_ERR_DISP; + } else if (notification_idx < 0) { + rc = MPI_ERR_NOTIFY_IDX; + } else { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count); + if (OMPI_SUCCESS == rc) { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, target_datatype, target_count); + } + } + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + if (MPI_PROC_NULL == target_rank) return MPI_SUCCESS; + + rc = win->w_osc_module->osc_put_notify(origin_addr, origin_count, origin_datatype, + target_rank, target_disp, target_count, + target_datatype, notification_idx, win); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} diff --git a/ompi/runtime/ompi_spc.c b/ompi/runtime/ompi_spc.c index fb097ac6077..45cf81babd0 100644 --- a/ompi/runtime/ompi_spc.c +++ b/ompi/runtime/ompi_spc.c @@ -71,8 +71,10 @@ static const ompi_spc_event_t ompi_spc_events_desc[OMPI_SPC_NUM_COUNTERS] = { SET_COUNTER_ARRAY(OMPI_SPC_SENDRECV, "The number of times MPI_Sendrecv was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_SENDRECV_REPLACE, "The number of times MPI_Sendrecv_replace was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_PUT, "The number of times MPI_Put was called.", false, false), + SET_COUNTER_ARRAY(OMPI_SPC_PUT_NOTIFY, "The number of times MPI_Put_notify was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_RPUT, "The number of times MPI_Rput was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_GET, "The number of times MPI_Get was called.", false, false), + SET_COUNTER_ARRAY(OMPI_SPC_GET_NOTIFY, "The number of times MPI_Get was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_RGET, "The number of times MPI_Rget was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_PROBE, "The number of times MPI_Probe was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_IPROBE, "The number of times MPI_Iprobe was called.", false, false), diff --git a/ompi/runtime/ompi_spc.h b/ompi/runtime/ompi_spc.h index ca61aa8a409..03f58dd2504 100644 --- a/ompi/runtime/ompi_spc.h +++ b/ompi/runtime/ompi_spc.h @@ -58,8 +58,10 @@ typedef enum ompi_spc_counters { OMPI_SPC_SENDRECV, OMPI_SPC_SENDRECV_REPLACE, OMPI_SPC_PUT, + OMPI_SPC_PUT_NOTIFY, OMPI_SPC_RPUT, OMPI_SPC_GET, + OMPI_SPC_GET_NOTIFY, OMPI_SPC_RGET, OMPI_SPC_PROBE, OMPI_SPC_IPROBE, From 90784701cd56ad64f7752d900c90714794837330 Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Mon, 22 Dec 2025 09:46:28 -0500 Subject: [PATCH 05/24] Edits for Public APIs: put_with_notify get_with_notify Signed-off-by: Joseph Antony --- ompi/mca/osc/sm/osc_sm.h | 1 - ompi/runtime/ompi_spc.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index 200ec8b3de8..0aca3b50892 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -107,7 +107,6 @@ int ompi_osc_sm_detach(struct ompi_win_t *win, const void *base); int ompi_osc_sm_free(struct ompi_win_t *win); -// TODO: add put/get_notify prototypes int ompi_osc_sm_put(const void *origin_addr, size_t origin_count, diff --git a/ompi/runtime/ompi_spc.c b/ompi/runtime/ompi_spc.c index 45cf81babd0..e7653e27c39 100644 --- a/ompi/runtime/ompi_spc.c +++ b/ompi/runtime/ompi_spc.c @@ -74,7 +74,7 @@ static const ompi_spc_event_t ompi_spc_events_desc[OMPI_SPC_NUM_COUNTERS] = { SET_COUNTER_ARRAY(OMPI_SPC_PUT_NOTIFY, "The number of times MPI_Put_notify was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_RPUT, "The number of times MPI_Rput was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_GET, "The number of times MPI_Get was called.", false, false), - SET_COUNTER_ARRAY(OMPI_SPC_GET_NOTIFY, "The number of times MPI_Get was called.", false, false), + SET_COUNTER_ARRAY(OMPI_SPC_GET_NOTIFY, "The number of times MPI_Get_notify was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_RGET, "The number of times MPI_Rget was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_PROBE, "The number of times MPI_Probe was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_IPROBE, "The number of times MPI_Iprobe was called.", false, false), From 26f568e4b6a431662d36e6f852b2c39652ad507c Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Tue, 3 Feb 2026 08:29:27 -0500 Subject: [PATCH 06/24] Notified RMA counters memory allocation in the shared memory segment for a single and multi rank window. Signed-off-by: Joseph Antony --- ompi/mca/osc/sm/osc_sm.h | 3 ++- ompi/mca/osc/sm/osc_sm_component.c | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index 0aca3b50892..bf80c082ac8 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -22,6 +22,7 @@ typedef uint64_t osc_sm_post_type_t; typedef opal_atomic_uint64_t osc_sm_post_atomic_type_t; #define OSC_SM_POST_BITS 6 #define OSC_SM_POST_MASK 0x3f +#define OSC_SM_MAX_NOTIFY_COUNTERS 16 /* data shared across all peers */ struct ompi_osc_sm_global_state_t { @@ -79,7 +80,7 @@ struct ompi_osc_sm_module_t { size_t *sizes; void **bases; ptrdiff_t *disp_units; - uint64_t **notify_counters; + uint64_t *notify_counters; ompi_group_t *start_group; diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index e7613c86f6e..5500a2bb412 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -255,12 +255,17 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis module->posts = calloc (1, sizeof(module->posts[0]) + sizeof (module->posts[0][0])); if (NULL == module->posts) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; module->posts[0] = (osc_sm_post_atomic_type_t *) (module->posts + 1); + + /* allocate notify counters for single process case */ + module->notify_counters = calloc(OSC_SM_MAX_NOTIFY_COUNTERS, sizeof(uint64_t)); + if (NULL == module->notify_counters) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; } else { unsigned long total, *rbuf; int i, flag; size_t pagesize; size_t state_size; size_t posts_size, post_size = (comm_size + OSC_SM_POST_MASK) / (OSC_SM_POST_MASK + 1); + size_t notify_counters_size; size_t data_base_size; opal_output_verbose(MCA_BASE_VERBOSE_DEBUG, ompi_osc_base_framework.framework_output, @@ -316,7 +321,9 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis state_size += OPAL_ALIGN_PAD_AMOUNT(state_size, 64); posts_size = comm_size * post_size * sizeof (module->posts[0][0]); posts_size += OPAL_ALIGN_PAD_AMOUNT(posts_size, 64); - data_base_size = state_size + posts_size; + notify_counters_size = OSC_SM_MAX_NOTIFY_COUNTERS * sizeof(uint64_t); + notify_counters_size += OPAL_ALIGN_PAD_AMOUNT(notify_counters_size, 64); + data_base_size = state_size + posts_size + notify_counters_size; data_base_size += OPAL_ALIGN_PAD_AMOUNT(data_base_size, pagesize); if (0 == ompi_comm_rank (module->comm)) { char *data_file; @@ -377,6 +384,12 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis module->global_state = (ompi_osc_sm_global_state_t *) (module->posts[0] + comm_size * post_size); module->node_states = (ompi_osc_sm_node_state_t *) (module->global_state + 1); + /* set up notify counters in shared memory after node_states */ + module->notify_counters = (uint64_t *) ((char *)(module->node_states + comm_size) + + OPAL_ALIGN_PAD_AMOUNT((uintptr_t)(module->node_states + comm_size), 64)); + /* zero out notify counters */ + memset(module->notify_counters, 0, OSC_SM_MAX_NOTIFY_COUNTERS * sizeof(uint64_t)); + for (i = 0, total = data_base_size ; i < comm_size ; ++i) { if (i > 0) { module->posts[i] = module->posts[i - 1] + post_size; @@ -555,6 +568,7 @@ ompi_osc_sm_free(struct ompi_win_t *win) module->comm->c_coll->coll_barrier_module); opal_shmem_segment_detach (&module->seg_ds); + /* notify_counters points into shared memory segment, no separate free needed */ } else { free(module->node_states); free(module->global_state); @@ -562,6 +576,8 @@ ompi_osc_sm_free(struct ompi_win_t *win) mca_mpool_base_default_module->mpool_free(mca_mpool_base_default_module, module->bases[0]); } + /* free notify_counters for single process case */ + free(module->notify_counters); } free(module->disp_units); free(module->outstanding_locks); From 650ff8d80a70c225ac1c84b52b12df895aec7279 Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Wed, 4 Feb 2026 07:47:01 -0500 Subject: [PATCH 07/24] Editing Notified RMA implementation Signed-off-by: Joseph Antony --- ompi/mca/osc/sm/osc_sm_comm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 4391a375ebc..6cc5384d750 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -98,7 +98,7 @@ ompi_osc_sm_rput_notify(const void *origin_addr, *ompi_req = &ompi_request_empty; opal_atomic_wmb(); - opal_atomic_add(&module->notify_counters[target][notify], 1); + opal_atomic_add(&module->notify_counters[notify], 1); return OMPI_SUCCESS; } @@ -181,7 +181,7 @@ ompi_osc_sm_rget_notify(void *origin_addr, *ompi_req = &ompi_request_empty; opal_atomic_rmb(); - opal_atomic_add(&module->notify_counters[target][notify], 1); + opal_atomic_add(&module->notify_counters[notify], 1); return OMPI_SUCCESS; } @@ -355,7 +355,7 @@ ompi_osc_sm_put_notify(const void *origin_addr, } opal_atomic_wmb(); - opal_atomic_add(&module->notify_counters[target][notify], 1); + opal_atomic_add(&module->notify_counters[notify], 1); return ret; } @@ -422,7 +422,7 @@ ompi_osc_sm_get_notify(void *origin_addr, return ret; } opal_atomic_rmb(); - opal_atomic_add(&module->notify_counters[target][notify], 1); + opal_atomic_add(&module->notify_counters[notify], 1); return ret; } From cf07e67f5e40115b5c9efaa0008bfd711afe3537 Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Wed, 18 Feb 2026 22:17:07 -0500 Subject: [PATCH 08/24] Editing Notified RMA implementation with new design Signed-off-by: Joseph Antony --- ompi/mca/osc/sm/osc_sm.h | 3 +++ ompi/mca/osc/sm/osc_sm_comm.c | 35 +++++++++++++++++++++++++---- ompi/mca/osc/sm/osc_sm_component.c | 36 ++++++++++++++++++++---------- 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index bf80c082ac8..cb104e5df15 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -48,6 +48,9 @@ struct ompi_osc_sm_node_state_t { opal_atomic_int32_t complete_count; ompi_osc_sm_lock_t lock; opal_atomic_lock_t accumulate_lock; + uint32_t notify_counter_count; + uint64_t notify_counter_offset; /* offset from segment_base, not raw pointer */ + }; typedef struct ompi_osc_sm_node_state_t ompi_osc_sm_node_state_t; diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 6cc5384d750..359cdf7147f 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -20,6 +20,17 @@ #include "osc_sm.h" +static inline uint64_t *osc_sm_target_notify_base(ompi_osc_sm_module_t *module, int target) +{ + if (NULL == module->segment_base) { + /* single-rank path: notify_counters is a regular local allocation */ + return module->notify_counters; + } + + return (uint64_t *) ((char *) module->segment_base + + module->node_states[target].notify_counter_offset); +} + int ompi_osc_sm_rput(const void *origin_addr, size_t origin_count, @@ -97,8 +108,12 @@ ompi_osc_sm_rput_notify(const void *origin_addr, * complete. */ *ompi_req = &ompi_request_empty; + if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { + return OMPI_ERR_BAD_PARAM; + } + opal_atomic_wmb(); - opal_atomic_add(&module->notify_counters[notify], 1); + opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); return OMPI_SUCCESS; } @@ -180,8 +195,12 @@ ompi_osc_sm_rget_notify(void *origin_addr, * complete. */ *ompi_req = &ompi_request_empty; + if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { + return OMPI_ERR_BAD_PARAM; + } + opal_atomic_rmb(); - opal_atomic_add(&module->notify_counters[notify], 1); + opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); return OMPI_SUCCESS; } @@ -354,8 +373,12 @@ ompi_osc_sm_put_notify(const void *origin_addr, return ret; } + if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { + return OMPI_ERR_BAD_PARAM; + } + opal_atomic_wmb(); - opal_atomic_add(&module->notify_counters[notify], 1); + opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); return ret; } @@ -421,8 +444,12 @@ ompi_osc_sm_get_notify(void *origin_addr, if (OMPI_SUCCESS != ret) { return ret; } + if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { + return OMPI_ERR_BAD_PARAM; + } + opal_atomic_rmb(); - opal_atomic_add(&module->notify_counters[notify], 1); + opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); return ret; } diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index 5500a2bb412..7954ef6963e 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -259,8 +259,10 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis /* allocate notify counters for single process case */ module->notify_counters = calloc(OSC_SM_MAX_NOTIFY_COUNTERS, sizeof(uint64_t)); if (NULL == module->notify_counters) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; + module->node_states[0].notify_counter_count = OSC_SM_MAX_NOTIFY_COUNTERS; + module->node_states[0].notify_counter_offset = 0; } else { - unsigned long total, *rbuf; + unsigned long total, total_counters, gather_values[2], *rbuf; int i, flag; size_t pagesize; size_t state_size; @@ -274,7 +276,7 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis /* get the pagesize */ pagesize = opal_getpagesize(); - rbuf = malloc(sizeof(unsigned long) * comm_size); + rbuf = malloc(sizeof(unsigned long) * comm_size * 2 ); if (NULL == rbuf) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; /* Note that the alloc_shared_noncontig info key only has @@ -298,9 +300,10 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis "allocating window using contiguous strategy"); } - total = size; - ret = module->comm->c_coll->coll_allgather(&total, 1, MPI_UNSIGNED_LONG, - rbuf, 1, MPI_UNSIGNED_LONG, + gather_values[0] = size; + gather_values[1] = OSC_SM_MAX_NOTIFY_COUNTERS; + ret = module->comm->c_coll->coll_allgather(gather_values, 2, MPI_UNSIGNED_LONG, + rbuf, 2, MPI_UNSIGNED_LONG, module->comm, module->comm->c_coll->coll_allgather_module); if (OMPI_SUCCESS != ret) { @@ -309,8 +312,10 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis } total = 0; + total_counters = 0; for (i = 0 ; i < comm_size ; ++i) { - total += rbuf[i]; + total += rbuf[2 * i]; + total_counters += rbuf[2 * i + 1]; if (module->noncontig) { total += OPAL_ALIGN_PAD_AMOUNT(total, pagesize); } @@ -321,7 +326,7 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis state_size += OPAL_ALIGN_PAD_AMOUNT(state_size, 64); posts_size = comm_size * post_size * sizeof (module->posts[0][0]); posts_size += OPAL_ALIGN_PAD_AMOUNT(posts_size, 64); - notify_counters_size = OSC_SM_MAX_NOTIFY_COUNTERS * sizeof(uint64_t); + notify_counters_size = total_counters * sizeof(uint64_t); notify_counters_size += OPAL_ALIGN_PAD_AMOUNT(notify_counters_size, 64); data_base_size = state_size + posts_size + notify_counters_size; data_base_size += OPAL_ALIGN_PAD_AMOUNT(data_base_size, pagesize); @@ -388,17 +393,23 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis module->notify_counters = (uint64_t *) ((char *)(module->node_states + comm_size) + OPAL_ALIGN_PAD_AMOUNT((uintptr_t)(module->node_states + comm_size), 64)); /* zero out notify counters */ - memset(module->notify_counters, 0, OSC_SM_MAX_NOTIFY_COUNTERS * sizeof(uint64_t)); + memset(module->notify_counters, 0, total_counters * sizeof(uint64_t)); - for (i = 0, total = data_base_size ; i < comm_size ; ++i) { + for (i = 0, total = data_base_size, total_counters = 0 ; i < comm_size ; ++i) { if (i > 0) { module->posts[i] = module->posts[i - 1] + post_size; } - module->sizes[i] = rbuf[i]; + module->node_states[i].notify_counter_count = (uint32_t) rbuf[2 * i + 1]; + module->node_states[i].notify_counter_offset = + (uint64_t) ((char *) (module->notify_counters + total_counters) - + (char *) module->segment_base); + total_counters += rbuf[2 * i + 1]; + + module->sizes[i] = rbuf[2 * i]; if (module->sizes[i] || !module->noncontig) { module->bases[i] = ((char *) module->segment_base) + total; - total += rbuf[i]; + total += rbuf[2 * i]; if (module->noncontig) { total += OPAL_ALIGN_PAD_AMOUNT(total, pagesize); } @@ -412,7 +423,8 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis /* initialize my state shared */ module->my_node_state = &module->node_states[ompi_comm_rank(module->comm)]; - memset (module->my_node_state, 0, sizeof(*module->my_node_state)); + module->my_node_state->complete_count = 0; + memset (&module->my_node_state->lock, 0, sizeof(module->my_node_state->lock)); *base = module->bases[ompi_comm_rank(module->comm)]; From cd5f1b9619aa0262670dcbdf43f9d616fac5192f Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Wed, 4 Mar 2026 13:19:28 -0500 Subject: [PATCH 09/24] Implementing Notify Query Signed-off-by: Joseph Antony --- ompi/include/mpi.h.in | 2 ++ ompi/mca/osc/osc.h | 5 ++++ ompi/mca/osc/sm/osc_sm.h | 4 +++ ompi/mca/osc/sm/osc_sm_comm.c | 19 +++++++++++++ ompi/mca/osc/sm/osc_sm_component.c | 1 + ompi/mca/osc/ubcl/osc_ubcl.c | 5 ++++ ompi/mpi/c/Makefile.am | 2 ++ ompi/mpi/c/win_get_notify_value.c.in | 41 ++++++++++++++++++++++++++++ 8 files changed, 79 insertions(+) create mode 100644 ompi/mpi/c/win_get_notify_value.c.in diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index 1e5d56d9f91..79695910bd2 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -2623,6 +2623,7 @@ OMPI_DECLSPEC int MPI_Win_get_errhandler(MPI_Win win, MPI_Errhandler *errhandle OMPI_DECLSPEC int MPI_Win_get_group(MPI_Win win, MPI_Group *group); OMPI_DECLSPEC int MPI_Win_get_info(MPI_Win win, MPI_Info *info_used); OMPI_DECLSPEC int MPI_Win_get_name(MPI_Win win, char *win_name, int *resultlen); +OMPI_DECLSPEC int MPI_Win_get_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); OMPI_DECLSPEC int MPI_Win_lock(int lock_type, int rank, int mpi_assert, MPI_Win win); OMPI_DECLSPEC int MPI_Win_lock_all(int mpi_assert, MPI_Win win); OMPI_DECLSPEC int MPI_Win_post(MPI_Group group, int mpi_assert, MPI_Win win); @@ -3811,6 +3812,7 @@ OMPI_DECLSPEC int PMPI_Win_get_errhandler(MPI_Win win, MPI_Errhandler *errhandl OMPI_DECLSPEC int PMPI_Win_get_group(MPI_Win win, MPI_Group *group); OMPI_DECLSPEC int PMPI_Win_get_info(MPI_Win win, MPI_Info *info_used); OMPI_DECLSPEC int PMPI_Win_get_name(MPI_Win win, char *win_name, int *resultlen); +OMPI_DECLSPEC int PMPI_Win_get_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); OMPI_DECLSPEC int PMPI_Win_lock(int lock_type, int rank, int mpi_assert, MPI_Win win); OMPI_DECLSPEC int PMPI_Win_lock_all(int mpi_assert, MPI_Win win); OMPI_DECLSPEC int PMPI_Win_post(MPI_Group group, int mpi_assert, MPI_Win win); diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index 83c7af9305e..b43757b9b5c 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -245,6 +245,10 @@ typedef int (*ompi_osc_base_module_get_notify_fn_t)(void *origin_addr, int notify, struct ompi_win_t *win); +typedef int (*ompi_osc_base_module_win_get_notify_value_fn_t)(struct ompi_win_t *win, + int notify, + MPI_Count *value); + typedef int (*ompi_osc_base_module_accumulate_fn_t)(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, @@ -421,6 +425,7 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_put_notify_fn_t osc_put_notify; ompi_osc_base_module_get_fn_t osc_get; ompi_osc_base_module_get_notify_fn_t osc_get_notify; + ompi_osc_base_module_win_get_notify_value_fn_t osc_win_get_notify_value; ompi_osc_base_module_accumulate_fn_t osc_accumulate; ompi_osc_base_module_compare_and_swap_fn_t osc_compare_and_swap; ompi_osc_base_module_fetch_and_op_fn_t osc_fetch_and_op; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index cb104e5df15..f80c0116d73 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -149,6 +149,10 @@ int ompi_osc_sm_get_notify(void *origin_addr, struct ompi_datatype_t *target_dt, int notify, struct ompi_win_t *win); + +int ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, + int notify, + MPI_Count *value); int ompi_osc_sm_accumulate(const void *origin_addr, size_t origin_count, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 359cdf7147f..0597ecf3095 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -17,6 +17,7 @@ #include "ompi/mca/osc/osc.h" #include "ompi/mca/osc/base/base.h" #include "ompi/mca/osc/base/osc_base_obj_convert.h" +#include "ompi/communicator/communicator.h" #include "osc_sm.h" @@ -31,6 +32,24 @@ static inline uint64_t *osc_sm_target_notify_base(ompi_osc_sm_module_t *module, module->node_states[target].notify_counter_offset); } +int +ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, + int notify, + MPI_Count *value) +{ + ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; + int rank = ompi_comm_rank(module->comm); + + if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { + return OMPI_ERR_BAD_PARAM; + } + + opal_atomic_rmb(); + *value = (MPI_Count) osc_sm_target_notify_base(module, rank)[notify]; + + return OMPI_SUCCESS; +} + int ompi_osc_sm_rput(const void *origin_addr, size_t origin_count, diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index 7954ef6963e..0a3f7002337 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -82,6 +82,7 @@ ompi_osc_sm_module_t ompi_osc_sm_module_template = { .osc_put_notify = ompi_osc_sm_put_notify, .osc_get = ompi_osc_sm_get, .osc_get_notify = ompi_osc_sm_get_notify, + .osc_win_get_notify_value = ompi_osc_sm_win_get_notify_value, .osc_accumulate = ompi_osc_sm_accumulate, .osc_compare_and_swap = ompi_osc_sm_compare_and_swap, .osc_fetch_and_op = ompi_osc_sm_fetch_and_op, diff --git a/ompi/mca/osc/ubcl/osc_ubcl.c b/ompi/mca/osc/ubcl/osc_ubcl.c index 5a81d0a763d..b55c96298ab 100644 --- a/ompi/mca/osc/ubcl/osc_ubcl.c +++ b/ompi/mca/osc/ubcl/osc_ubcl.c @@ -80,14 +80,19 @@ mca_osc_ubcl_module_t mca_osc_ubcl_module_template = { win_free, ompi_osc_ubcl_put, + NULL, ompi_osc_ubcl_get, + NULL, + NULL, ompi_osc_ubcl_accumulate, ompi_osc_ubcl_compare_and_swap, ompi_osc_ubcl_fetch_and_op, ompi_osc_ubcl_get_accumulate, ompi_osc_ubcl_rput, + NULL, ompi_osc_ubcl_rget, + NULL, ompi_osc_ubcl_raccumulate, ompi_osc_ubcl_rget_accumulate, diff --git a/ompi/mpi/c/Makefile.am b/ompi/mpi/c/Makefile.am index 8e4c2bcd388..ec260ede897 100644 --- a/ompi/mpi/c/Makefile.am +++ b/ompi/mpi/c/Makefile.am @@ -486,6 +486,7 @@ prototype_sources = \ win_get_group.c.in \ win_get_info.c.in \ win_get_name.c.in \ + win_get_notify_value.c.in \ win_lock_all.c.in \ win_lock.c.in \ win_post.c.in \ @@ -956,6 +957,7 @@ interface_profile_sources = \ win_get_group_generated.c \ win_get_info_generated.c \ win_get_name_generated.c \ + win_get_notify_value_generated.c \ win_lock_all_generated.c \ win_lock_generated.c \ win_post_generated.c \ diff --git a/ompi/mpi/c/win_get_notify_value.c.in b/ompi/mpi/c/win_get_notify_value.c.in new file mode 100644 index 00000000000..228999c13ea --- /dev/null +++ b/ompi/mpi/c/win_get_notify_value.c.in @@ -0,0 +1,41 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2026 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" + +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" + +PROTOTYPE ERROR_CLASS win_get_notify_value(WIN win, INT notification_idx, ELEMENT_COUNT value) +{ + int rc; + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (notification_idx < 0) { + rc = MPI_ERR_NOTIFY_IDX; + } else if (NULL == value) { + rc = MPI_ERR_ARG; + } + + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + rc = win->w_osc_module->osc_win_get_notify_value(win, notification_idx, value); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} From 0c661b2466ea57ae3c326a3cbafb9b94a9a42675 Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Wed, 4 Mar 2026 13:39:55 -0500 Subject: [PATCH 10/24] Changes to Notify Query Signed-off-by: Joseph Antony --- ompi/mca/osc/osc.h | 2 +- ompi/mca/osc/sm/osc_sm.h | 2 +- ompi/mca/osc/sm/osc_sm_comm.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index b43757b9b5c..8aebf7446b1 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -247,7 +247,7 @@ typedef int (*ompi_osc_base_module_get_notify_fn_t)(void *origin_addr, typedef int (*ompi_osc_base_module_win_get_notify_value_fn_t)(struct ompi_win_t *win, int notify, - MPI_Count *value); + OMPI_MPI_COUNT_TYPE *value); typedef int (*ompi_osc_base_module_accumulate_fn_t)(const void *origin_addr, size_t origin_count, diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index f80c0116d73..c294cc7d1f6 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -152,7 +152,7 @@ int ompi_osc_sm_get_notify(void *origin_addr, int ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, int notify, - MPI_Count *value); + OMPI_MPI_COUNT_TYPE *value); int ompi_osc_sm_accumulate(const void *origin_addr, size_t origin_count, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 0597ecf3095..b0b3bde37f8 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -35,7 +35,7 @@ static inline uint64_t *osc_sm_target_notify_base(ompi_osc_sm_module_t *module, int ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, int notify, - MPI_Count *value) + OMPI_MPI_COUNT_TYPE *value) { ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; int rank = ompi_comm_rank(module->comm); @@ -45,7 +45,7 @@ ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, } opal_atomic_rmb(); - *value = (MPI_Count) osc_sm_target_notify_base(module, rank)[notify]; + *value = (OMPI_MPI_COUNT_TYPE) osc_sm_target_notify_base(module, rank)[notify]; return OMPI_SUCCESS; } From 45c2eda683cb63f044856e7fa449c3442f8313d5 Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Wed, 4 Mar 2026 18:24:42 -0500 Subject: [PATCH 11/24] Implemented Set Notify Query Signed-off-by: Joseph Antony --- ompi/include/mpi.h.in | 2 ++ ompi/mca/osc/osc.h | 5 ++++ ompi/mca/osc/sm/osc_sm.h | 4 +++ ompi/mca/osc/sm/osc_sm_comm.c | 21 +++++++++++++- ompi/mca/osc/sm/osc_sm_component.c | 1 + ompi/mpi/c/Makefile.am | 2 ++ ompi/mpi/c/win_set_notify_value.c.in | 41 ++++++++++++++++++++++++++++ 7 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 ompi/mpi/c/win_set_notify_value.c.in diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index 79695910bd2..744dcbfe803 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -2624,6 +2624,7 @@ OMPI_DECLSPEC int MPI_Win_get_group(MPI_Win win, MPI_Group *group); OMPI_DECLSPEC int MPI_Win_get_info(MPI_Win win, MPI_Info *info_used); OMPI_DECLSPEC int MPI_Win_get_name(MPI_Win win, char *win_name, int *resultlen); OMPI_DECLSPEC int MPI_Win_get_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); +OMPI_DECLSPEC int MPI_Win_set_notify_value(MPI_Win win, int notification_idx, MPI_Count value); OMPI_DECLSPEC int MPI_Win_lock(int lock_type, int rank, int mpi_assert, MPI_Win win); OMPI_DECLSPEC int MPI_Win_lock_all(int mpi_assert, MPI_Win win); OMPI_DECLSPEC int MPI_Win_post(MPI_Group group, int mpi_assert, MPI_Win win); @@ -3813,6 +3814,7 @@ OMPI_DECLSPEC int PMPI_Win_get_group(MPI_Win win, MPI_Group *group); OMPI_DECLSPEC int PMPI_Win_get_info(MPI_Win win, MPI_Info *info_used); OMPI_DECLSPEC int PMPI_Win_get_name(MPI_Win win, char *win_name, int *resultlen); OMPI_DECLSPEC int PMPI_Win_get_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); +OMPI_DECLSPEC int PMPI_Win_set_notify_value(MPI_Win win, int notification_idx, MPI_Count value); OMPI_DECLSPEC int PMPI_Win_lock(int lock_type, int rank, int mpi_assert, MPI_Win win); OMPI_DECLSPEC int PMPI_Win_lock_all(int mpi_assert, MPI_Win win); OMPI_DECLSPEC int PMPI_Win_post(MPI_Group group, int mpi_assert, MPI_Win win); diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index 8aebf7446b1..ca3b9aac3ef 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -248,6 +248,10 @@ typedef int (*ompi_osc_base_module_get_notify_fn_t)(void *origin_addr, typedef int (*ompi_osc_base_module_win_get_notify_value_fn_t)(struct ompi_win_t *win, int notify, OMPI_MPI_COUNT_TYPE *value); + +typedef int (*ompi_osc_base_module_win_set_notify_value_fn_t)(struct ompi_win_t *win, + int notify, + OMPI_MPI_COUNT_TYPE value); typedef int (*ompi_osc_base_module_accumulate_fn_t)(const void *origin_addr, size_t origin_count, @@ -426,6 +430,7 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_get_fn_t osc_get; ompi_osc_base_module_get_notify_fn_t osc_get_notify; ompi_osc_base_module_win_get_notify_value_fn_t osc_win_get_notify_value; + ompi_osc_base_module_win_set_notify_value_fn_t osc_win_set_notify_value; ompi_osc_base_module_accumulate_fn_t osc_accumulate; ompi_osc_base_module_compare_and_swap_fn_t osc_compare_and_swap; ompi_osc_base_module_fetch_and_op_fn_t osc_fetch_and_op; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index c294cc7d1f6..cec3fa44bb2 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -153,6 +153,10 @@ int ompi_osc_sm_get_notify(void *origin_addr, int ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, int notify, OMPI_MPI_COUNT_TYPE *value); + +int ompi_osc_sm_win_set_notify_value(struct ompi_win_t *win, + int notify, + OMPI_MPI_COUNT_TYPE value); int ompi_osc_sm_accumulate(const void *origin_addr, size_t origin_count, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index b0b3bde37f8..b3879c11949 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -44,8 +44,27 @@ ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, return OMPI_ERR_BAD_PARAM; } - opal_atomic_rmb(); + *value = (OMPI_MPI_COUNT_TYPE) osc_sm_target_notify_base(module, rank)[notify]; + opal_atomic_rmb(); + + return OMPI_SUCCESS; +} + +int +ompi_osc_sm_win_set_notify_value(struct ompi_win_t *win, + int notify, + OMPI_MPI_COUNT_TYPE value) +{ + ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; + int rank = ompi_comm_rank(module->comm); + + if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { + return OMPI_ERR_BAD_PARAM; + } + + opal_atomic_wmb(); + osc_sm_target_notify_base(module, rank)[notify] = (uint64_t) value; return OMPI_SUCCESS; } diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index 0a3f7002337..e64d04d6130 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -83,6 +83,7 @@ ompi_osc_sm_module_t ompi_osc_sm_module_template = { .osc_get = ompi_osc_sm_get, .osc_get_notify = ompi_osc_sm_get_notify, .osc_win_get_notify_value = ompi_osc_sm_win_get_notify_value, + .osc_win_set_notify_value = ompi_osc_sm_win_set_notify_value, .osc_accumulate = ompi_osc_sm_accumulate, .osc_compare_and_swap = ompi_osc_sm_compare_and_swap, .osc_fetch_and_op = ompi_osc_sm_fetch_and_op, diff --git a/ompi/mpi/c/Makefile.am b/ompi/mpi/c/Makefile.am index ec260ede897..e2e32de0175 100644 --- a/ompi/mpi/c/Makefile.am +++ b/ompi/mpi/c/Makefile.am @@ -487,6 +487,7 @@ prototype_sources = \ win_get_info.c.in \ win_get_name.c.in \ win_get_notify_value.c.in \ + win_set_notify_value.c.in \ win_lock_all.c.in \ win_lock.c.in \ win_post.c.in \ @@ -958,6 +959,7 @@ interface_profile_sources = \ win_get_info_generated.c \ win_get_name_generated.c \ win_get_notify_value_generated.c \ + win_set_notify_value_generated.c \ win_lock_all_generated.c \ win_lock_generated.c \ win_post_generated.c \ diff --git a/ompi/mpi/c/win_set_notify_value.c.in b/ompi/mpi/c/win_set_notify_value.c.in new file mode 100644 index 00000000000..8a7d97567db --- /dev/null +++ b/ompi/mpi/c/win_set_notify_value.c.in @@ -0,0 +1,41 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2026 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" + +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" + +PROTOTYPE ERROR_CLASS win_set_notify_value(WIN win, INT notification_idx, PARTITIONED_COUNT value) +{ + int rc; + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (notification_idx < 0) { + rc = MPI_ERR_NOTIFY_IDX; + } else if (value < 0) { + rc = MPI_ERR_ARG; + } + + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + rc = win->w_osc_module->osc_win_set_notify_value(win, notification_idx, value); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} From 193c10baaf62d576f634e9577c43143186810fcc Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Wed, 4 Mar 2026 18:25:43 -0500 Subject: [PATCH 12/24] Changes to Notify Query Signed-off-by: Joseph Antony --- ompi/mca/osc/sm/osc_sm_comm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index b3879c11949..5d9032e19ea 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -44,10 +44,9 @@ ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, return OMPI_ERR_BAD_PARAM; } - - *value = (OMPI_MPI_COUNT_TYPE) osc_sm_target_notify_base(module, rank)[notify]; opal_atomic_rmb(); - + *value = (OMPI_MPI_COUNT_TYPE) osc_sm_target_notify_base(module, rank)[notify]; + return OMPI_SUCCESS; } From e47983f302620d63bccd9288c5413a30adadf88a Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Wed, 11 Mar 2026 18:20:13 -0400 Subject: [PATCH 13/24] Configuring memory barries to propagate the update Signed-off-by: Joseph Antony --- ompi/mca/osc/sm/osc_sm_comm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 5d9032e19ea..6d17d914283 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -44,8 +44,8 @@ ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, return OMPI_ERR_BAD_PARAM; } - opal_atomic_rmb(); *value = (OMPI_MPI_COUNT_TYPE) osc_sm_target_notify_base(module, rank)[notify]; + opal_atomic_rmb(); return OMPI_SUCCESS; } @@ -62,8 +62,8 @@ ompi_osc_sm_win_set_notify_value(struct ompi_win_t *win, return OMPI_ERR_BAD_PARAM; } - opal_atomic_wmb(); osc_sm_target_notify_base(module, rank)[notify] = (uint64_t) value; + opal_atomic_wmb(); return OMPI_SUCCESS; } From 095c99d2b8250f19a9a1bf395bdc69184b0c84cf Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Wed, 11 Mar 2026 19:26:11 -0400 Subject: [PATCH 14/24] Reset notify value Implementation Signed-off-by: Joseph Antony --- ompi/include/mpi.h.in | 2 ++ ompi/mca/osc/osc.h | 5 ++++ ompi/mca/osc/sm/osc_sm.h | 6 +++- ompi/mca/osc/sm/osc_sm_comm.c | 19 ++++++++++++ ompi/mca/osc/sm/osc_sm_component.c | 1 + ompi/mpi/c/Makefile.am | 2 ++ ompi/mpi/c/win_reset_notify_value.c.in | 41 ++++++++++++++++++++++++++ 7 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 ompi/mpi/c/win_reset_notify_value.c.in diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index 744dcbfe803..182ecc807eb 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -2625,6 +2625,7 @@ OMPI_DECLSPEC int MPI_Win_get_info(MPI_Win win, MPI_Info *info_used); OMPI_DECLSPEC int MPI_Win_get_name(MPI_Win win, char *win_name, int *resultlen); OMPI_DECLSPEC int MPI_Win_get_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); OMPI_DECLSPEC int MPI_Win_set_notify_value(MPI_Win win, int notification_idx, MPI_Count value); +OMPI_DECLSPEC int MPI_Win_reset_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); OMPI_DECLSPEC int MPI_Win_lock(int lock_type, int rank, int mpi_assert, MPI_Win win); OMPI_DECLSPEC int MPI_Win_lock_all(int mpi_assert, MPI_Win win); OMPI_DECLSPEC int MPI_Win_post(MPI_Group group, int mpi_assert, MPI_Win win); @@ -3815,6 +3816,7 @@ OMPI_DECLSPEC int PMPI_Win_get_info(MPI_Win win, MPI_Info *info_used); OMPI_DECLSPEC int PMPI_Win_get_name(MPI_Win win, char *win_name, int *resultlen); OMPI_DECLSPEC int PMPI_Win_get_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); OMPI_DECLSPEC int PMPI_Win_set_notify_value(MPI_Win win, int notification_idx, MPI_Count value); +OMPI_DECLSPEC int PMPI_Win_reset_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); OMPI_DECLSPEC int PMPI_Win_lock(int lock_type, int rank, int mpi_assert, MPI_Win win); OMPI_DECLSPEC int PMPI_Win_lock_all(int mpi_assert, MPI_Win win); OMPI_DECLSPEC int PMPI_Win_post(MPI_Group group, int mpi_assert, MPI_Win win); diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index ca3b9aac3ef..6af72390f7f 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -253,6 +253,10 @@ typedef int (*ompi_osc_base_module_win_set_notify_value_fn_t)(struct ompi_win_t int notify, OMPI_MPI_COUNT_TYPE value); +typedef int (*ompi_osc_base_module_win_reset_notify_value_fn_t)(struct ompi_win_t *win, + int notify, + OMPI_MPI_COUNT_TYPE *value); + typedef int (*ompi_osc_base_module_accumulate_fn_t)(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, @@ -431,6 +435,7 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_get_notify_fn_t osc_get_notify; ompi_osc_base_module_win_get_notify_value_fn_t osc_win_get_notify_value; ompi_osc_base_module_win_set_notify_value_fn_t osc_win_set_notify_value; + ompi_osc_base_module_win_reset_notify_value_fn_t osc_win_reset_notify_value; ompi_osc_base_module_accumulate_fn_t osc_accumulate; ompi_osc_base_module_compare_and_swap_fn_t osc_compare_and_swap; ompi_osc_base_module_fetch_and_op_fn_t osc_fetch_and_op; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index cec3fa44bb2..ca776bd59a0 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -157,7 +157,11 @@ int ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, int ompi_osc_sm_win_set_notify_value(struct ompi_win_t *win, int notify, OMPI_MPI_COUNT_TYPE value); - + +int ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, + int notify, + OMPI_MPI_COUNT_TYPE *value); + int ompi_osc_sm_accumulate(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 6d17d914283..40cbc9d2813 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -68,6 +68,25 @@ ompi_osc_sm_win_set_notify_value(struct ompi_win_t *win, return OMPI_SUCCESS; } +int +ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, + int notify, + OMPI_MPI_COUNT_TYPE *value) +{ + ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; + int rank = ompi_comm_rank(module->comm); + + if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { + return OMPI_ERR_BAD_PARAM; + } + + /* Atomically swap the counter to 0 and return the previous value */ + *value = (OMPI_MPI_COUNT_TYPE) opal_atomic_swap_64( + &osc_sm_target_notify_base(module, rank)[notify], 0); + + return OMPI_SUCCESS; +} + int ompi_osc_sm_rput(const void *origin_addr, size_t origin_count, diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index e64d04d6130..3ba892e0885 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -84,6 +84,7 @@ ompi_osc_sm_module_t ompi_osc_sm_module_template = { .osc_get_notify = ompi_osc_sm_get_notify, .osc_win_get_notify_value = ompi_osc_sm_win_get_notify_value, .osc_win_set_notify_value = ompi_osc_sm_win_set_notify_value, + .osc_win_reset_notify_value = ompi_osc_sm_win_reset_notify_value, .osc_accumulate = ompi_osc_sm_accumulate, .osc_compare_and_swap = ompi_osc_sm_compare_and_swap, .osc_fetch_and_op = ompi_osc_sm_fetch_and_op, diff --git a/ompi/mpi/c/Makefile.am b/ompi/mpi/c/Makefile.am index e2e32de0175..2d9c5c852ce 100644 --- a/ompi/mpi/c/Makefile.am +++ b/ompi/mpi/c/Makefile.am @@ -488,6 +488,7 @@ prototype_sources = \ win_get_name.c.in \ win_get_notify_value.c.in \ win_set_notify_value.c.in \ + win_reset_notify_value.c.in \ win_lock_all.c.in \ win_lock.c.in \ win_post.c.in \ @@ -960,6 +961,7 @@ interface_profile_sources = \ win_get_name_generated.c \ win_get_notify_value_generated.c \ win_set_notify_value_generated.c \ + win_reset_notify_value_generated.c \ win_lock_all_generated.c \ win_lock_generated.c \ win_post_generated.c \ diff --git a/ompi/mpi/c/win_reset_notify_value.c.in b/ompi/mpi/c/win_reset_notify_value.c.in new file mode 100644 index 00000000000..99aa1755a76 --- /dev/null +++ b/ompi/mpi/c/win_reset_notify_value.c.in @@ -0,0 +1,41 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2026 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" + +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" + +PROTOTYPE ERROR_CLASS win_reset_notify_value(WIN win, INT notification_idx, ELEMENT_COUNT value) +{ + int rc; + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (notification_idx < 0) { + rc = MPI_ERR_NOTIFY_IDX; + } else if (NULL == value) { + rc = MPI_ERR_ARG; + } + + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + rc = win->w_osc_module->osc_win_reset_notify_value(win, notification_idx, value); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} From 9d4d06ca7fe3f656348c184ac832ecaa403ca6a8 Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Fri, 13 Mar 2026 11:43:20 -0400 Subject: [PATCH 15/24] Addressing review comments and bug fixes Signed-off-by: Joseph Antony --- ompi/mca/osc/osc.h | 14 +++++++------- ompi/mca/osc/sm/osc_sm_comm.c | 12 ++++++------ ompi/mca/osc/ubcl/osc_ubcl.c | 5 ----- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index 6af72390f7f..002866a69da 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -430,21 +430,14 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_free_fn_t osc_free; ompi_osc_base_module_put_fn_t osc_put; - ompi_osc_base_module_put_notify_fn_t osc_put_notify; ompi_osc_base_module_get_fn_t osc_get; - ompi_osc_base_module_get_notify_fn_t osc_get_notify; - ompi_osc_base_module_win_get_notify_value_fn_t osc_win_get_notify_value; - ompi_osc_base_module_win_set_notify_value_fn_t osc_win_set_notify_value; - ompi_osc_base_module_win_reset_notify_value_fn_t osc_win_reset_notify_value; ompi_osc_base_module_accumulate_fn_t osc_accumulate; ompi_osc_base_module_compare_and_swap_fn_t osc_compare_and_swap; ompi_osc_base_module_fetch_and_op_fn_t osc_fetch_and_op; ompi_osc_base_module_get_accumulate_fn_t osc_get_accumulate; ompi_osc_base_module_rput_fn_t osc_rput; - ompi_osc_base_module_rput_notify_fn_t osc_rput_notify; ompi_osc_base_module_rget_fn_t osc_rget; - ompi_osc_base_module_rget_notify_fn_t osc_rget_notify; ompi_osc_base_module_raccumulate_fn_t osc_raccumulate; ompi_osc_base_module_rget_accumulate_fn_t osc_rget_accumulate; @@ -466,6 +459,13 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_flush_all_fn_t osc_flush_all; ompi_osc_base_module_flush_local_fn_t osc_flush_local; ompi_osc_base_module_flush_local_all_fn_t osc_flush_local_all; + ompi_osc_base_module_put_notify_fn_t osc_put_notify; + ompi_osc_base_module_get_notify_fn_t osc_get_notify; + ompi_osc_base_module_win_get_notify_value_fn_t osc_win_get_notify_value; + ompi_osc_base_module_win_set_notify_value_fn_t osc_win_set_notify_value; + ompi_osc_base_module_win_reset_notify_value_fn_t osc_win_reset_notify_value; + ompi_osc_base_module_rput_notify_fn_t osc_rput_notify; + ompi_osc_base_module_rget_notify_fn_t osc_rget_notify; }; typedef struct ompi_osc_base_module_4_0_0_t ompi_osc_base_module_4_0_0_t; typedef ompi_osc_base_module_4_0_0_t ompi_osc_base_module_t; diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 40cbc9d2813..7d7501dcabf 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -41,7 +41,7 @@ ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, int rank = ompi_comm_rank(module->comm); if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { - return OMPI_ERR_BAD_PARAM; + return MPI_ERR_NOTIFY_IDX; } *value = (OMPI_MPI_COUNT_TYPE) osc_sm_target_notify_base(module, rank)[notify]; @@ -59,7 +59,7 @@ ompi_osc_sm_win_set_notify_value(struct ompi_win_t *win, int rank = ompi_comm_rank(module->comm); if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { - return OMPI_ERR_BAD_PARAM; + return MPI_ERR_NOTIFY_IDX; } osc_sm_target_notify_base(module, rank)[notify] = (uint64_t) value; @@ -77,7 +77,7 @@ ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, int rank = ompi_comm_rank(module->comm); if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { - return OMPI_ERR_BAD_PARAM; + return MPI_ERR_NOTIFY_IDX; } /* Atomically swap the counter to 0 and return the previous value */ @@ -165,7 +165,7 @@ ompi_osc_sm_rput_notify(const void *origin_addr, *ompi_req = &ompi_request_empty; if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { - return OMPI_ERR_BAD_PARAM; + return MPI_ERR_NOTIFY_IDX; } opal_atomic_wmb(); @@ -252,7 +252,7 @@ ompi_osc_sm_rget_notify(void *origin_addr, *ompi_req = &ompi_request_empty; if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { - return OMPI_ERR_BAD_PARAM; + return MPI_ERR_NOTIFY_IDX; } opal_atomic_rmb(); @@ -430,7 +430,7 @@ ompi_osc_sm_put_notify(const void *origin_addr, } if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { - return OMPI_ERR_BAD_PARAM; + return MPI_ERR_NOTIFY_IDX; } opal_atomic_wmb(); diff --git a/ompi/mca/osc/ubcl/osc_ubcl.c b/ompi/mca/osc/ubcl/osc_ubcl.c index b55c96298ab..5a81d0a763d 100644 --- a/ompi/mca/osc/ubcl/osc_ubcl.c +++ b/ompi/mca/osc/ubcl/osc_ubcl.c @@ -80,19 +80,14 @@ mca_osc_ubcl_module_t mca_osc_ubcl_module_template = { win_free, ompi_osc_ubcl_put, - NULL, ompi_osc_ubcl_get, - NULL, - NULL, ompi_osc_ubcl_accumulate, ompi_osc_ubcl_compare_and_swap, ompi_osc_ubcl_fetch_and_op, ompi_osc_ubcl_get_accumulate, ompi_osc_ubcl_rput, - NULL, ompi_osc_ubcl_rget, - NULL, ompi_osc_ubcl_raccumulate, ompi_osc_ubcl_rget_accumulate, From 6719fbda67e6c64e0f2a38fc94d0590317445446 Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Fri, 13 Mar 2026 17:23:08 -0400 Subject: [PATCH 16/24] Removing Duplicate changes Signed-off-by: Joseph Antony --- ompi/include/mpi.h.in | 2 -- ompi/mca/osc/osc.h | 5 ---- ompi/mca/osc/sm/osc_sm.h | 4 --- ompi/mca/osc/sm/osc_sm_comm.c | 18 ------------ ompi/mca/osc/sm/osc_sm_component.c | 1 - ompi/mpi/c/Makefile.am | 2 -- ompi/mpi/c/win_set_notify_value.c.in | 41 ---------------------------- 7 files changed, 73 deletions(-) delete mode 100644 ompi/mpi/c/win_set_notify_value.c.in diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index 182ecc807eb..f600c66733b 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -2624,7 +2624,6 @@ OMPI_DECLSPEC int MPI_Win_get_group(MPI_Win win, MPI_Group *group); OMPI_DECLSPEC int MPI_Win_get_info(MPI_Win win, MPI_Info *info_used); OMPI_DECLSPEC int MPI_Win_get_name(MPI_Win win, char *win_name, int *resultlen); OMPI_DECLSPEC int MPI_Win_get_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); -OMPI_DECLSPEC int MPI_Win_set_notify_value(MPI_Win win, int notification_idx, MPI_Count value); OMPI_DECLSPEC int MPI_Win_reset_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); OMPI_DECLSPEC int MPI_Win_lock(int lock_type, int rank, int mpi_assert, MPI_Win win); OMPI_DECLSPEC int MPI_Win_lock_all(int mpi_assert, MPI_Win win); @@ -3815,7 +3814,6 @@ OMPI_DECLSPEC int PMPI_Win_get_group(MPI_Win win, MPI_Group *group); OMPI_DECLSPEC int PMPI_Win_get_info(MPI_Win win, MPI_Info *info_used); OMPI_DECLSPEC int PMPI_Win_get_name(MPI_Win win, char *win_name, int *resultlen); OMPI_DECLSPEC int PMPI_Win_get_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); -OMPI_DECLSPEC int PMPI_Win_set_notify_value(MPI_Win win, int notification_idx, MPI_Count value); OMPI_DECLSPEC int PMPI_Win_reset_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); OMPI_DECLSPEC int PMPI_Win_lock(int lock_type, int rank, int mpi_assert, MPI_Win win); OMPI_DECLSPEC int PMPI_Win_lock_all(int mpi_assert, MPI_Win win); diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index 002866a69da..b43f34ac3c5 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -249,10 +249,6 @@ typedef int (*ompi_osc_base_module_win_get_notify_value_fn_t)(struct ompi_win_t int notify, OMPI_MPI_COUNT_TYPE *value); -typedef int (*ompi_osc_base_module_win_set_notify_value_fn_t)(struct ompi_win_t *win, - int notify, - OMPI_MPI_COUNT_TYPE value); - typedef int (*ompi_osc_base_module_win_reset_notify_value_fn_t)(struct ompi_win_t *win, int notify, OMPI_MPI_COUNT_TYPE *value); @@ -462,7 +458,6 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_put_notify_fn_t osc_put_notify; ompi_osc_base_module_get_notify_fn_t osc_get_notify; ompi_osc_base_module_win_get_notify_value_fn_t osc_win_get_notify_value; - ompi_osc_base_module_win_set_notify_value_fn_t osc_win_set_notify_value; ompi_osc_base_module_win_reset_notify_value_fn_t osc_win_reset_notify_value; ompi_osc_base_module_rput_notify_fn_t osc_rput_notify; ompi_osc_base_module_rget_notify_fn_t osc_rget_notify; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index ca776bd59a0..85d250bfa18 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -154,10 +154,6 @@ int ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, int notify, OMPI_MPI_COUNT_TYPE *value); -int ompi_osc_sm_win_set_notify_value(struct ompi_win_t *win, - int notify, - OMPI_MPI_COUNT_TYPE value); - int ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, int notify, OMPI_MPI_COUNT_TYPE *value); diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 7d7501dcabf..fbd4f17856c 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -50,24 +50,6 @@ ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, return OMPI_SUCCESS; } -int -ompi_osc_sm_win_set_notify_value(struct ompi_win_t *win, - int notify, - OMPI_MPI_COUNT_TYPE value) -{ - ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; - int rank = ompi_comm_rank(module->comm); - - if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { - return MPI_ERR_NOTIFY_IDX; - } - - osc_sm_target_notify_base(module, rank)[notify] = (uint64_t) value; - opal_atomic_wmb(); - - return OMPI_SUCCESS; -} - int ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, int notify, diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index 3ba892e0885..259c0826017 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -83,7 +83,6 @@ ompi_osc_sm_module_t ompi_osc_sm_module_template = { .osc_get = ompi_osc_sm_get, .osc_get_notify = ompi_osc_sm_get_notify, .osc_win_get_notify_value = ompi_osc_sm_win_get_notify_value, - .osc_win_set_notify_value = ompi_osc_sm_win_set_notify_value, .osc_win_reset_notify_value = ompi_osc_sm_win_reset_notify_value, .osc_accumulate = ompi_osc_sm_accumulate, .osc_compare_and_swap = ompi_osc_sm_compare_and_swap, diff --git a/ompi/mpi/c/Makefile.am b/ompi/mpi/c/Makefile.am index 2d9c5c852ce..7aecd5a3411 100644 --- a/ompi/mpi/c/Makefile.am +++ b/ompi/mpi/c/Makefile.am @@ -487,7 +487,6 @@ prototype_sources = \ win_get_info.c.in \ win_get_name.c.in \ win_get_notify_value.c.in \ - win_set_notify_value.c.in \ win_reset_notify_value.c.in \ win_lock_all.c.in \ win_lock.c.in \ @@ -960,7 +959,6 @@ interface_profile_sources = \ win_get_info_generated.c \ win_get_name_generated.c \ win_get_notify_value_generated.c \ - win_set_notify_value_generated.c \ win_reset_notify_value_generated.c \ win_lock_all_generated.c \ win_lock_generated.c \ diff --git a/ompi/mpi/c/win_set_notify_value.c.in b/ompi/mpi/c/win_set_notify_value.c.in deleted file mode 100644 index 8a7d97567db..00000000000 --- a/ompi/mpi/c/win_set_notify_value.c.in +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ -/* - * Copyright (c) 2026 Triad National Security, LLC. All rights - * reserved. - * $COPYRIGHT$ - * - * Additional copyrights may follow - * - * $HEADER$ - */ -#include "ompi_config.h" - -#include "ompi/mpi/c/bindings.h" -#include "ompi/runtime/params.h" -#include "ompi/errhandler/errhandler.h" -#include "ompi/win/win.h" -#include "ompi/mca/osc/osc.h" - -PROTOTYPE ERROR_CLASS win_set_notify_value(WIN win, INT notification_idx, PARTITIONED_COUNT value) -{ - int rc; - - if (MPI_PARAM_CHECK) { - rc = OMPI_SUCCESS; - - OMPI_ERR_INIT_FINALIZE(FUNC_NAME); - - if (ompi_win_invalid(win)) { - return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); - } else if (notification_idx < 0) { - rc = MPI_ERR_NOTIFY_IDX; - } else if (value < 0) { - rc = MPI_ERR_ARG; - } - - OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); - } - - rc = win->w_osc_module->osc_win_set_notify_value(win, notification_idx, value); - OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); -} From 1ff322d87ea1dde3643c78faec0158844d81fe23 Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Sun, 2 Aug 2026 00:01:50 -0400 Subject: [PATCH 17/24] ompi: rename MPI_ERR_NOTIFY_IDX to MPI_ERR_RMA_NOTIFICATION MPI-5.1 names the error class for an invalid notification index MPI_ERR_RMA_NOTIFICATION. Rename the placeholder used by the notified RMA work to match the standard. The class was never registered with the error code subsystem, so MPI_Error_string() and MPI_Error_class() did not know about it; add the missing CONSTRUCT_ERRCODE()/OBJ_DESTRUCT() pair in errcode.c. Also fix the binding generator's ERROR_CLASSES list, where the entry was inserted without a trailing comma and so was silently concatenated with the following 'MPI_ERR_TYPE' element rather than added as a class of its own. Signed-off-by: Joseph Antony --- ompi/errhandler/errcode.c | 3 +++ ompi/include/mpi.h.in | 2 +- ompi/include/mpif-values.py | 2 +- ompi/mca/osc/sm/osc_sm_comm.c | 10 +++++----- ompi/mpi/bindings/ompi_bindings/consts.py | 2 +- ompi/mpi/c/get_notify.c.in | 2 +- ompi/mpi/c/put_notify.c.in | 2 +- ompi/mpi/c/win_get_notify_value.c.in | 2 +- ompi/mpi/c/win_reset_notify_value.c.in | 2 +- 9 files changed, 15 insertions(+), 12 deletions(-) diff --git a/ompi/errhandler/errcode.c b/ompi/errhandler/errcode.c index 631f1483b12..d04b6f9069c 100644 --- a/ompi/errhandler/errcode.c +++ b/ompi/errhandler/errcode.c @@ -131,6 +131,7 @@ static ompi_mpi_errcode_t ompi_err_value_too_large; static ompi_mpi_errcode_t ompi_err_errhandler; static ompi_mpi_errcode_t ompi_t_err_not_accessible; static ompi_mpi_errcode_t ompi_t_err_not_supported; +static ompi_mpi_errcode_t ompi_err_rma_notification; static void ompi_mpi_errcode_construct(ompi_mpi_errcode_t* errcode); static void ompi_mpi_errcode_destruct(ompi_mpi_errcode_t* errcode); @@ -252,6 +253,7 @@ int ompi_mpi_errcode_init (void) CONSTRUCT_ERRCODE( ompi_err_errhandler, MPI_ERR_ERRHANDLER, "MPI_ERR_ERRHANDLER: Invalid error handler handle" ); CONSTRUCT_ERRCODE( ompi_t_err_not_accessible, MPI_T_ERR_NOT_ACCESSIBLE, "MPI_T_ERR_NOT_ACCESSIBLE: Requested functionality is not accessible" ); CONSTRUCT_ERRCODE( ompi_t_err_not_supported, MPI_T_ERR_NOT_SUPPORTED, "MPI_T_ERR_NOT_SUPPORTED: Requested functionality not supported" ); + CONSTRUCT_ERRCODE( ompi_err_rma_notification, MPI_ERR_RMA_NOTIFICATION, "MPI_ERR_RMA_NOTIFICATION: Invalid notification index passed to MPI call" ); /* Per MPI-3 p353:27-32, MPI_LASTUSEDCODE must be >= MPI_ERR_LASTCODE. So just start it as == MPI_ERR_LASTCODE. */ @@ -373,6 +375,7 @@ int ompi_mpi_errcode_finalize (void) OBJ_DESTRUCT(&ompi_err_errhandler); OBJ_DESTRUCT(&ompi_t_err_not_accessible); OBJ_DESTRUCT(&ompi_t_err_not_supported); + OBJ_DESTRUCT(&ompi_err_rma_notification); OBJ_DESTRUCT(&ompi_mpi_errcodes); ompi_mpi_errcode_lastpredefined = 0; opal_mutex_unlock(&errcode_lock); diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index f600c66733b..8d393da453b 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -767,7 +767,7 @@ enum { #define MPI_ERR_ERRHANDLER 80 #define MPI_T_ERR_NOT_ACCESSIBLE 81 #define MPI_T_ERR_NOT_SUPPORTED 82 -#define MPI_ERR_NOTIFY_IDX 83 +#define MPI_ERR_RMA_NOTIFICATION 83 /* Per MPI-3 p349 47, MPI_ERR_LASTCODE must be >= the last predefined MPI_ERR_ code. Set the last code to allow some room for adding diff --git a/ompi/include/mpif-values.py b/ompi/include/mpif-values.py index af55b87baee..62cd9c4e421 100755 --- a/ompi/include/mpif-values.py +++ b/ompi/include/mpif-values.py @@ -304,7 +304,7 @@ 'MPI_ERR_ERRHANDLER': 80, 'MPI_T_ERR_NOT_ACCESSIBLE': 81, 'MPI_T_ERR_NOT_SUPPORTED': 82, - 'MPI_ERR_NOTIFY_IDX': 83, + 'MPI_ERR_RMA_NOTIFICATION': 83, 'MPI_ERR_LASTCODE': 92, 'MPI_IDENT': 0, 'MPI_CONGRUENT': 1, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index fbd4f17856c..78966b4d809 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -41,7 +41,7 @@ ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, int rank = ompi_comm_rank(module->comm); if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { - return MPI_ERR_NOTIFY_IDX; + return MPI_ERR_RMA_NOTIFICATION; } *value = (OMPI_MPI_COUNT_TYPE) osc_sm_target_notify_base(module, rank)[notify]; @@ -59,7 +59,7 @@ ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, int rank = ompi_comm_rank(module->comm); if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { - return MPI_ERR_NOTIFY_IDX; + return MPI_ERR_RMA_NOTIFICATION; } /* Atomically swap the counter to 0 and return the previous value */ @@ -147,7 +147,7 @@ ompi_osc_sm_rput_notify(const void *origin_addr, *ompi_req = &ompi_request_empty; if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { - return MPI_ERR_NOTIFY_IDX; + return MPI_ERR_RMA_NOTIFICATION; } opal_atomic_wmb(); @@ -234,7 +234,7 @@ ompi_osc_sm_rget_notify(void *origin_addr, *ompi_req = &ompi_request_empty; if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { - return MPI_ERR_NOTIFY_IDX; + return MPI_ERR_RMA_NOTIFICATION; } opal_atomic_rmb(); @@ -412,7 +412,7 @@ ompi_osc_sm_put_notify(const void *origin_addr, } if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { - return MPI_ERR_NOTIFY_IDX; + return MPI_ERR_RMA_NOTIFICATION; } opal_atomic_wmb(); diff --git a/ompi/mpi/bindings/ompi_bindings/consts.py b/ompi/mpi/bindings/ompi_bindings/consts.py index 1477956ae83..4a249629079 100644 --- a/ompi/mpi/bindings/ompi_bindings/consts.py +++ b/ompi/mpi/bindings/ompi_bindings/consts.py @@ -23,7 +23,6 @@ 'MPI_SUCCESS', 'MPI_ERR_BUFFER', 'MPI_ERR_COUNT', - 'MPI_ERR_NOTIFY_IDX' 'MPI_ERR_TYPE', 'MPI_ERR_TAG', 'MPI_ERR_COMM', @@ -101,6 +100,7 @@ 'MPI_T_ERR_PVAR_NO_ATOMIC', 'MPI_T_ERR_NOT_ACCESSIBLE', 'MPI_T_ERR_NOT_SUPPORTED', + 'MPI_ERR_RMA_NOTIFICATION', 'MPI_ERR_LASTCODE', ] diff --git a/ompi/mpi/c/get_notify.c.in b/ompi/mpi/c/get_notify.c.in index 1bad16944ab..d9b8f5b68ef 100644 --- a/ompi/mpi/c/get_notify.c.in +++ b/ompi/mpi/c/get_notify.c.in @@ -58,7 +58,7 @@ PROTOTYPE ERROR_CLASS get_notify(BUFFER_OUT origin_addr, COUNT origin_count, } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) { rc = MPI_ERR_DISP; } else if (notification_idx < 0) { - rc = MPI_ERR_NOTIFY_IDX; + rc = MPI_ERR_RMA_NOTIFICATION; } else { OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count); if (OMPI_SUCCESS == rc) { diff --git a/ompi/mpi/c/put_notify.c.in b/ompi/mpi/c/put_notify.c.in index 14ee5c7e365..f278e16cb16 100644 --- a/ompi/mpi/c/put_notify.c.in +++ b/ompi/mpi/c/put_notify.c.in @@ -61,7 +61,7 @@ PROTOTYPE ERROR_CLASS put_notify(BUFFER origin_addr, COUNT origin_count, DATATYP } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) { rc = MPI_ERR_DISP; } else if (notification_idx < 0) { - rc = MPI_ERR_NOTIFY_IDX; + rc = MPI_ERR_RMA_NOTIFICATION; } else { OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count); if (OMPI_SUCCESS == rc) { diff --git a/ompi/mpi/c/win_get_notify_value.c.in b/ompi/mpi/c/win_get_notify_value.c.in index 228999c13ea..27df94e1e82 100644 --- a/ompi/mpi/c/win_get_notify_value.c.in +++ b/ompi/mpi/c/win_get_notify_value.c.in @@ -28,7 +28,7 @@ PROTOTYPE ERROR_CLASS win_get_notify_value(WIN win, INT notification_idx, ELEMEN if (ompi_win_invalid(win)) { return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); } else if (notification_idx < 0) { - rc = MPI_ERR_NOTIFY_IDX; + rc = MPI_ERR_RMA_NOTIFICATION; } else if (NULL == value) { rc = MPI_ERR_ARG; } diff --git a/ompi/mpi/c/win_reset_notify_value.c.in b/ompi/mpi/c/win_reset_notify_value.c.in index 99aa1755a76..68b462a510e 100644 --- a/ompi/mpi/c/win_reset_notify_value.c.in +++ b/ompi/mpi/c/win_reset_notify_value.c.in @@ -28,7 +28,7 @@ PROTOTYPE ERROR_CLASS win_reset_notify_value(WIN win, INT notification_idx, ELEM if (ompi_win_invalid(win)) { return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); } else if (notification_idx < 0) { - rc = MPI_ERR_NOTIFY_IDX; + rc = MPI_ERR_RMA_NOTIFICATION; } else if (NULL == value) { rc = MPI_ERR_ARG; } From d909605a01e76645e526a023427f06807dfd488b Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Sun, 2 Aug 2026 00:03:29 -0400 Subject: [PATCH 18/24] osc: add MPI_WIN_SET_NUM_NOTIFY and MPI_WIN_GET_NUM_NOTIFY Add the two remaining notification-management procedures from MPI-5.1 section 12.6.1: MPI_WIN_SET_NUM_NOTIFY is a blocking, synchronizing collective that sets the number of notification counters attached at the calling MPI process to exactly num_notifications and resets all of them to zero. MPI_WIN_GET_NUM_NOTIFY is local and returns the number of counters attached at target_rank. Both are wired through the osc framework as new module entry points, so components that do not implement them return MPI_ERR_UNSUPPORTED_OPERATION rather than crashing. The osc/sm implementation carves a fixed per-rank counter region out of the shared segment at window creation, which is therefore the effective MPI_WIN_NOTIFICATION_NUM_UB; a request beyond that capacity is rejected with MPI_ERR_ARG. Each rank publishes its own attached count into the shared segment, so the collective needs only a barrier -- no counts have to be exchanged -- and MPI_WIN_GET_NUM_NOTIFY is a plain shared-memory read. Also add the missing put_notify/get_notify entries to interface_profile_sources, which were omitted when those two procedures were introduced. Signed-off-by: Joseph Antony --- ompi/include/mpi.h.in | 4 ++ ompi/mca/osc/osc.h | 15 ++++++ ompi/mca/osc/sm/osc_sm.h | 8 ++++ ompi/mca/osc/sm/osc_sm_comm.c | 77 ++++++++++++++++++++++++++++++ ompi/mca/osc/sm/osc_sm_component.c | 2 + ompi/mpi/c/Makefile.am | 6 +++ ompi/mpi/c/win_get_num_notify.c.in | 43 +++++++++++++++++ ompi/mpi/c/win_set_num_notify.c.in | 48 +++++++++++++++++++ 8 files changed, 203 insertions(+) create mode 100644 ompi/mpi/c/win_get_num_notify.c.in create mode 100644 ompi/mpi/c/win_set_num_notify.c.in diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index 8d393da453b..71afc4cefbc 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -2625,6 +2625,8 @@ OMPI_DECLSPEC int MPI_Win_get_info(MPI_Win win, MPI_Info *info_used); OMPI_DECLSPEC int MPI_Win_get_name(MPI_Win win, char *win_name, int *resultlen); OMPI_DECLSPEC int MPI_Win_get_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); OMPI_DECLSPEC int MPI_Win_reset_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); +OMPI_DECLSPEC int MPI_Win_get_num_notify(MPI_Win win, int target_rank, int *num_notifications); +OMPI_DECLSPEC int MPI_Win_set_num_notify(MPI_Win win, MPI_Info info, int num_notifications); OMPI_DECLSPEC int MPI_Win_lock(int lock_type, int rank, int mpi_assert, MPI_Win win); OMPI_DECLSPEC int MPI_Win_lock_all(int mpi_assert, MPI_Win win); OMPI_DECLSPEC int MPI_Win_post(MPI_Group group, int mpi_assert, MPI_Win win); @@ -3815,6 +3817,8 @@ OMPI_DECLSPEC int PMPI_Win_get_info(MPI_Win win, MPI_Info *info_used); OMPI_DECLSPEC int PMPI_Win_get_name(MPI_Win win, char *win_name, int *resultlen); OMPI_DECLSPEC int PMPI_Win_get_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); OMPI_DECLSPEC int PMPI_Win_reset_notify_value(MPI_Win win, int notification_idx, MPI_Count *value); +OMPI_DECLSPEC int PMPI_Win_get_num_notify(MPI_Win win, int target_rank, int *num_notifications); +OMPI_DECLSPEC int PMPI_Win_set_num_notify(MPI_Win win, MPI_Info info, int num_notifications); OMPI_DECLSPEC int PMPI_Win_lock(int lock_type, int rank, int mpi_assert, MPI_Win win); OMPI_DECLSPEC int PMPI_Win_lock_all(int mpi_assert, MPI_Win win); OMPI_DECLSPEC int PMPI_Win_post(MPI_Group group, int mpi_assert, MPI_Win win); diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index b43f34ac3c5..2f66c2ac107 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -253,6 +253,19 @@ typedef int (*ompi_osc_base_module_win_reset_notify_value_fn_t)(struct ompi_win_ int notify, OMPI_MPI_COUNT_TYPE *value); +/* MPI-5.1 section 12.6.1. Blocking, synchronizing collective; sets the number + * of notification counters attached at the calling MPI process to exactly + * num_notifications and resets every counter to zero. */ +typedef int (*ompi_osc_base_module_win_set_num_notify_fn_t)(struct ompi_win_t *win, + struct opal_info_t *info, + int num_notifications); + +/* MPI-5.1 section 12.6.1. Local; returns the number of notification counters + * attached at target_rank. */ +typedef int (*ompi_osc_base_module_win_get_num_notify_fn_t)(struct ompi_win_t *win, + int target_rank, + int *num_notifications); + typedef int (*ompi_osc_base_module_accumulate_fn_t)(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, @@ -459,6 +472,8 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_get_notify_fn_t osc_get_notify; ompi_osc_base_module_win_get_notify_value_fn_t osc_win_get_notify_value; ompi_osc_base_module_win_reset_notify_value_fn_t osc_win_reset_notify_value; + ompi_osc_base_module_win_set_num_notify_fn_t osc_win_set_num_notify; + ompi_osc_base_module_win_get_num_notify_fn_t osc_win_get_num_notify; ompi_osc_base_module_rput_notify_fn_t osc_rput_notify; ompi_osc_base_module_rget_notify_fn_t osc_rget_notify; }; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index 85d250bfa18..d9ac9742f80 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -158,6 +158,14 @@ int ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, int notify, OMPI_MPI_COUNT_TYPE *value); +int ompi_osc_sm_win_set_num_notify(struct ompi_win_t *win, + struct opal_info_t *info, + int num_notifications); + +int ompi_osc_sm_win_get_num_notify(struct ompi_win_t *win, + int target_rank, + int *num_notifications); + int ompi_osc_sm_accumulate(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 78966b4d809..fdb598dff29 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -69,6 +69,83 @@ ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, return OMPI_SUCCESS; } +int +ompi_osc_sm_win_set_num_notify(struct ompi_win_t *win, + struct opal_info_t *info, + int num_notifications) +{ + ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; + int rank = ompi_comm_rank(module->comm); + int ret; + + /* "mpi_assert_same_num_notifications" is an optimization hint only, and + * osc/sm reserves the same fixed number of counters at every rank + * regardless, so there is nothing to specialize on. */ + (void) info; + + if (num_notifications < 0) { + return MPI_ERR_ARG; + } + + /* A fixed region of OSC_SM_MAX_NOTIFY_COUNTERS counters per rank is carved + * out of the shared segment at window creation, so that is the effective + * MPI_WIN_NOTIFICATION_NUM_UB. Asking for more cannot be satisfied without + * re-creating the segment. */ + if (num_notifications > OSC_SM_MAX_NOTIFY_COUNTERS) { + return MPI_ERR_ARG; + } + + /* MPI-5.1 section 12.6.1: "A subsequent call to MPI_WIN_GET_NUM_NOTIFY will + * return the value given to MPI_WIN_SET_NUM_NOTIFY." The count is set to + * exactly what was asked for -- note this differs from earlier drafts of + * the chapter, which forbade decreasing it. + * + * "All notification counters (both existing and newly attached) are reset + * to zero by this call." Zero the whole reserved region rather than just + * the attached prefix, so that counters left over from a previous, larger + * attachment cannot resurface if the count is raised again. It is + * erroneous to call this while an access epoch is open, so no origin can be + * incrementing our counters concurrently and plain stores are sufficient. */ + memset((void *) osc_sm_target_notify_base(module, rank), 0, + OSC_SM_MAX_NOTIFY_COUNTERS * sizeof(int64_t)); + module->node_states[rank].notify_counter_count = (uint32_t) num_notifications; + opal_atomic_wmb(); + + /* "MPI_WIN_SET_NUM_NOTIFY is a blocking, synchronizing collective + * procedure; it will not return until all MPI processes in the group of the + * window have called the function and all processes have adjusted the + * number of notification counters attached to the window." Each rank + * publishes its own count into the shared segment above, so the barrier is + * all that is needed to make every rank's count visible to every other -- + * no counts have to be exchanged. */ + ret = module->comm->c_coll->coll_barrier(module->comm, + module->comm->c_coll->coll_barrier_module); + if (OMPI_SUCCESS != ret) { + return ret; + } + + return OMPI_SUCCESS; +} + +int +ompi_osc_sm_win_get_num_notify(struct ompi_win_t *win, + int target_rank, + int *num_notifications) +{ + ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; + + if (target_rank < 0 || target_rank >= ompi_comm_size(module->comm)) { + return MPI_ERR_RANK; + } + + /* MPI-5.1 section 12.6.1: local procedure returning the number of counters + * attached at target_rank. Every rank's count is published in the shared + * segment by MPI_WIN_SET_NUM_NOTIFY, so this is a plain read. */ + *num_notifications = (int) module->node_states[target_rank].notify_counter_count; + + return OMPI_SUCCESS; +} + int ompi_osc_sm_rput(const void *origin_addr, size_t origin_count, diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index 259c0826017..a50db388b3a 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -84,6 +84,8 @@ ompi_osc_sm_module_t ompi_osc_sm_module_template = { .osc_get_notify = ompi_osc_sm_get_notify, .osc_win_get_notify_value = ompi_osc_sm_win_get_notify_value, .osc_win_reset_notify_value = ompi_osc_sm_win_reset_notify_value, + .osc_win_set_num_notify = ompi_osc_sm_win_set_num_notify, + .osc_win_get_num_notify = ompi_osc_sm_win_get_num_notify, .osc_accumulate = ompi_osc_sm_accumulate, .osc_compare_and_swap = ompi_osc_sm_compare_and_swap, .osc_fetch_and_op = ompi_osc_sm_fetch_and_op, diff --git a/ompi/mpi/c/Makefile.am b/ompi/mpi/c/Makefile.am index 7aecd5a3411..50a16c9d134 100644 --- a/ompi/mpi/c/Makefile.am +++ b/ompi/mpi/c/Makefile.am @@ -488,6 +488,8 @@ prototype_sources = \ win_get_name.c.in \ win_get_notify_value.c.in \ win_reset_notify_value.c.in \ + win_get_num_notify.c.in \ + win_set_num_notify.c.in \ win_lock_all.c.in \ win_lock.c.in \ win_post.c.in \ @@ -702,6 +704,7 @@ interface_profile_sources = \ get_elements_x_generated.c \ get_hw_resource_info_generated.c \ get_library_version_generated.c \ + get_notify_generated.c \ get_processor_name_generated.c \ get_version_generated.c \ graph_create_generated.c \ @@ -815,6 +818,7 @@ interface_profile_sources = \ psend_init_generated.c \ publish_name_generated.c \ put_generated.c \ + put_notify_generated.c \ query_thread_generated.c \ raccumulate_generated.c \ recv_generated.c \ @@ -960,6 +964,8 @@ interface_profile_sources = \ win_get_name_generated.c \ win_get_notify_value_generated.c \ win_reset_notify_value_generated.c \ + win_get_num_notify_generated.c \ + win_set_num_notify_generated.c \ win_lock_all_generated.c \ win_lock_generated.c \ win_post_generated.c \ diff --git a/ompi/mpi/c/win_get_num_notify.c.in b/ompi/mpi/c/win_get_num_notify.c.in new file mode 100644 index 00000000000..9ec6b60b5bc --- /dev/null +++ b/ompi/mpi/c/win_get_num_notify.c.in @@ -0,0 +1,43 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2026 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" + +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" + +PROTOTYPE ERROR_CLASS win_get_num_notify(WIN win, INT target_rank, INT_OUT num_notifications) +{ + int rc; + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (NULL == num_notifications) { + rc = MPI_ERR_ARG; + } + + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + if (NULL == win->w_osc_module->osc_win_get_num_notify) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + + rc = win->w_osc_module->osc_win_get_num_notify(win, target_rank, num_notifications); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} diff --git a/ompi/mpi/c/win_set_num_notify.c.in b/ompi/mpi/c/win_set_num_notify.c.in new file mode 100644 index 00000000000..cc1d39a9e77 --- /dev/null +++ b/ompi/mpi/c/win_set_num_notify.c.in @@ -0,0 +1,48 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2026 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" + +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/info/info.h" +#include "ompi/mca/osc/osc.h" + +PROTOTYPE ERROR_CLASS win_set_num_notify(WIN win, INFO info, INT num_notifications) +{ + int rc; + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (NULL != info && MPI_INFO_NULL != info && ompi_info_is_freed(info)) { + rc = MPI_ERR_INFO; + } else if (num_notifications < 0) { + rc = MPI_ERR_ARG; + } + + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + if (NULL == win->w_osc_module->osc_win_set_num_notify) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + + rc = win->w_osc_module->osc_win_set_num_notify(win, + (NULL != info && MPI_INFO_NULL != info) ? &(info->super) : NULL, + num_notifications); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} From 773703c1e23088b432c01e28cdb70a61cf2d4d7d Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Sun, 2 Aug 2026 00:03:55 -0400 Subject: [PATCH 19/24] osc/sm: fix notification counter ordering and index validation Three correctness problems in the osc/sm notified communication path: 1. The notification counters were plain uint64_t but are incremented concurrently by remote origins with opal_atomic_add() and polled by the local rank. Type them opal_atomic_int64_t so that the reads in MPI_WIN_GET_NOTIFY_VALUE are atomic and cannot be hoisted out of a caller's polling loop. 2. The notification index was validated *after* the data movement, so an erroneous call had already overwritten the target window (or, for get, the origin buffer) by the time the error was returned. MPI-5.1 section 12.6.1 makes referencing an out-of-range counter erroneous at initiation, so hoist the check above ompi_datatype_sndrcv() in all four notified operations. The check is factored into a helper, which also fixes MPI_GET_NOTIFY returning OMPI_ERR_BAD_PARAM instead of MPI_ERR_RMA_NOTIFICATION. 3. The get paths used opal_atomic_rmb() before incrementing the target's counter. The notification tells the target that the get has read the window, so the constraint is load-before-store, which a load-load fence does not express; opal_atomic_add() is relaxed and adds no ordering of its own. Use a full opal_atomic_mb(). In MPI_WIN_GET_NOTIFY_VALUE the barrier was likewise placed before the counter load, where it ordered nothing; move it after so that it gives the acquire semantics the caller needs. MPI_WIN_RESET_NOTIFY_VALUE also gains the trailing barrier for the same reason. Signed-off-by: Joseph Antony --- ompi/mca/osc/sm/osc_sm.h | 15 +++- ompi/mca/osc/sm/osc_sm_comm.c | 119 +++++++++++++++++++++-------- ompi/mca/osc/sm/osc_sm_component.c | 19 +++-- 3 files changed, 117 insertions(+), 36 deletions(-) diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index d9ac9742f80..88962891ecd 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -22,6 +22,12 @@ typedef uint64_t osc_sm_post_type_t; typedef opal_atomic_uint64_t osc_sm_post_atomic_type_t; #define OSC_SM_POST_BITS 6 #define OSC_SM_POST_MASK 0x3f + +/* Capacity of the per-rank notification counter region reserved in the shared + * segment at window creation, i.e. the effective + * MPI_WIN_NOTIFICATION_NUM_UB. How many of those counters are actually + * *attached* is a separate, per-rank quantity that starts at zero and is set by + * MPI_WIN_SET_NUM_NOTIFY (MPI-5.1 section 12.6.1). */ #define OSC_SM_MAX_NOTIFY_COUNTERS 16 /* data shared across all peers */ @@ -48,6 +54,10 @@ struct ompi_osc_sm_node_state_t { opal_atomic_int32_t complete_count; ompi_osc_sm_lock_t lock; opal_atomic_lock_t accumulate_lock; + /* Number of notification counters currently *attached* at this rank. Zero + * until MPI_WIN_SET_NUM_NOTIFY is called (MPI-5.1 section 12.6.1). Lives in + * the shared segment so that an origin can validate a notification index + * against the target's attached count without any communication. */ uint32_t notify_counter_count; uint64_t notify_counter_offset; /* offset from segment_base, not raw pointer */ @@ -83,7 +93,10 @@ struct ompi_osc_sm_module_t { size_t *sizes; void **bases; ptrdiff_t *disp_units; - uint64_t *notify_counters; + /* Base of the notification counter region. Typed atomic so that plain + * loads are atomic (and never hoisted out of a caller's polling loop) while + * remote origins increment the same location with opal_atomic_add(). */ + opal_atomic_int64_t *notify_counters; ompi_group_t *start_group; diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index fdb598dff29..a5b27b65fc4 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -21,15 +21,36 @@ #include "osc_sm.h" -static inline uint64_t *osc_sm_target_notify_base(ompi_osc_sm_module_t *module, int target) +static inline opal_atomic_int64_t * +osc_sm_target_notify_base(ompi_osc_sm_module_t *module, int target) { if (NULL == module->segment_base) { /* single-rank path: notify_counters is a regular local allocation */ return module->notify_counters; } - return (uint64_t *) ((char *) module->segment_base + - module->node_states[target].notify_counter_offset); + return (opal_atomic_int64_t *) ((char *) module->segment_base + + module->node_states[target].notify_counter_offset); +} + +/* MPI-5.1 section 12.6.1: "The notification counter referenced by a notified + * communication operation must be attached to the window at the target before + * the operation is initiated at the origin. Initiating a notified + * communication operation that references a notification counter that is out of + * range at the target is erroneous." + * + * The check is therefore against the *target's* attached count, and it must + * happen before any data is moved -- otherwise an erroneous call would still + * have overwritten the target window (or, for get, the origin buffer) by the + * time the error is reported. */ +static inline int +osc_sm_check_notify_idx(ompi_osc_sm_module_t *module, int target, int notify) +{ + if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { + return MPI_ERR_RMA_NOTIFICATION; + } + + return OMPI_SUCCESS; } int @@ -39,11 +60,24 @@ ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, { ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; int rank = ompi_comm_rank(module->comm); + int ret; - if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { - return MPI_ERR_RMA_NOTIFICATION; + ret = osc_sm_check_notify_idx(module, rank, notify); + if (OMPI_SUCCESS != ret) { + return ret; } + /* Acquire ordering: sample the counter first, then fence, so that window + * loads issued by the caller after this call cannot be satisfied by values + * read before the notification was observed. A barrier placed ahead of the + * counter load would order nothing useful. MPI-5.1 section 12.6.2 requires + * this procedure to synchronize the public and private window copies as if + * MPI_WIN_SYNC had been called; osc/sm is a unified-memory-model component, + * so the barrier is the whole of that synchronization. + * + * The load itself is atomic because notify_counters is opal_atomic_int64_t: + * remote origins bump the same location concurrently, and the standard's + * usage model is to poll this procedure in a loop. */ *value = (OMPI_MPI_COUNT_TYPE) osc_sm_target_notify_base(module, rank)[notify]; opal_atomic_rmb(); @@ -57,14 +91,19 @@ ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, { ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; int rank = ompi_comm_rank(module->comm); + int ret; - if (notify < 0 || (uint32_t) notify >= module->node_states[rank].notify_counter_count) { - return MPI_ERR_RMA_NOTIFICATION; + ret = osc_sm_check_notify_idx(module, rank, notify); + if (OMPI_SUCCESS != ret) { + return ret; } - /* Atomically swap the counter to 0 and return the previous value */ + /* Atomically swap the counter to 0 and return the previous value. Must be + * a single atomic so that increments arriving from other MPI processes + * between the read and the zeroing are not lost. */ *value = (OMPI_MPI_COUNT_TYPE) opal_atomic_swap_64( &osc_sm_target_notify_base(module, rank)[notify], 0); + opal_atomic_rmb(); return OMPI_SUCCESS; } @@ -210,6 +249,11 @@ ompi_osc_sm_rput_notify(const void *origin_addr, notify, (unsigned long) win)); + ret = osc_sm_check_notify_idx(module, target, notify); + if (OMPI_SUCCESS != ret) { + return ret; + } + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; ret = ompi_datatype_sndrcv((void *)origin_addr, origin_count, origin_dt, @@ -218,18 +262,18 @@ ompi_osc_sm_rput_notify(const void *origin_addr, return ret; } + /* Release ordering: the data must be visible at the target before the + * notification is (MPI-5.1 section 12.3, "The notification counter will be + * updated at the target only after the completion of the data movement + * operation at the target"). */ + opal_atomic_wmb(); + opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); + /* the only valid field of RMA request status is the MPI_ERROR field. * ompi_request_empty has status MPI_SUCCESS and indicates the request is * complete. */ *ompi_req = &ompi_request_empty; - if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { - return MPI_ERR_RMA_NOTIFICATION; - } - - opal_atomic_wmb(); - opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); - return OMPI_SUCCESS; } @@ -297,6 +341,11 @@ ompi_osc_sm_rget_notify(void *origin_addr, notify, (unsigned long) win)); + ret = osc_sm_check_notify_idx(module, target, notify); + if (OMPI_SUCCESS != ret) { + return ret; + } + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; ret = ompi_datatype_sndrcv(remote_address, target_count, target_dt, @@ -305,18 +354,20 @@ ompi_osc_sm_rget_notify(void *origin_addr, return ret; } + /* Full barrier, not opal_atomic_rmb(): the notification tells the target + * that this get has read the window, so the loads above must not be + * reordered after the counter increment below -- that is a load-before-store + * constraint, which a load-load fence does not express. opal_atomic_add() + * is relaxed (see opal/include/opal/sys/atomic_stdc.h) and supplies no + * ordering of its own. */ + opal_atomic_mb(); + opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); + /* the only valid field of RMA request status is the MPI_ERROR field. * ompi_request_empty has status MPI_SUCCESS and indicates the request is * complete. */ *ompi_req = &ompi_request_empty; - if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { - return MPI_ERR_RMA_NOTIFICATION; - } - - opal_atomic_rmb(); - opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); - return OMPI_SUCCESS; } @@ -480,6 +531,11 @@ ompi_osc_sm_put_notify(const void *origin_addr, notify, (unsigned long) win)); + ret = osc_sm_check_notify_idx(module, target, notify); + if (OMPI_SUCCESS != ret) { + return ret; + } + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; ret = ompi_datatype_sndrcv((void *)origin_addr, origin_count, origin_dt, @@ -488,10 +544,10 @@ ompi_osc_sm_put_notify(const void *origin_addr, return ret; } - if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { - return MPI_ERR_RMA_NOTIFICATION; - } - + /* Release ordering: the data must be visible at the target before the + * notification is (MPI-5.1 section 12.3, "The notification counter will be + * updated at the target only after the completion of the data movement + * operation at the target"). */ opal_atomic_wmb(); opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); @@ -552,6 +608,11 @@ ompi_osc_sm_get_notify(void *origin_addr, target_count, target_dt->name, (unsigned long) win)); + ret = osc_sm_check_notify_idx(module, target, notify); + if (OMPI_SUCCESS != ret) { + return ret; + } + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; ret = ompi_datatype_sndrcv(remote_address, target_count, target_dt, @@ -559,11 +620,9 @@ ompi_osc_sm_get_notify(void *origin_addr, if (OMPI_SUCCESS != ret) { return ret; } - if (notify < 0 || (uint32_t) notify >= module->node_states[target].notify_counter_count) { - return OMPI_ERR_BAD_PARAM; - } - opal_atomic_rmb(); + /* Full barrier, not opal_atomic_rmb(): see ompi_osc_sm_rget_notify(). */ + opal_atomic_mb(); opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); return ret; diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index a50db388b3a..9af4530c77c 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -260,8 +260,15 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis if (NULL == module->posts) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; module->posts[0] = (osc_sm_post_atomic_type_t *) (module->posts + 1); - /* allocate notify counters for single process case */ - module->notify_counters = calloc(OSC_SM_MAX_NOTIFY_COUNTERS, sizeof(uint64_t)); + /* allocate notify counters for single process case. + * + * NOTE: osc/sm pre-attaches the full reserved capacity, whereas osc/ucx + * starts at zero and requires MPI_WIN_SET_NUM_NOTIFY before any counter + * may be referenced. MPI-5.1 section 12.6.1 does not state what the + * initial attached count is, so neither is provably wrong, but the + * divergence means a program that omits MPI_WIN_SET_NUM_NOTIFY works + * here and fails on ucx. Left as-is pending a decision. */ + module->notify_counters = calloc(OSC_SM_MAX_NOTIFY_COUNTERS, sizeof(int64_t)); if (NULL == module->notify_counters) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; module->node_states[0].notify_counter_count = OSC_SM_MAX_NOTIFY_COUNTERS; module->node_states[0].notify_counter_offset = 0; @@ -394,10 +401,10 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis module->node_states = (ompi_osc_sm_node_state_t *) (module->global_state + 1); /* set up notify counters in shared memory after node_states */ - module->notify_counters = (uint64_t *) ((char *)(module->node_states + comm_size) + + module->notify_counters = (opal_atomic_int64_t *) ((char *)(module->node_states + comm_size) + OPAL_ALIGN_PAD_AMOUNT((uintptr_t)(module->node_states + comm_size), 64)); /* zero out notify counters */ - memset(module->notify_counters, 0, total_counters * sizeof(uint64_t)); + memset((void *) module->notify_counters, 0, total_counters * sizeof(int64_t)); for (i = 0, total = data_base_size, total_counters = 0 ; i < comm_size ; ++i) { if (i > 0) { @@ -593,7 +600,9 @@ ompi_osc_sm_free(struct ompi_win_t *win) module->bases[0]); } /* free notify_counters for single process case */ - free(module->notify_counters); + /* cast away the atomic/volatile qualifier for free(), as in + * opal/runtime/opal_progress.c */ + free((void *) module->notify_counters); } free(module->disp_units); free(module->outstanding_locks); From e69cacc72408fc3841766a24a6a9c2c904eac0bb Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Mon, 10 Aug 2026 20:45:20 -0400 Subject: [PATCH 20/24] osc/sm: complete the notified RMA operation set and grow counters Adds the six remaining notified operations from the MPI-5.1 draft -- accumulate, get_accumulate, and the four request-based forms -- so that osc/sm covers all eight defined in section 12.3, and sizes the notification counters from window info rather than a compile-time constant. The counter region was a fixed 16 entries per MPI process carved out of the shared segment, and MPI_WIN_SET_NUM_NOTIFY rejected anything larger. That conflicts with the mpi_assert_max_num_notify info key, whose default of 0 the standard defines as "the implementation does not assume any limit on the number of notification counters". The reservation now comes from that key when one is given, and otherwise from a new osc_sm_num_notify_counters MCA parameter. A request beyond the reservation relocates the counters to a dedicated shared segment instead of failing; when the key was given it is a hard bound, since the window was sized on the strength of that assertion. Growth is collective and runs inside MPI_WIN_SET_NUM_NOTIFY, which the standard already defines as a blocking synchronizing collective. Every process agrees on the new layout through an allgather of the requested counts, and on whether the attach succeeded through an allreduce, so a failure at one process cannot leave others incrementing counters that nobody reads. The published count stays clamped to the current allocation until the larger one exists, so a failed growth cannot leave behind a count that would admit writes past the end of the region. A barrier separates the attach from the unlink, because attach opens the backing file by name and the broadcast does not tell rank 0 that the other processes are finished with it. Each process now caches a per-target pointer to the counters, making the lookup on the path of every notified operation a single indexed load -- cheaper than the previous base-plus-offset arithmetic -- so the ability to relocate the region costs the hot path nothing. Also corrects the reset at the end of component_select(), which zeroed the whole node state and so wiped the notification fields it had just written, and removes a stray double semicolon in ompi_osc_sm_fetch_and_op(). Signed-off-by: Joseph Antony --- ompi/include/mpi.h.in | 104 +++++ ompi/mca/osc/osc.h | 56 +++ ompi/mca/osc/sm/osc_sm.h | 125 +++++- ompi/mca/osc/sm/osc_sm_comm.c | 542 +++++++++++++++++++++++-- ompi/mca/osc/sm/osc_sm_component.c | 161 +++++++- ompi/mpi/c/Makefile.am | 12 + ompi/mpi/c/accumulate_notify.c.in | 141 +++++++ ompi/mpi/c/get_accumulate_notify.c.in | 150 +++++++ ompi/mpi/c/get_notify.c.in | 4 + ompi/mpi/c/put_notify.c.in | 4 + ompi/mpi/c/raccumulate_notify.c.in | 143 +++++++ ompi/mpi/c/rget_accumulate_notify.c.in | 152 +++++++ ompi/mpi/c/rget_notify.c.in | 93 +++++ ompi/mpi/c/rput_notify.c.in | 93 +++++ ompi/mpi/c/win_get_notify_value.c.in | 4 + ompi/mpi/c/win_reset_notify_value.c.in | 4 + ompi/runtime/ompi_spc.c | 2 + ompi/runtime/ompi_spc.h | 2 + 18 files changed, 1732 insertions(+), 60 deletions(-) create mode 100644 ompi/mpi/c/accumulate_notify.c.in create mode 100644 ompi/mpi/c/get_accumulate_notify.c.in create mode 100644 ompi/mpi/c/raccumulate_notify.c.in create mode 100644 ompi/mpi/c/rget_accumulate_notify.c.in create mode 100644 ompi/mpi/c/rget_notify.c.in create mode 100644 ompi/mpi/c/rput_notify.c.in diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index 71afc4cefbc..d259c5ab4f3 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -1463,6 +1463,14 @@ OMPI_DECLSPEC int MPI_Accumulate(const void *origin_addr, int origin_count, MPI OMPI_DECLSPEC int MPI_Accumulate_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win); +OMPI_DECLSPEC int MPI_Accumulate_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win); +OMPI_DECLSPEC int MPI_Accumulate_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win); OMPI_DECLSPEC int MPI_Add_error_class(int *errorclass); OMPI_DECLSPEC int MPI_Add_error_code(int errorclass, int *errorcode); OMPI_DECLSPEC int MPI_Add_error_string(int errorcode, const char *string); @@ -1938,6 +1946,16 @@ OMPI_DECLSPEC int MPI_Get_accumulate_c(const void *origin_addr, MPI_Count origi void *result_addr, MPI_Count result_count, MPI_Datatype result_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win); +OMPI_DECLSPEC int MPI_Get_accumulate_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + void *result_addr, int result_count, MPI_Datatype result_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win); +OMPI_DECLSPEC int MPI_Get_accumulate_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + void *result_addr, MPI_Count result_count, MPI_Datatype result_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win); OMPI_DECLSPEC int MPI_Get_library_version(char *version, int *resultlen); OMPI_DECLSPEC int MPI_Get_processor_name(char *name, int *resultlen); OMPI_DECLSPEC int MPI_Get_version(int *version, int *subversion); @@ -2206,6 +2224,14 @@ OMPI_DECLSPEC int MPI_Raccumulate(const void *origin_addr, int origin_count, MP OMPI_DECLSPEC int MPI_Raccumulate_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int MPI_Raccumulate_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int MPI_Raccumulate_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win, MPI_Request *request); OMPI_DECLSPEC int MPI_Recv_init(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int MPI_Recv_init_c(void *buf, MPI_Count count, MPI_Datatype datatype, int source, @@ -2284,6 +2310,14 @@ OMPI_DECLSPEC int MPI_Rget(void *origin_addr, int origin_count, MPI_Datatype or OMPI_DECLSPEC int MPI_Rget_c(void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int MPI_Rget_notify(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, int notification_idx, + MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int MPI_Rget_notify_c(void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, int notification_idx, + MPI_Win win, MPI_Request *request); OMPI_DECLSPEC int MPI_Rget_accumulate(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, void *result_addr, int result_count, MPI_Datatype result_datatype, int target_rank, MPI_Aint target_disp, int target_count, @@ -2294,12 +2328,30 @@ OMPI_DECLSPEC int MPI_Rget_accumulate_c(const void *origin_addr, MPI_Count orig int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int MPI_Rget_accumulate_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + void *result_addr, int result_count, MPI_Datatype result_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int MPI_Rget_accumulate_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + void *result_addr, MPI_Count result_count, MPI_Datatype result_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win, MPI_Request *request); OMPI_DECLSPEC int MPI_Rput(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_cout, MPI_Datatype target_datatype, MPI_Win win, MPI_Request *request); OMPI_DECLSPEC int MPI_Rput_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_cout, MPI_Datatype target_datatype, MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int MPI_Rput_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, int notification_idx, + MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int MPI_Rput_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, int notification_idx, + MPI_Win win, MPI_Request *request); OMPI_DECLSPEC int MPI_Rsend(const void *ibuf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm); OMPI_DECLSPEC int MPI_Rsend_c(const void *ibuf, MPI_Count count, MPI_Datatype datatype, int dest, @@ -2655,6 +2707,14 @@ OMPI_DECLSPEC int PMPI_Accumulate(const void *origin_addr, int origin_count, MP OMPI_DECLSPEC int PMPI_Accumulate_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win); +OMPI_DECLSPEC int PMPI_Accumulate_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win); +OMPI_DECLSPEC int PMPI_Accumulate_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win); OMPI_DECLSPEC int PMPI_Add_error_class(int *errorclass); OMPI_DECLSPEC int PMPI_Add_error_code(int errorclass, int *errorcode); OMPI_DECLSPEC int PMPI_Add_error_string(int errorcode, const char *string); @@ -3130,6 +3190,16 @@ OMPI_DECLSPEC int PMPI_Get_accumulate_c(const void *origin_addr, MPI_Count orig void *result_addr, MPI_Count result_count, MPI_Datatype result_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win); +OMPI_DECLSPEC int PMPI_Get_accumulate_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + void *result_addr, int result_count, MPI_Datatype result_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win); +OMPI_DECLSPEC int PMPI_Get_accumulate_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + void *result_addr, MPI_Count result_count, MPI_Datatype result_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win); OMPI_DECLSPEC int PMPI_Get_library_version(char *version, int *resultlen); OMPI_DECLSPEC int PMPI_Get_processor_name(char *name, int *resultlen); OMPI_DECLSPEC int PMPI_Get_version(int *version, int *subversion); @@ -3398,6 +3468,14 @@ OMPI_DECLSPEC int PMPI_Raccumulate(const void *origin_addr, int origin_count, M OMPI_DECLSPEC int PMPI_Raccumulate_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int PMPI_Raccumulate_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int PMPI_Raccumulate_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win, MPI_Request *request); OMPI_DECLSPEC int PMPI_Recv_init(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int PMPI_Recv_init_c(void *buf, MPI_Count count, MPI_Datatype datatype, int source, @@ -3476,6 +3554,14 @@ OMPI_DECLSPEC int PMPI_Rget(void *origin_addr, int origin_count, MPI_Datatype o OMPI_DECLSPEC int PMPI_Rget_c(void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int PMPI_Rget_notify(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, int notification_idx, + MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int PMPI_Rget_notify_c(void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, int notification_idx, + MPI_Win win, MPI_Request *request); OMPI_DECLSPEC int PMPI_Rget_accumulate(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, void *result_addr, int result_count, MPI_Datatype result_datatype, int target_rank, MPI_Aint target_disp, int target_count, @@ -3486,12 +3572,30 @@ OMPI_DECLSPEC int PMPI_Rget_accumulate_c(const void *origin_addr, MPI_Count ori int target_rank, MPI_Aint target_disp, MPI_Count target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int PMPI_Rget_accumulate_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + void *result_addr, int result_count, MPI_Datatype result_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int PMPI_Rget_accumulate_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + void *result_addr, MPI_Count result_count, MPI_Datatype result_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, MPI_Op op, int notification_idx, + MPI_Win win, MPI_Request *request); OMPI_DECLSPEC int PMPI_Rput(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_cout, MPI_Datatype target_datatype, MPI_Win win, MPI_Request *request); OMPI_DECLSPEC int PMPI_Rput_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, MPI_Count target_cout, MPI_Datatype target_datatype, MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int PMPI_Rput_notify(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, int target_count, + MPI_Datatype target_datatype, int notification_idx, + MPI_Win win, MPI_Request *request); +OMPI_DECLSPEC int PMPI_Rput_notify_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, int notification_idx, + MPI_Win win, MPI_Request *request); OMPI_DECLSPEC int PMPI_Rsend(const void *ibuf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm); OMPI_DECLSPEC int PMPI_Rsend_c(const void *ibuf, MPI_Count count, MPI_Datatype datatype, int dest, diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index 2f66c2ac107..74197cd3ac3 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -276,6 +276,17 @@ typedef int (*ompi_osc_base_module_accumulate_fn_t)(const void *origin_addr, struct ompi_op_t *op, struct ompi_win_t *win); +typedef int (*ompi_osc_base_module_accumulate_notify_fn_t)(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win); + typedef int (*ompi_osc_base_module_compare_and_swap_fn_t)(const void *origin_addr, const void *compare_addr, void *result_addr, @@ -305,6 +316,20 @@ typedef int (*ompi_osc_base_module_get_accumulate_fn_t)(const void *origin_addr, struct ompi_op_t *op, struct ompi_win_t *win); +typedef int (*ompi_osc_base_module_get_accumulate_notify_fn_t)(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_datatype, + void *result_addr, + size_t result_count, + struct ompi_datatype_t *result_datatype, + int target_rank, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_datatype, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win); + typedef int (*ompi_osc_base_module_rput_fn_t)(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, @@ -358,6 +383,18 @@ typedef int (*ompi_osc_base_module_raccumulate_fn_t)(const void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); +typedef int (*ompi_osc_base_module_raccumulate_notify_fn_t)(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **request); + typedef int (*ompi_osc_base_module_rget_accumulate_fn_t)(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_datatype, @@ -372,6 +409,21 @@ typedef int (*ompi_osc_base_module_rget_accumulate_fn_t)(const void *origin_addr struct ompi_win_t *win, struct ompi_request_t **request); +typedef int (*ompi_osc_base_module_rget_accumulate_notify_fn_t)(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_datatype, + void *result_addr, + size_t result_count, + struct ompi_datatype_t *result_datatype, + int target_rank, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_datatype, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **request); + typedef int (*ompi_osc_base_module_fence_fn_t)(int mpi_assert, struct ompi_win_t *win); @@ -476,6 +528,10 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_win_get_num_notify_fn_t osc_win_get_num_notify; ompi_osc_base_module_rput_notify_fn_t osc_rput_notify; ompi_osc_base_module_rget_notify_fn_t osc_rget_notify; + ompi_osc_base_module_accumulate_notify_fn_t osc_accumulate_notify; + ompi_osc_base_module_get_accumulate_notify_fn_t osc_get_accumulate_notify; + ompi_osc_base_module_raccumulate_notify_fn_t osc_raccumulate_notify; + ompi_osc_base_module_rget_accumulate_notify_fn_t osc_rget_accumulate_notify; }; typedef struct ompi_osc_base_module_4_0_0_t ompi_osc_base_module_4_0_0_t; typedef ompi_osc_base_module_4_0_0_t ompi_osc_base_module_t; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index 88962891ecd..75ea8cffebe 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -23,12 +23,18 @@ typedef opal_atomic_uint64_t osc_sm_post_atomic_type_t; #define OSC_SM_POST_BITS 6 #define OSC_SM_POST_MASK 0x3f -/* Capacity of the per-rank notification counter region reserved in the shared - * segment at window creation, i.e. the effective - * MPI_WIN_NOTIFICATION_NUM_UB. How many of those counters are actually - * *attached* is a separate, per-rank quantity that starts at zero and is set by - * MPI_WIN_SET_NUM_NOTIFY (MPI-5.1 section 12.6.1). */ -#define OSC_SM_MAX_NOTIFY_COUNTERS 16 +/* Per-rank notification counter capacity reserved inline in the main shared + * segment at window creation, and the value reported as + * MPI_WIN_NOTIFICATION_NUM_SB -- the number of counters osc/sm supports without + * any further allocation. Overridden by the osc_sm_num_notify_counters MCA + * parameter, and per window by the mpi_assert_max_num_notify info key. + * + * This is a reservation, not a limit. When no info assertion was given, + * MPI_WIN_SET_NUM_NOTIFY may ask for more than this and osc/sm will move the + * counters to a larger, separately allocated shared segment; see + * ompi_osc_sm_win_set_num_notify(). How many counters are actually *attached* + * is a third, per-rank quantity (MPI-5.1 section 12.6.1). */ +#define OSC_SM_DEFAULT_NOTIFY_COUNTERS 16 /* data shared across all peers */ struct ompi_osc_sm_global_state_t { @@ -54,13 +60,21 @@ struct ompi_osc_sm_node_state_t { opal_atomic_int32_t complete_count; ompi_osc_sm_lock_t lock; opal_atomic_lock_t accumulate_lock; - /* Number of notification counters currently *attached* at this rank. Zero - * until MPI_WIN_SET_NUM_NOTIFY is called (MPI-5.1 section 12.6.1). Lives in - * the shared segment so that an origin can validate a notification index - * against the target's attached count without any communication. */ + /* Number of notification counters currently *attached* at this rank + * (MPI-5.1 section 12.6.1). Lives in the shared segment so that an origin + * can validate a notification index against the target's attached count + * without any communication. */ uint32_t notify_counter_count; - uint64_t notify_counter_offset; /* offset from segment_base, not raw pointer */ - + /* Number of counters currently *reserved* for this rank, i.e. how many it + * may attach without reallocating. This is the rank's + * MPI_WIN_NOTIFICATION_NUM_UB when the window was created with an + * mpi_assert_max_num_notify assertion. */ + uint32_t notify_counter_capacity; + /* Offset of this rank's counters within whichever segment currently holds + * them -- the main segment initially, an overflow segment after a growth. + * An offset rather than a pointer because the segment is mapped at a + * different address in every process. */ + uint64_t notify_counter_offset; }; typedef struct ompi_osc_sm_node_state_t ompi_osc_sm_node_state_t; @@ -71,6 +85,10 @@ struct ompi_osc_sm_component_t { unsigned int priority; char *backing_directory; + + /** Notification counters reserved per MPI process at window creation when + * the window's info gives no mpi_assert_max_num_notify hint */ + unsigned int num_notify_counters; }; typedef struct ompi_osc_sm_component_t ompi_osc_sm_component_t; OMPI_DECLSPEC extern ompi_osc_sm_component_t mca_osc_sm_component; @@ -93,10 +111,27 @@ struct ompi_osc_sm_module_t { size_t *sizes; void **bases; ptrdiff_t *disp_units; - /* Base of the notification counter region. Typed atomic so that plain - * loads are atomic (and never hoisted out of a caller's polling loop) while - * remote origins increment the same location with opal_atomic_add(). */ - opal_atomic_int64_t *notify_counters; + + /* notify_bases[i] is *this* process's address for rank i's notification + * counters. Private to each process, since the segment holding the + * counters is mapped at a different address in every process, and + * recomputed by ompi_osc_sm_refresh_notify_bases() whenever the counters + * move. Typed atomic so that plain loads are atomic (and never hoisted out + * of a caller's polling loop) while remote origins increment the same + * location with opal_atomic_add(). */ + opal_atomic_int64_t **notify_bases; + /* Overflow segment holding the counters once MPI_WIN_SET_NUM_NOTIFY has + * grown them past what was reserved inline in the main segment. NULL base + * while the counters still live in the main segment. For a single-rank + * window there is no shared segment at all and notify_bases[0] is a plain + * heap allocation owned by this module. */ + opal_shmem_ds_t notify_seg_ds; + void *notify_segment_base; + /* Value of the mpi_assert_max_num_notify info key, or 0 if none was given. + * Non-zero makes the reservation a hard cap: the user asserted they would + * not exceed it, so MPI_WIN_SET_NUM_NOTIFY refuses to grow past it rather + * than silently reallocating. */ + unsigned int notify_max_assert; ompi_group_t *start_group; @@ -124,6 +159,12 @@ int ompi_osc_sm_detach(struct ompi_win_t *win, const void *base); int ompi_osc_sm_free(struct ompi_win_t *win); +/* Recompute notify_bases[] from the segment that currently holds the counters. + * Must be called by every MPI process after the counters move, and at window + * creation. Not used for single-rank windows, whose counters are a plain heap + * allocation. */ +void ompi_osc_sm_refresh_notify_bases(ompi_osc_sm_module_t *module); + int ompi_osc_sm_put(const void *origin_addr, size_t origin_count, @@ -189,6 +230,17 @@ int ompi_osc_sm_accumulate(const void *origin_addr, struct ompi_op_t *op, struct ompi_win_t *win); +int ompi_osc_sm_accumulate_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win); + int ompi_osc_sm_compare_and_swap(const void *origin_addr, const void *compare_addr, void *result_addr, @@ -218,6 +270,20 @@ int ompi_osc_sm_get_accumulate(const void *origin_addr, struct ompi_op_t *op, struct ompi_win_t *win); +int ompi_osc_sm_get_accumulate_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_datatype, + void *result_addr, + size_t result_count, + struct ompi_datatype_t *result_datatype, + int target_rank, + MPI_Aint target_disp, + size_t target_count, + struct ompi_datatype_t *target_datatype, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win); + int ompi_osc_sm_rput(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, @@ -271,6 +337,18 @@ int ompi_osc_sm_raccumulate(const void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); +int ompi_osc_sm_raccumulate_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **request); + int ompi_osc_sm_rget_accumulate(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_datatype, @@ -285,6 +363,21 @@ int ompi_osc_sm_rget_accumulate(const void *origin_addr, struct ompi_win_t *win, struct ompi_request_t **request); +int ompi_osc_sm_rget_accumulate_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_datatype, + void *result_addr, + size_t result_count, + struct ompi_datatype_t *result_datatype, + int target_rank, + MPI_Aint target_disp, + size_t target_count, + struct ompi_datatype_t *target_datatype, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **request); + int ompi_osc_sm_fence(int mpi_assert, struct ompi_win_t *win); int ompi_osc_sm_start(struct ompi_group_t *group, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index a5b27b65fc4..410c440dd0a 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -18,19 +18,24 @@ #include "ompi/mca/osc/base/base.h" #include "ompi/mca/osc/base/osc_base_obj_convert.h" #include "ompi/communicator/communicator.h" +#include "opal/align.h" +#include "opal/util/printf.h" +#include "opal/util/sys_limits.h" + +#include +#include #include "osc_sm.h" +/* Where this process finds the target's notification counters. A single + * indexed load: the address is precomputed per target by + * ompi_osc_sm_refresh_notify_bases() so that neither the single-rank special + * case nor the possibility that the counters have been moved to an overflow + * segment costs anything on the path of every notified operation. */ static inline opal_atomic_int64_t * osc_sm_target_notify_base(ompi_osc_sm_module_t *module, int target) { - if (NULL == module->segment_base) { - /* single-rank path: notify_counters is a regular local allocation */ - return module->notify_counters; - } - - return (opal_atomic_int64_t *) ((char *) module->segment_base + - module->node_states[target].notify_counter_offset); + return module->notify_bases[target]; } /* MPI-5.1 section 12.6.1: "The notification counter referenced by a notified @@ -53,6 +58,30 @@ osc_sm_check_notify_idx(ompi_osc_sm_module_t *module, int target, int notify) return OMPI_SUCCESS; } +/* Publish the notification for an operation in the accumulate family. + * + * The fence is a full barrier rather than opal_atomic_wmb() because every + * accumulate-family operation both reads and writes the target window: plain + * accumulate is a read-modify-write of the target for any op other than + * MPI_REPLACE, and get-accumulate additionally copies the target's prior value + * out to the result buffer. MPI-5.1 section 12.6.4 requires that "the window + * locations have been accessed and that the notification counter has then been + * updated (in that order)" -- accesses include loads, so a store-store fence + * would not constrain the reads. opal_atomic_add() is relaxed (see + * opal/include/opal/sys/atomic_stdc.h) and supplies no ordering of its own. + * + * Called after the accumulate lock has been dropped. Holding the lock across + * the increment is unnecessary: the fence already guarantees this operation's + * accesses are visible before its own increment lands, and a concurrent origin + * whose accumulate becomes visible earlier than its increment does not violate + * anything the standard promises about a counter that merely counts. */ +static inline void +osc_sm_notify_accumulate_done(ompi_osc_sm_module_t *module, int target, int notify) +{ + opal_atomic_mb(); + opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); +} + int ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, int notify, @@ -75,7 +104,7 @@ ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, * MPI_WIN_SYNC had been called; osc/sm is a unified-memory-model component, * so the barrier is the whole of that synchronization. * - * The load itself is atomic because notify_counters is opal_atomic_int64_t: + * The load itself is atomic because the counters are opal_atomic_int64_t: * remote origins bump the same location concurrently, and the standard's * usage model is to poll this procedure in a loop. */ *value = (OMPI_MPI_COUNT_TYPE) osc_sm_target_notify_base(module, rank)[notify]; @@ -108,29 +137,172 @@ ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, return OMPI_SUCCESS; } +/* Move every rank's notification counters into a newly created shared segment + * sized for the capacities in new_caps. Collective over the window's + * communicator; every MPI process must call it with an identical new_caps. + * + * Only reachable when the window was created without an + * mpi_assert_max_num_notify assertion, since that assertion is precisely a + * promise that this will not be needed. */ +static int +osc_sm_grow_notify_counters(ompi_osc_sm_module_t *module, const unsigned long *new_caps, + unsigned long new_count) +{ + int comm_size = ompi_comm_size(module->comm); + int rank = ompi_comm_rank(module->comm); + opal_shmem_ds_t new_seg_ds; + opal_shmem_ds_t old_seg_ds = module->notify_seg_ds; + void *old_segment_base = module->notify_segment_base; + void *new_base; + unsigned long total_counters = 0; + size_t seg_size; + char *data_file; + int ret, i, status; + + for (i = 0 ; i < comm_size ; ++i) { + total_counters += new_caps[i]; + } + seg_size = total_counters * sizeof(int64_t); + seg_size += OPAL_ALIGN_PAD_AMOUNT(seg_size, opal_getpagesize()); + + memset(&new_seg_ds, 0, sizeof(new_seg_ds)); + + if (0 == rank) { + /* The cid alone does not distinguish successive segments for the same + * window, so include the generation implied by whether we already have + * an overflow segment plus the new size. */ + ret = opal_asprintf(&data_file, "%s" OPAL_PATH_SEP "osc_sm_notify.%s.%x.%d.%s.%lu", + mca_osc_sm_component.backing_directory, ompi_process_info.nodename, + OMPI_PROC_MY_NAME->jobid, (int) OMPI_PROC_MY_NAME->vpid, + ompi_comm_print_cid(module->comm), total_counters); + if (ret > 0) { + /* On failure leave new_seg_ds zeroed; the empty seg_name is the + * signal to every other MPI process that this collective failed, + * so that all of them return an error together instead of some + * hanging in the bcast that follows. */ + (void) opal_shmem_segment_create(&new_seg_ds, data_file, seg_size); + free(data_file); + } + } + + ret = module->comm->c_coll->coll_bcast(&new_seg_ds, sizeof(new_seg_ds), MPI_BYTE, 0, + module->comm, + module->comm->c_coll->coll_bcast_module); + if (OMPI_SUCCESS != ret) { + return ret; + } + + if ('\0' == new_seg_ds.seg_name[0]) { + return MPI_ERR_NO_MEM; + } + + new_base = opal_shmem_segment_attach(&new_seg_ds); + + /* Attach can fail at some MPI processes and not others. Agree on the + * outcome before touching any shared state: if even one process could not + * map the new segment, every process must keep using the old one, or those + * that moved would be incrementing counters that those that stayed never + * read. Nothing above this point has been mutated, so backing out is just + * dropping our own new mapping. */ + status = (NULL == new_base) ? 1 : 0; + ret = module->comm->c_coll->coll_allreduce(MPI_IN_PLACE, &status, 1, MPI_INT, MPI_MAX, + module->comm, + module->comm->c_coll->coll_allreduce_module); + if (OMPI_SUCCESS != ret) { + return ret; + } + + if (0 != status) { + if (NULL != new_base) { + opal_shmem_segment_detach(&new_seg_ds); + } + return MPI_ERR_NO_MEM; + } + + module->notify_segment_base = new_base; + module->notify_seg_ds = new_seg_ds; + + /* Republish the layout. Every MPI process computes the same offsets from + * the same new_caps, so these stores are identical everywhere; node_states + * lives in the main segment, which does not move. */ + total_counters = 0; + for (i = 0 ; i < comm_size ; ++i) { + module->node_states[i].notify_counter_capacity = (uint32_t) new_caps[i]; + module->node_states[i].notify_counter_offset = total_counters * sizeof(int64_t); + total_counters += new_caps[i]; + } + + ompi_osc_sm_refresh_notify_bases(module); + + /* Zero our own counters in their new home. This is also the first touch of + * these pages: if the backing filesystem cannot supply them the fault + * surfaces here rather than at some later notified operation. */ + memset((void *) module->notify_bases[rank], 0, + module->node_states[rank].notify_counter_capacity * sizeof(int64_t)); + + /* Only now raise the attached count to what was asked for. Until the + * space behind it exists, the count must not exceed the capacity: an origin + * validates notification indices against this count, so a count larger than + * the allocation would let a notified operation write past the end of our + * counters. */ + module->node_states[rank].notify_counter_count = (uint32_t) new_count; + opal_atomic_wmb(); + + /* Everyone has opened the new segment and published their layout. Both + * facts are needed before we continue: the unlink below removes the name + * that the attach above resolves, and an origin returning from this call + * may immediately validate a notification index against our count. */ + ret = module->comm->c_coll->coll_barrier(module->comm, + module->comm->c_coll->coll_barrier_module); + if (OMPI_SUCCESS != ret) { + return ret; + } + + if (0 == rank) { + opal_shmem_unlink(&module->notify_seg_ds); + } + + /* Dropping the old mapping is purely local -- munmap in one MPI process + * does not disturb any other process's view -- so it needs no + * synchronization of its own. On the first growth there is nothing to + * drop: the counters were inline in the main segment, which stays mapped + * for the lifetime of the window. */ + if (NULL != old_segment_base) { + opal_shmem_segment_detach(&old_seg_ds); + } + + return OMPI_SUCCESS; +} + int ompi_osc_sm_win_set_num_notify(struct ompi_win_t *win, struct opal_info_t *info, int num_notifications) { ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; + int comm_size = ompi_comm_size(module->comm); int rank = ompi_comm_rank(module->comm); - int ret; - - /* "mpi_assert_same_num_notifications" is an optimization hint only, and - * osc/sm reserves the same fixed number of counters at every rank - * regardless, so there is nothing to specialize on. */ + unsigned long requested = (unsigned long) num_notifications; + unsigned long *new_caps; + bool grow = false; + int ret, i; + + /* "mpi_assert_same_num_notifications" would let us skip the allgather below + * and derive the layout from our own num_notifications. Not taken up yet; + * the allgather is one collective on a procedure that is already + * synchronizing and collective. */ (void) info; if (num_notifications < 0) { return MPI_ERR_ARG; } - /* A fixed region of OSC_SM_MAX_NOTIFY_COUNTERS counters per rank is carved - * out of the shared segment at window creation, so that is the effective - * MPI_WIN_NOTIFICATION_NUM_UB. Asking for more cannot be satisfied without - * re-creating the segment. */ - if (num_notifications > OSC_SM_MAX_NOTIFY_COUNTERS) { + /* When the window was created with an mpi_assert_max_num_notify value the + * user asserted they would not exceed it, and we reserved exactly that + * many. Hold them to it rather than silently reallocating: honouring the + * assertion is the only reason the reservation is not generous. */ + if (0 != module->notify_max_assert && + requested > (unsigned long) module->notify_max_assert) { return MPI_ERR_ARG; } @@ -144,25 +316,78 @@ ompi_osc_sm_win_set_num_notify(struct ompi_win_t *win, * the attached prefix, so that counters left over from a previous, larger * attachment cannot resurface if the count is raised again. It is * erroneous to call this while an access epoch is open, so no origin can be - * incrementing our counters concurrently and plain stores are sufficient. */ - memset((void *) osc_sm_target_notify_base(module, rank), 0, - OSC_SM_MAX_NOTIFY_COUNTERS * sizeof(int64_t)); - module->node_states[rank].notify_counter_count = (uint32_t) num_notifications; + * incrementing our counters concurrently and plain stores are sufficient. + * + * Done before the allgather so that the allgather doubles as the + * synchronization the standard requires: once it returns, every MPI process + * has both reset its counters and published its new count. + * + * The published count is clamped to what we have actually allocated. When + * growth is needed it is raised to the requested value only once the larger + * allocation exists, so that a growth that fails leaves behind a count an + * origin can safely validate against rather than one that would admit + * writes past the end of our counters. */ + memset((void *) module->notify_bases[rank], 0, + module->node_states[rank].notify_counter_capacity * sizeof(int64_t)); + module->node_states[rank].notify_counter_count = + (requested > module->node_states[rank].notify_counter_capacity) + ? module->node_states[rank].notify_counter_capacity + : (uint32_t) requested; opal_atomic_wmb(); - /* "MPI_WIN_SET_NUM_NOTIFY is a blocking, synchronizing collective - * procedure; it will not return until all MPI processes in the group of the - * window have called the function and all processes have adjusted the - * number of notification counters attached to the window." Each rank - * publishes its own count into the shared segment above, so the barrier is - * all that is needed to make every rank's count visible to every other -- - * no counts have to be exchanged. */ - ret = module->comm->c_coll->coll_barrier(module->comm, - module->comm->c_coll->coll_barrier_module); + if (1 == comm_size) { + /* No shared segment for a single-process window; the counters are a + * plain allocation, so growing them is a plain reallocation and none of + * the collective machinery below applies. */ + if (requested > module->node_states[0].notify_counter_capacity) { + void *grown = calloc(requested, sizeof(int64_t)); + if (NULL == grown) { + return MPI_ERR_NO_MEM; + } + free((void *) module->notify_bases[0]); + module->notify_bases[0] = (opal_atomic_int64_t *) grown; + module->node_states[0].notify_counter_capacity = (uint32_t) requested; + module->node_states[0].notify_counter_count = (uint32_t) requested; + } + return OMPI_SUCCESS; + } + + new_caps = malloc(sizeof(*new_caps) * comm_size); + if (NULL == new_caps) { + return OMPI_ERR_TEMP_OUT_OF_RESOURCE; + } + + /* Ranks may pass different values, so the new layout cannot be computed + * without everyone's request. This also makes the grow/no-grow decision + * identical at every MPI process, which it must be: creating the new + * segment is itself collective. */ + ret = module->comm->c_coll->coll_allgather(&requested, 1, MPI_UNSIGNED_LONG, + new_caps, 1, MPI_UNSIGNED_LONG, + module->comm, + module->comm->c_coll->coll_allgather_module); if (OMPI_SUCCESS != ret) { + free(new_caps); return ret; } + for (i = 0 ; i < comm_size ; ++i) { + if (new_caps[i] > module->node_states[i].notify_counter_capacity) { + grow = true; + } else { + /* Never shrink: a rank that lowered its count keeps the space it + * already has, so that only genuine growth costs a reallocation. */ + new_caps[i] = module->node_states[i].notify_counter_capacity; + } + } + + if (grow) { + ret = osc_sm_grow_notify_counters(module, new_caps, requested); + free(new_caps); + return ret; + } + + free(new_caps); + return OMPI_SUCCESS; } @@ -418,6 +643,67 @@ ompi_osc_sm_raccumulate(const void *origin_addr, } +int +ompi_osc_sm_raccumulate_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **ompi_req) +{ + int ret; + ompi_osc_sm_module_t *module = + (ompi_osc_sm_module_t*) win->w_osc_module; + void *remote_address; + + OPAL_OUTPUT_VERBOSE((50, ompi_osc_base_framework.framework_output, + "raccumulate_notify: 0x%lx, %zu, %s, %d, %d, %zu, %s, %s, %d, 0x%lx", + (unsigned long) origin_addr, origin_count, + origin_dt->name, target, (int) target_disp, + target_count, target_dt->name, + op->o_name, notify, + (unsigned long) win)); + + ret = osc_sm_check_notify_idx(module, target, notify); + if (OMPI_SUCCESS != ret) { + return ret; + } + + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; + + opal_atomic_lock(&module->node_states[target].accumulate_lock); + if (op == &ompi_mpi_op_replace.op) { + ret = ompi_datatype_sndrcv((void *)origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt); + } else { + ret = ompi_osc_base_sndrcv_op(origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt, + op); + } + opal_atomic_unlock(&module->node_states[target].accumulate_lock); + + /* Only notify once the accumulate actually happened -- a counter bumped for + * an operation that failed would tell the target that data it never + * received is ready. */ + if (OMPI_SUCCESS != ret) { + return ret; + } + + osc_sm_notify_accumulate_done(module, target, notify); + + /* the only valid field of RMA request status is the MPI_ERROR field. + * ompi_request_empty has status MPI_SUCCESS and indicates the request is + * complete. */ + *ompi_req = &ompi_request_empty; + + return ret; +} + int ompi_osc_sm_rget_accumulate(const void *origin_addr, @@ -476,6 +762,78 @@ ompi_osc_sm_rget_accumulate(const void *origin_addr, } +int +ompi_osc_sm_rget_accumulate_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + void *result_addr, + size_t result_count, + struct ompi_datatype_t *result_dt, + int target, + MPI_Aint target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win, + struct ompi_request_t **ompi_req) +{ + int ret; + ompi_osc_sm_module_t *module = + (ompi_osc_sm_module_t*) win->w_osc_module; + void *remote_address; + + OPAL_OUTPUT_VERBOSE((50, ompi_osc_base_framework.framework_output, + "rget_accumulate_notify: 0x%lx, %zu, %s, %d, %d, %zu, %s, %s, %d, 0x%lx", + (unsigned long) origin_addr, origin_count, + origin_dt->name, target, (int) target_disp, + target_count, target_dt->name, + op->o_name, notify, + (unsigned long) win)); + + ret = osc_sm_check_notify_idx(module, target, notify); + if (OMPI_SUCCESS != ret) { + return ret; + } + + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; + + opal_atomic_lock(&module->node_states[target].accumulate_lock); + + ret = ompi_datatype_sndrcv(remote_address, target_count, target_dt, + result_addr, result_count, result_dt); + if (OMPI_SUCCESS != ret || op == &ompi_mpi_op_no_op.op) goto done; + + if (op == &ompi_mpi_op_replace.op) { + ret = ompi_datatype_sndrcv((void *)origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt); + } else { + ret = ompi_osc_base_sndrcv_op(origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt, + op); + } + + done: + opal_atomic_unlock(&module->node_states[target].accumulate_lock); + + /* Only notify once the operation actually happened. MPI_NO_OP is not a + * failure: the target window was still read into the result buffer, which is + * an access the notification is required to cover. */ + if (OMPI_SUCCESS != ret) { + return ret; + } + + osc_sm_notify_accumulate_done(module, target, notify); + + /* the only valid field of RMA request status is the MPI_ERROR field. + * ompi_request_empty has status MPI_SUCCESS and indicates the request is + * complete. */ + *ompi_req = &ompi_request_empty; + + return ret; +} + + int ompi_osc_sm_put(const void *origin_addr, size_t origin_count, @@ -670,6 +1028,62 @@ ompi_osc_sm_accumulate(const void *origin_addr, } +int +ompi_osc_sm_accumulate_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + int target, + ptrdiff_t target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win) +{ + int ret; + ompi_osc_sm_module_t *module = + (ompi_osc_sm_module_t*) win->w_osc_module; + void *remote_address; + + OPAL_OUTPUT_VERBOSE((50, ompi_osc_base_framework.framework_output, + "accumulate_notify: 0x%lx, %zu, %s, %d, %d, %zu, %s, %s, %d, 0x%lx", + (unsigned long) origin_addr, origin_count, + origin_dt->name, target, (int) target_disp, + target_count, target_dt->name, + op->o_name, notify, + (unsigned long) win)); + + ret = osc_sm_check_notify_idx(module, target, notify); + if (OMPI_SUCCESS != ret) { + return ret; + } + + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; + + opal_atomic_lock(&module->node_states[target].accumulate_lock); + if (op == &ompi_mpi_op_replace.op) { + ret = ompi_datatype_sndrcv((void *)origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt); + } else { + ret = ompi_osc_base_sndrcv_op(origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt, + op); + } + opal_atomic_unlock(&module->node_states[target].accumulate_lock); + + /* Only notify once the accumulate actually happened -- a counter bumped for + * an operation that failed would tell the target that data it never + * received is ready. */ + if (OMPI_SUCCESS != ret) { + return ret; + } + + osc_sm_notify_accumulate_done(module, target, notify); + + return ret; +} + + int ompi_osc_sm_get_accumulate(const void *origin_addr, size_t origin_count, @@ -721,6 +1135,72 @@ ompi_osc_sm_get_accumulate(const void *origin_addr, } +int +ompi_osc_sm_get_accumulate_notify(const void *origin_addr, + size_t origin_count, + struct ompi_datatype_t *origin_dt, + void *result_addr, + size_t result_count, + struct ompi_datatype_t *result_dt, + int target, + MPI_Aint target_disp, + size_t target_count, + struct ompi_datatype_t *target_dt, + struct ompi_op_t *op, + int notify, + struct ompi_win_t *win) +{ + int ret; + ompi_osc_sm_module_t *module = + (ompi_osc_sm_module_t*) win->w_osc_module; + void *remote_address; + + OPAL_OUTPUT_VERBOSE((50, ompi_osc_base_framework.framework_output, + "get_accumulate_notify: 0x%lx, %zu, %s, %d, %d, %zu, %s, %s, %d, 0x%lx", + (unsigned long) origin_addr, origin_count, + origin_dt->name, target, (int) target_disp, + target_count, target_dt->name, + op->o_name, notify, + (unsigned long) win)); + + ret = osc_sm_check_notify_idx(module, target, notify); + if (OMPI_SUCCESS != ret) { + return ret; + } + + remote_address = ((char*) (module->bases[target])) + module->disp_units[target] * target_disp; + + opal_atomic_lock(&module->node_states[target].accumulate_lock); + + ret = ompi_datatype_sndrcv(remote_address, target_count, target_dt, + result_addr, result_count, result_dt); + if (OMPI_SUCCESS != ret || op == &ompi_mpi_op_no_op.op) goto done; + + if (op == &ompi_mpi_op_replace.op) { + ret = ompi_datatype_sndrcv((void *)origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt); + } else { + ret = ompi_osc_base_sndrcv_op(origin_addr, origin_count, origin_dt, + remote_address, target_count, target_dt, + op); + } + + done: + opal_atomic_unlock(&module->node_states[target].accumulate_lock); + + /* Only notify once the operation actually happened. MPI_NO_OP is not a + * failure: the target window was still read into the result buffer, which is + * an access the notification is required to cover. */ + if (OMPI_SUCCESS != ret) { + return ret; + } + + osc_sm_notify_accumulate_done(module, target, notify); + + return ret; +} + + int ompi_osc_sm_compare_and_swap(const void *origin_addr, const void *compare_addr, diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index 9af4530c77c..b315fed97d5 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -31,7 +31,9 @@ #include "ompi/request/request.h" #include "opal/util/sys_limits.h" #include "opal/align.h" +#include "opal/util/info.h" #include "opal/util/printf.h" +#include "opal/class/opal_cstring.h" #include "opal/mca/mpool/base/base.h" #include "osc_sm.h" @@ -87,16 +89,20 @@ ompi_osc_sm_module_t ompi_osc_sm_module_template = { .osc_win_set_num_notify = ompi_osc_sm_win_set_num_notify, .osc_win_get_num_notify = ompi_osc_sm_win_get_num_notify, .osc_accumulate = ompi_osc_sm_accumulate, + .osc_accumulate_notify = ompi_osc_sm_accumulate_notify, .osc_compare_and_swap = ompi_osc_sm_compare_and_swap, .osc_fetch_and_op = ompi_osc_sm_fetch_and_op, .osc_get_accumulate = ompi_osc_sm_get_accumulate, + .osc_get_accumulate_notify = ompi_osc_sm_get_accumulate_notify, .osc_rput = ompi_osc_sm_rput, .osc_rput_notify = ompi_osc_sm_rput_notify, .osc_rget = ompi_osc_sm_rget, .osc_rget_notify = ompi_osc_sm_rget_notify, .osc_raccumulate = ompi_osc_sm_raccumulate, + .osc_raccumulate_notify = ompi_osc_sm_raccumulate_notify, .osc_rget_accumulate = ompi_osc_sm_rget_accumulate, + .osc_rget_accumulate_notify = ompi_osc_sm_rget_accumulate_notify, .osc_fence = ompi_osc_sm_fence, @@ -146,9 +152,94 @@ static int component_register (void) &mca_osc_sm_component.priority); free(description_str); + mca_osc_sm_component.num_notify_counters = OSC_SM_DEFAULT_NOTIFY_COUNTERS; + opal_asprintf(&description_str, + "Number of RMA notification counters reserved per MPI process " + "in the shared memory segment of each window. Windows whose " + "info gives an mpi_assert_max_num_notify value use that " + "instead. MPI_Win_set_num_notify may exceed this value, at " + "the cost of allocating a new shared segment (default: %u)", + mca_osc_sm_component.num_notify_counters); + (void) mca_base_component_var_register(&mca_osc_sm_component.super.osc_version, + "num_notify_counters", description_str, + MCA_BASE_VAR_TYPE_UNSIGNED_INT, NULL, 0, 0, + OPAL_INFO_LVL_3, MCA_BASE_VAR_SCOPE_GROUP, + &mca_osc_sm_component.num_notify_counters); + free(description_str); + return OPAL_SUCCESS; } + +/* Read the mpi_assert_max_num_notify info key (MPI-5.1 section 12.2). + * + * A non-zero value is an assertion by the user that no call to + * MPI_WIN_SET_NUM_NOTIFY on this window will ask for more counters than this, + * which lets us reserve exactly that many and never reallocate. The key's + * default is 0, which the standard defines as "no limit is assumed" -- so it is + * not a request for zero counters, it means we pick, and we must stay able to + * grow on demand later. + * + * Returns the number of counters to reserve per MPI process; *assert_value is + * the raw key value (0 when absent), which the caller keeps to decide whether + * growth is permitted. */ +static int osc_sm_reserved_notify_counters(opal_info_t *info, unsigned int *assert_value, + unsigned int *reserved) +{ + opal_cstring_t *value_string; + int flag = 0, value = 0; + + *assert_value = 0; + *reserved = mca_osc_sm_component.num_notify_counters; + + if (NULL == info) { + return OMPI_SUCCESS; + } + + if (OMPI_SUCCESS != opal_info_get(info, "mpi_assert_max_num_notify", + &value_string, &flag) || !flag) { + return OMPI_SUCCESS; + } + + if (OPAL_SUCCESS != opal_cstring_to_int(value_string, &value)) { + OBJ_RELEASE(value_string); + return MPI_ERR_INFO; + } + OBJ_RELEASE(value_string); + + /* A negative value is a malformed key rather than "no assertion"; only 0 + * carries the "assume nothing" meaning. */ + if (value < 0) { + return MPI_ERR_INFO; + } + + if (0 != value) { + *assert_value = (unsigned int) value; + *reserved = (unsigned int) value; + } + + return OMPI_SUCCESS; +} + + +void +ompi_osc_sm_refresh_notify_bases(ompi_osc_sm_module_t *module) +{ + int comm_size = ompi_comm_size(module->comm); + char *base; + int i; + + /* Once the counters have been grown they live in their own segment; + * before that they sit inline in the main one. */ + base = (NULL != module->notify_segment_base) ? (char *) module->notify_segment_base + : (char *) module->segment_base; + + for (i = 0 ; i < comm_size ; ++i) { + module->notify_bases[i] = (opal_atomic_int64_t *) + (base + module->node_states[i].notify_counter_offset); + } +} + static int component_open(void) { @@ -209,6 +300,7 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis bool unlink_needed = false; int ret = OMPI_ERROR; size_t memory_alignment = OPAL_ALIGN_MIN; + unsigned int notify_assert = 0, notify_reserved = 0; assert(MPI_WIN_FLAVOR_SHARED == flavor || MPI_WIN_FLAVOR_ALLOCATE == flavor); @@ -239,6 +331,16 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis module->flavor = flavor; + /* How many notification counters to reserve per MPI process. Read before + * the segment is sized, since the reservation is part of its layout. */ + ret = osc_sm_reserved_notify_counters(info, ¬ify_assert, ¬ify_reserved); + if (OMPI_SUCCESS != ret) goto error; + module->notify_max_assert = notify_assert; + module->notify_segment_base = NULL; + + module->notify_bases = calloc(comm_size, sizeof(module->notify_bases[0])); + if (NULL == module->notify_bases) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; + /* create the segment */ if (1 == comm_size) { module->segment_base = NULL; @@ -260,17 +362,20 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis if (NULL == module->posts) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; module->posts[0] = (osc_sm_post_atomic_type_t *) (module->posts + 1); - /* allocate notify counters for single process case. + /* Notification counters for the single process case. There is no + * shared segment here, so they are a plain heap allocation owned by + * this module and reached through notify_bases[0]. * - * NOTE: osc/sm pre-attaches the full reserved capacity, whereas osc/ucx + * NOTE: osc/sm pre-attaches the reserved capacity, whereas osc/ucx * starts at zero and requires MPI_WIN_SET_NUM_NOTIFY before any counter * may be referenced. MPI-5.1 section 12.6.1 does not state what the * initial attached count is, so neither is provably wrong, but the * divergence means a program that omits MPI_WIN_SET_NUM_NOTIFY works * here and fails on ucx. Left as-is pending a decision. */ - module->notify_counters = calloc(OSC_SM_MAX_NOTIFY_COUNTERS, sizeof(int64_t)); - if (NULL == module->notify_counters) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; - module->node_states[0].notify_counter_count = OSC_SM_MAX_NOTIFY_COUNTERS; + module->notify_bases[0] = calloc(notify_reserved, sizeof(int64_t)); + if (NULL == module->notify_bases[0]) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; + module->node_states[0].notify_counter_capacity = notify_reserved; + module->node_states[0].notify_counter_count = notify_reserved; module->node_states[0].notify_counter_offset = 0; } else { unsigned long total, total_counters, gather_values[2], *rbuf; @@ -280,6 +385,7 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis size_t posts_size, post_size = (comm_size + OSC_SM_POST_MASK) / (OSC_SM_POST_MASK + 1); size_t notify_counters_size; size_t data_base_size; + opal_atomic_int64_t *notify_counters_base; opal_output_verbose(MCA_BASE_VERBOSE_DEBUG, ompi_osc_base_framework.framework_output, "allocating shared memory region of size %ld\n", (long) size); @@ -312,7 +418,7 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis } gather_values[0] = size; - gather_values[1] = OSC_SM_MAX_NOTIFY_COUNTERS; + gather_values[1] = notify_reserved; ret = module->comm->c_coll->coll_allgather(gather_values, 2, MPI_UNSIGNED_LONG, rbuf, 2, MPI_UNSIGNED_LONG, module->comm, @@ -401,19 +507,18 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis module->node_states = (ompi_osc_sm_node_state_t *) (module->global_state + 1); /* set up notify counters in shared memory after node_states */ - module->notify_counters = (opal_atomic_int64_t *) ((char *)(module->node_states + comm_size) + + notify_counters_base = (opal_atomic_int64_t *) ((char *)(module->node_states + comm_size) + OPAL_ALIGN_PAD_AMOUNT((uintptr_t)(module->node_states + comm_size), 64)); - /* zero out notify counters */ - memset((void *) module->notify_counters, 0, total_counters * sizeof(int64_t)); for (i = 0, total = data_base_size, total_counters = 0 ; i < comm_size ; ++i) { if (i > 0) { module->posts[i] = module->posts[i - 1] + post_size; } + module->node_states[i].notify_counter_capacity = (uint32_t) rbuf[2 * i + 1]; module->node_states[i].notify_counter_count = (uint32_t) rbuf[2 * i + 1]; module->node_states[i].notify_counter_offset = - (uint64_t) ((char *) (module->notify_counters + total_counters) - + (uint64_t) ((char *) (notify_counters_base + total_counters) - (char *) module->segment_base); total_counters += rbuf[2 * i + 1]; @@ -429,6 +534,16 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis } } + ompi_osc_sm_refresh_notify_bases(module); + + /* Zero only this process's own counters. A freshly created segment + * already reads as zero, but do not depend on the backing store for + * that; zeroing just our own slice keeps the cost proportional to what + * we reserved instead of touching -- and so committing -- every page of + * every rank's region. */ + memset((void *) module->notify_bases[ompi_comm_rank(module->comm)], 0, + notify_reserved * sizeof(int64_t)); + free(rbuf); } @@ -590,8 +705,15 @@ ompi_osc_sm_free(struct ompi_win_t *win) module->comm->c_coll->coll_barrier(module->comm, module->comm->c_coll->coll_barrier_module); + /* The counters live either inline in the main segment or, once + * MPI_WIN_SET_NUM_NOTIFY grew them, in an overflow segment of their + * own. Either way they are shared memory, so there is nothing to + * free -- only the overflow mapping to drop. */ + if (NULL != module->notify_segment_base) { + opal_shmem_segment_detach (&module->notify_seg_ds); + } + opal_shmem_segment_detach (&module->seg_ds); - /* notify_counters points into shared memory segment, no separate free needed */ } else { free(module->node_states); free(module->global_state); @@ -599,11 +721,14 @@ ompi_osc_sm_free(struct ompi_win_t *win) mca_mpool_base_default_module->mpool_free(mca_mpool_base_default_module, module->bases[0]); } - /* free notify_counters for single process case */ + /* free the counters for the single process case */ /* cast away the atomic/volatile qualifier for free(), as in * opal/runtime/opal_progress.c */ - free((void *) module->notify_counters); + if (NULL != module->notify_bases) { + free((void *) module->notify_bases[0]); + } } + free(module->notify_bases); free(module->disp_units); free(module->outstanding_locks); free(module->sizes); @@ -650,6 +775,16 @@ ompi_osc_sm_get_info(struct ompi_win_t *win, struct opal_info_t **info_used) (module->noncontig) ? "true" : "false"); } + /* Report the assertion back only when one was actually given. Its default + * is 0, meaning "no limit is assumed", and osc/sm honours that by growing on + * demand rather than by adopting any particular bound -- so there is no + * value to report in that case. */ + if (0 != module->notify_max_assert) { + char value_str[16]; + snprintf(value_str, sizeof(value_str), "%u", module->notify_max_assert); + opal_info_set(info, "mpi_assert_max_num_notify", value_str); + } + *info_used = info; return OMPI_SUCCESS; diff --git a/ompi/mpi/c/Makefile.am b/ompi/mpi/c/Makefile.am index 50a16c9d134..e4b6367045f 100644 --- a/ompi/mpi/c/Makefile.am +++ b/ompi/mpi/c/Makefile.am @@ -56,6 +56,7 @@ headers = bindings.h prototype_sources = \ abort.c.in \ accumulate.c.in \ + accumulate_notify.c.in \ add_error_class.c.in \ add_error_code.c.in \ add_error_string.c.in \ @@ -221,6 +222,7 @@ prototype_sources = \ gatherv.c.in \ gatherv_init.c.in \ get_accumulate.c.in \ + get_accumulate_notify.c.in \ get_address.c.in \ get.c.in \ get_notify.c.in \ @@ -345,6 +347,7 @@ prototype_sources = \ put_notify.c.in \ query_thread.c.in \ raccumulate.c.in \ + raccumulate_notify.c.in \ recv.c.in \ recv_init.c.in \ reduce.c.in \ @@ -366,8 +369,11 @@ prototype_sources = \ request_get_status_any.c.in \ request_get_status_some.c.in \ rget_accumulate.c.in \ + rget_accumulate_notify.c.in \ rget.c.in \ + rget_notify.c.in \ rput.c.in \ + rput_notify.c.in \ rsend.c.in \ rsend_init.c.in \ scan.c.in \ @@ -532,6 +538,7 @@ endif interface_profile_sources = \ abort_generated.c \ accumulate_generated.c \ + accumulate_notify_generated.c \ add_error_class_generated.c \ add_error_code_generated.c \ add_error_string_generated.c \ @@ -697,6 +704,7 @@ interface_profile_sources = \ gatherv_generated.c \ gatherv_init_generated.c \ get_accumulate_generated.c \ + get_accumulate_notify_generated.c \ get_address_generated.c \ get_generated.c \ get_count_generated.c \ @@ -821,6 +829,7 @@ interface_profile_sources = \ put_notify_generated.c \ query_thread_generated.c \ raccumulate_generated.c \ + raccumulate_notify_generated.c \ recv_generated.c \ recv_init_generated.c \ reduce_generated.c \ @@ -842,8 +851,11 @@ interface_profile_sources = \ request_get_status_any_generated.c \ request_get_status_some_generated.c \ rget_accumulate_generated.c \ + rget_accumulate_notify_generated.c \ rget_generated.c \ + rget_notify_generated.c \ rput_generated.c \ + rput_notify_generated.c \ rsend_generated.c \ rsend_init_generated.c \ scan_generated.c \ diff --git a/ompi/mpi/c/accumulate_notify.c.in b/ompi/mpi/c/accumulate_notify.c.in new file mode 100644 index 00000000000..395dd3cad24 --- /dev/null +++ b/ompi/mpi/c/accumulate_notify.c.in @@ -0,0 +1,141 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2004-2020 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + * Copyright (c) 2004-2008 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * Copyright (c) 2004-2005 The Regents of the University of California. + * All rights reserved. + * Copyright (c) 2009 Sun Microsystmes, Inc. All rights reserved. + * Copyright (c) 2013-2015 Los Alamos National Security, LLC. All rights + * reserved. + * Copyright (c) 2015 Research Organization for Information Science + * and Technology (RIST). All rights reserved. + * Copyright (c) 2024 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "ompi_config.h" +#include +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/communicator/communicator.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" +#include "ompi/op/op.h" +#include "ompi/datatype/ompi_datatype.h" +#include "ompi/datatype/ompi_datatype_internal.h" +#include "ompi/memchecker.h" + +PROTOTYPE ERROR_CLASS accumulate_notify(BUFFER origin_addr, COUNT origin_count, DATATYPE origin_datatype, + INT target_rank, AINT target_disp, COUNT target_count, + DATATYPE target_datatype, OP op, INT notification_idx, + WIN win) +{ + int rc; + ompi_win_t *ompi_win = (ompi_win_t*) win; + + MEMCHECKER( + memchecker_datatype(origin_datatype); + memchecker_datatype(target_datatype); + memchecker_call(&opal_memchecker_base_isdefined, (void *) origin_addr, origin_count, origin_datatype); + ); + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (origin_count < 0 || target_count < 0) { + rc = MPI_ERR_COUNT; + } else if (ompi_win_peer_invalid(win, target_rank) && + (MPI_PROC_NULL != target_rank)) { + rc = MPI_ERR_RANK; + } else if (MPI_OP_NULL == op || MPI_NO_OP == op) { + rc = MPI_ERR_OP; + } else if (!ompi_op_is_intrinsic(op)) { + rc = MPI_ERR_OP; + } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) { + rc = MPI_ERR_DISP; + } else if (notification_idx < 0) { + /* The upper bound depends on how many counters the *target* has + attached, which only the osc module can see, so the range check + proper happens there. */ + rc = MPI_ERR_RMA_NOTIFICATION; + } else { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count); + if (OMPI_SUCCESS == rc) { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, target_datatype, target_count); + } + if (OMPI_SUCCESS == rc) { + /* While technically the standard probably requires that the + datatypes used with MPI_REPLACE conform to all the rules + for other reduction operators, we don't require such + behavior, as checking for it is expensive here and we don't + care in implementation.. */ + if (op != &ompi_mpi_op_replace.op && op != &ompi_mpi_op_no_op.op) { + ompi_datatype_t *op_check_dt, *origin_check_dt; + char *msg; + + /* ACCUMULATE, unlike REDUCE, can use with derived + datatypes with predefinied operations, with some + restrictions outlined in MPI-3:11.3.4. The derived + datatype must be composed entirely from one predefined + datatype (so you can do all the construction you want, + but at the bottom, you can only use one datatype, say, + MPI_INT). If the datatype at the target isn't + predefined, then make sure it's composed of only one + datatype, and check that datatype against + ompi_op_is_valid(). */ + origin_check_dt = ompi_datatype_get_single_predefined_type_from_args(origin_datatype); + op_check_dt = ompi_datatype_get_single_predefined_type_from_args(target_datatype); + + if( !((origin_check_dt == op_check_dt) & (NULL != op_check_dt)) ) { + OMPI_ERRHANDLER_RETURN(MPI_ERR_ARG, win, MPI_ERR_ARG, FUNC_NAME); + } + + /* check to make sure primitive type is valid for + reduction. Should do this on the target, but + then can't get the errcode back for this + call */ + if (!ompi_op_is_valid(op, op_check_dt, &msg, FUNC_NAME)) { + int ret = OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_OP, msg); + free(msg); + return ret; + } + } + } + } + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + if (NULL == win->w_osc_module->osc_accumulate_notify) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + + if (MPI_PROC_NULL == target_rank) { + return MPI_SUCCESS; + } + + rc = ompi_win->w_osc_module->osc_accumulate_notify(origin_addr, + origin_count, + origin_datatype, + target_rank, + target_disp, + target_count, + target_datatype, + op, notification_idx, win); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} diff --git a/ompi/mpi/c/get_accumulate_notify.c.in b/ompi/mpi/c/get_accumulate_notify.c.in new file mode 100644 index 00000000000..2c16e79299c --- /dev/null +++ b/ompi/mpi/c/get_accumulate_notify.c.in @@ -0,0 +1,150 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2004-2020 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + * Copyright (c) 2004-2008 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * Copyright (c) 2004-2005 The Regents of the University of California. + * All rights reserved. + * Copyright (c) 2009 Sun Microsystmes, Inc. All rights reserved. + * Copyright (c) 2013-2015 Los Alamos National Security, LLC. All rights + * reserved. + * Copyright (c) 2015 Research Organization for Information Science + * and Technology (RIST). All rights reserved. + * Copyright (c) 2024 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "ompi_config.h" +#include +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/communicator/communicator.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" +#include "ompi/op/op.h" +#include "ompi/datatype/ompi_datatype.h" +#include "ompi/datatype/ompi_datatype_internal.h" +#include "ompi/memchecker.h" + +PROTOTYPE ERROR_CLASS get_accumulate_notify(BUFFER origin_addr, COUNT origin_count, DATATYPE origin_datatype, + BUFFER_OUT result_addr, COUNT result_count, DATATYPE result_datatype, + INT target_rank, AINT target_disp, COUNT target_count, + DATATYPE target_datatype, OP op, INT notification_idx, + WIN win) +{ + int rc; + ompi_win_t *ompi_win = (ompi_win_t*) win; + + MEMCHECKER( + memchecker_datatype(origin_datatype); + memchecker_datatype(target_datatype); + memchecker_call(&opal_memchecker_base_isdefined, (void *) origin_addr, origin_count, origin_datatype); + ); + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (origin_count < 0 || target_count < 0) { + rc = MPI_ERR_COUNT; + } else if (ompi_win_peer_invalid(win, target_rank) && + (MPI_PROC_NULL != target_rank)) { + rc = MPI_ERR_RANK; + } else if (MPI_OP_NULL == op) { + rc = MPI_ERR_OP; + } else if (!ompi_op_is_intrinsic(op)) { + rc = MPI_ERR_OP; + } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) { + rc = MPI_ERR_DISP; + } else if (notification_idx < 0) { + /* The upper bound depends on how many counters the *target* has + attached, which only the osc module can see, so the range check + proper happens there. */ + rc = MPI_ERR_RMA_NOTIFICATION; + } else { + /* the origin datatype is meaningless when using MPI_OP_NO_OP */ + if (&ompi_mpi_op_no_op.op != op) { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count); + } else { + rc = OMPI_SUCCESS; + } + if (OMPI_SUCCESS == rc) { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, target_datatype, target_count); + } + if (OMPI_SUCCESS == rc) { + /* While technically the standard probably requires that the + datatypes used with MPI_REPLACE conform to all the rules + for other reduction operators, we don't require such + behavior, as checking for it is expensive here and we don't + care in implementation.. */ + if (op != &ompi_mpi_op_replace.op && op != &ompi_mpi_op_no_op.op) { + ompi_datatype_t *op_check_dt, *origin_check_dt; + char *msg; + + /* GET_ACCUMULATE, unlike REDUCE, can use with derived + datatypes with predefinied operations, with some + restrictions outlined in MPI-3:11.3.4. The derived + datatype must be composed entirely from one predefined + datatype (so you can do all the construction you want, + but at the bottom, you can only use one datatype, say, + MPI_INT). If the datatype at the target isn't + predefined, then make sure it's composed of only one + datatype, and check that datatype against + ompi_op_is_valid(). */ + origin_check_dt = ompi_datatype_get_single_predefined_type_from_args(origin_datatype); + op_check_dt = ompi_datatype_get_single_predefined_type_from_args(target_datatype); + + if( !((origin_check_dt == op_check_dt) & (NULL != op_check_dt)) ) { + OMPI_ERRHANDLER_RETURN(MPI_ERR_ARG, win, MPI_ERR_ARG, FUNC_NAME); + } + + /* check to make sure primitive type is valid for + reduction. Should do this on the target, but + then can't get the errcode back for this + call */ + if (!ompi_op_is_valid(op, op_check_dt, &msg, FUNC_NAME)) { + int ret = OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_OP, msg); + free(msg); + return ret; + } + } + } + } + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + if (NULL == win->w_osc_module->osc_get_accumulate_notify) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + + if (MPI_PROC_NULL == target_rank) { + return MPI_SUCCESS; + } + + rc = ompi_win->w_osc_module->osc_get_accumulate_notify(origin_addr, + origin_count, + origin_datatype, + result_addr, + result_count, + result_datatype, + target_rank, + target_disp, + target_count, + target_datatype, + op, notification_idx, win); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} diff --git a/ompi/mpi/c/get_notify.c.in b/ompi/mpi/c/get_notify.c.in index d9b8f5b68ef..6191eceaac2 100644 --- a/ompi/mpi/c/get_notify.c.in +++ b/ompi/mpi/c/get_notify.c.in @@ -68,6 +68,10 @@ PROTOTYPE ERROR_CLASS get_notify(BUFFER_OUT origin_addr, COUNT origin_count, OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); } + if (NULL == win->w_osc_module->osc_get_notify) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + if (MPI_PROC_NULL == target_rank) return MPI_SUCCESS; rc = win->w_osc_module->osc_get_notify(origin_addr, origin_count, origin_datatype, diff --git a/ompi/mpi/c/put_notify.c.in b/ompi/mpi/c/put_notify.c.in index f278e16cb16..0141725c322 100644 --- a/ompi/mpi/c/put_notify.c.in +++ b/ompi/mpi/c/put_notify.c.in @@ -71,6 +71,10 @@ PROTOTYPE ERROR_CLASS put_notify(BUFFER origin_addr, COUNT origin_count, DATATYP OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); } + if (NULL == win->w_osc_module->osc_put_notify) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + if (MPI_PROC_NULL == target_rank) return MPI_SUCCESS; rc = win->w_osc_module->osc_put_notify(origin_addr, origin_count, origin_datatype, diff --git a/ompi/mpi/c/raccumulate_notify.c.in b/ompi/mpi/c/raccumulate_notify.c.in new file mode 100644 index 00000000000..c9df87b74bc --- /dev/null +++ b/ompi/mpi/c/raccumulate_notify.c.in @@ -0,0 +1,143 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2004-2020 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + * Copyright (c) 2004-2008 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * Copyright (c) 2004-2005 The Regents of the University of California. + * All rights reserved. + * Copyright (c) 2009 Sun Microsystmes, Inc. All rights reserved. + * Copyright (c) 2011 Sandia National Laboratories. All rights reserved. + * Copyright (c) 2014-2015 Los Alamos National Security, LLC. All rights + * reserved. + * Copyright (c) 2015 Research Organization for Information Science + * and Technology (RIST). All rights reserved. + * Copyright (c) 2024 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" +#include +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/communicator/communicator.h" +#include "ompi/request/request.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" +#include "ompi/op/op.h" +#include "ompi/datatype/ompi_datatype.h" +#include "ompi/datatype/ompi_datatype_internal.h" +#include "ompi/memchecker.h" + +PROTOTYPE ERROR_CLASS raccumulate_notify(BUFFER origin_addr, COUNT origin_count, DATATYPE origin_datatype, + INT target_rank, AINT target_disp, COUNT target_count, + DATATYPE target_datatype, OP op, INT notification_idx, + WIN win, REQUEST_INOUT request) +{ + int rc; + ompi_win_t *ompi_win = (ompi_win_t*) win; + + MEMCHECKER( + memchecker_datatype(origin_datatype); + memchecker_datatype(target_datatype); + memchecker_call(&opal_memchecker_base_isdefined, (void *) origin_addr, origin_count, origin_datatype); + ); + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (origin_count < 0 || target_count < 0) { + rc = MPI_ERR_COUNT; + } else if (ompi_win_peer_invalid(win, target_rank) && + (MPI_PROC_NULL != target_rank)) { + rc = MPI_ERR_RANK; + } else if (MPI_OP_NULL == op || MPI_NO_OP == op) { + rc = MPI_ERR_OP; + } else if (!ompi_op_is_intrinsic(op)) { + rc = MPI_ERR_OP; + } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) { + rc = MPI_ERR_DISP; + } else if (notification_idx < 0) { + /* The upper bound depends on how many counters the *target* has + attached, which only the osc module can see, so the range check + proper happens there. */ + rc = MPI_ERR_RMA_NOTIFICATION; + } else { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count); + if (OMPI_SUCCESS == rc) { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, target_datatype, target_count); + } + if (OMPI_SUCCESS == rc) { + /* While technically the standard probably requires that the + datatypes used with MPI_REPLACE conform to all the rules + for other reduction operators, we don't require such + behavior, as checking for it is expensive here and we don't + care in implementation.. */ + if (op != &ompi_mpi_op_replace.op && op != &ompi_mpi_op_no_op.op) { + ompi_datatype_t *op_check_dt, *origin_check_dt; + char *msg; + + /* ACCUMULATE, unlike REDUCE, can use with derived + datatypes with predefinied operations, with some + restrictions outlined in MPI-3:11.3.4. The derived + datatype must be composed entirely from one predefined + datatype (so you can do all the construction you want, + but at the bottom, you can only use one datatype, say, + MPI_INT). If the datatype at the target isn't + predefined, then make sure it's composed of only one + datatype, and check that datatype against + ompi_op_is_valid(). */ + origin_check_dt = ompi_datatype_get_single_predefined_type_from_args(origin_datatype); + op_check_dt = ompi_datatype_get_single_predefined_type_from_args(target_datatype); + + if( !((origin_check_dt == op_check_dt) & (NULL != op_check_dt)) ) { + OMPI_ERRHANDLER_RETURN(MPI_ERR_ARG, win, MPI_ERR_ARG, FUNC_NAME); + } + + /* check to make sure primitive type is valid for + reduction. Should do this on the target, but + then can't get the errcode back for this + call */ + if (!ompi_op_is_valid(op, op_check_dt, &msg, FUNC_NAME)) { + int ret = OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_OP, msg); + free(msg); + return ret; + } + } + } + } + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + if (NULL == win->w_osc_module->osc_raccumulate_notify) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + + if (MPI_PROC_NULL == target_rank) { + *request = &ompi_request_empty; + return MPI_SUCCESS; + } + + rc = ompi_win->w_osc_module->osc_raccumulate_notify(origin_addr, + origin_count, + origin_datatype, + target_rank, + target_disp, + target_count, + target_datatype, + op, notification_idx, win, request); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} diff --git a/ompi/mpi/c/rget_accumulate_notify.c.in b/ompi/mpi/c/rget_accumulate_notify.c.in new file mode 100644 index 00000000000..f3466f5fb0b --- /dev/null +++ b/ompi/mpi/c/rget_accumulate_notify.c.in @@ -0,0 +1,152 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2004-2020 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + * Copyright (c) 2004-2008 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * Copyright (c) 2004-2005 The Regents of the University of California. + * All rights reserved. + * Copyright (c) 2009 Sun Microsystmes, Inc. All rights reserved. + * Copyright (c) 2011 Sandia National Laboratories. All rights reserved. + * Copyright (c) 2014-2015 Los Alamos National Security, LLC. All rights + * reserved. + * Copyright (c) 2015 Research Organization for Information Science + * and Technology (RIST). All rights reserved. + * Copyright (c) 2024 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" +#include +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/communicator/communicator.h" +#include "ompi/request/request.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" +#include "ompi/op/op.h" +#include "ompi/datatype/ompi_datatype.h" +#include "ompi/datatype/ompi_datatype_internal.h" +#include "ompi/memchecker.h" + +PROTOTYPE ERROR_CLASS rget_accumulate_notify(BUFFER origin_addr, COUNT origin_count, DATATYPE origin_datatype, + BUFFER_OUT result_addr, COUNT result_count, DATATYPE result_datatype, + INT target_rank, AINT target_disp, COUNT target_count, + DATATYPE target_datatype, OP op, INT notification_idx, + WIN win, REQUEST_INOUT request) +{ + int rc; + ompi_win_t *ompi_win = (ompi_win_t*) win; + + MEMCHECKER( + memchecker_datatype(origin_datatype); + memchecker_datatype(target_datatype); + memchecker_call(&opal_memchecker_base_isdefined, (void *) origin_addr, origin_count, origin_datatype); + ); + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (origin_count < 0 || target_count < 0) { + rc = MPI_ERR_COUNT; + } else if (ompi_win_peer_invalid(win, target_rank) && + (MPI_PROC_NULL != target_rank)) { + rc = MPI_ERR_RANK; + } else if (MPI_OP_NULL == op) { + rc = MPI_ERR_OP; + } else if (!ompi_op_is_intrinsic(op)) { + rc = MPI_ERR_OP; + } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) { + rc = MPI_ERR_DISP; + } else if (notification_idx < 0) { + /* The upper bound depends on how many counters the *target* has + attached, which only the osc module can see, so the range check + proper happens there. */ + rc = MPI_ERR_RMA_NOTIFICATION; + } else { + /* the origin datatype is meaningless when using MPI_OP_NO_OP */ + if (&ompi_mpi_op_no_op.op != op) { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count); + } else { + rc = OMPI_SUCCESS; + } + if (OMPI_SUCCESS == rc) { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, target_datatype, target_count); + } + if (OMPI_SUCCESS == rc) { + /* While technically the standard probably requires that the + datatypes used with MPI_REPLACE conform to all the rules + for other reduction operators, we don't require such + behavior, as checking for it is expensive here and we don't + care in implementation.. */ + if (op != &ompi_mpi_op_replace.op && op != &ompi_mpi_op_no_op.op) { + ompi_datatype_t *op_check_dt, *origin_check_dt; + char *msg; + + /* GET_ACCUMULATE, unlike REDUCE, can use with derived + datatypes with predefinied operations, with some + restrictions outlined in MPI-3:11.3.4. The derived + datatype must be composed entirely from one predefined + datatype (so you can do all the construction you want, + but at the bottom, you can only use one datatype, say, + MPI_INT). If the datatype at the target isn't + predefined, then make sure it's composed of only one + datatype, and check that datatype against + ompi_op_is_valid(). */ + origin_check_dt = ompi_datatype_get_single_predefined_type_from_args(origin_datatype); + op_check_dt = ompi_datatype_get_single_predefined_type_from_args(target_datatype); + + if( !((origin_check_dt == op_check_dt) & (NULL != op_check_dt)) ) { + OMPI_ERRHANDLER_RETURN(MPI_ERR_ARG, win, MPI_ERR_ARG, FUNC_NAME); + } + + /* check to make sure primitive type is valid for + reduction. Should do this on the target, but + then can't get the errcode back for this + call */ + if (!ompi_op_is_valid(op, op_check_dt, &msg, FUNC_NAME)) { + int ret = OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_OP, msg); + free(msg); + return ret; + } + } + } + } + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + if (NULL == win->w_osc_module->osc_rget_accumulate_notify) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + + if (MPI_PROC_NULL == target_rank) { + *request = &ompi_request_empty; + return MPI_SUCCESS; + } + + rc = ompi_win->w_osc_module->osc_rget_accumulate_notify(origin_addr, + origin_count, + origin_datatype, + result_addr, + result_count, + result_datatype, + target_rank, + target_disp, + target_count, + target_datatype, + op, notification_idx, win, request); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} diff --git a/ompi/mpi/c/rget_notify.c.in b/ompi/mpi/c/rget_notify.c.in new file mode 100644 index 00000000000..1241a84128a --- /dev/null +++ b/ompi/mpi/c/rget_notify.c.in @@ -0,0 +1,93 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2004-2020 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + * Copyright (c) 2004-2008 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * Copyright (c) 2004-2005 The Regents of the University of California. + * All rights reserved. + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2013-2015 Los Alamos National Security, LLC. All rights + * reserved. + * Copyright (c) 2015 Research Organization for Information Science + * and Technology (RIST). All rights reserved. + * Copyright (c) 2024 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" +#include + +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/communicator/communicator.h" +#include "ompi/request/request.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" +#include "ompi/datatype/ompi_datatype.h" +#include "ompi/runtime/ompi_spc.h" + +PROTOTYPE ERROR_CLASS rget_notify(BUFFER_OUT origin_addr, COUNT origin_count, DATATYPE origin_datatype, + INT target_rank, AINT target_disp, COUNT target_count, + DATATYPE target_datatype, INT notification_idx, WIN win, + REQUEST_INOUT request) +{ + int rc; + + SPC_RECORD(OMPI_SPC_RGET_NOTIFY, 1); + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (origin_count < 0 || target_count < 0) { + rc = MPI_ERR_COUNT; + } else if (ompi_win_peer_invalid(win, target_rank) && + (MPI_PROC_NULL != target_rank)) { + rc = MPI_ERR_RANK; + } else if (NULL == target_datatype || + MPI_DATATYPE_NULL == target_datatype) { + rc = MPI_ERR_TYPE; + } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) { + rc = MPI_ERR_DISP; + } else if (notification_idx < 0) { + /* The upper bound depends on how many counters the *target* has + attached, which only the osc module can see, so the range check + proper happens there. */ + rc = MPI_ERR_RMA_NOTIFICATION; + } else { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count); + if (OMPI_SUCCESS == rc) { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, target_datatype, target_count); + } + } + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + if (NULL == win->w_osc_module->osc_rget_notify) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + + if (MPI_PROC_NULL == target_rank) { + *request = &ompi_request_empty; + return MPI_SUCCESS; + } + + rc = win->w_osc_module->osc_rget_notify(origin_addr, origin_count, origin_datatype, + target_rank, target_disp, target_count, + target_datatype, notification_idx, win, + request); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} diff --git a/ompi/mpi/c/rput_notify.c.in b/ompi/mpi/c/rput_notify.c.in new file mode 100644 index 00000000000..621bfadb10b --- /dev/null +++ b/ompi/mpi/c/rput_notify.c.in @@ -0,0 +1,93 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2004-2020 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + * Copyright (c) 2004-2008 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * Copyright (c) 2004-2005 The Regents of the University of California. + * All rights reserved. + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2013-2015 Los Alamos National Security, LLC. All rights + * reserved. + * Copyright (c) 2015 Research Organization for Information Science + * and Technology (RIST). All rights reserved. + * Copyright (c) 2024 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#include "ompi_config.h" +#include + +#include "ompi/mpi/c/bindings.h" +#include "ompi/runtime/params.h" +#include "ompi/communicator/communicator.h" +#include "ompi/request/request.h" +#include "ompi/errhandler/errhandler.h" +#include "ompi/win/win.h" +#include "ompi/mca/osc/osc.h" +#include "ompi/datatype/ompi_datatype.h" +#include "ompi/runtime/ompi_spc.h" + +PROTOTYPE ERROR_CLASS rput_notify(BUFFER origin_addr, COUNT origin_count, DATATYPE origin_datatype, + INT target_rank, AINT target_disp, COUNT target_count, + DATATYPE target_datatype, INT notification_idx, WIN win, + REQUEST_INOUT request) +{ + int rc; + + SPC_RECORD(OMPI_SPC_RPUT_NOTIFY, 1); + + if (MPI_PARAM_CHECK) { + rc = OMPI_SUCCESS; + + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + if (ompi_win_invalid(win)) { + return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (origin_count < 0 || target_count < 0) { + rc = MPI_ERR_COUNT; + } else if (ompi_win_peer_invalid(win, target_rank) && + (MPI_PROC_NULL != target_rank)) { + rc = MPI_ERR_RANK; + } else if (NULL == target_datatype || + MPI_DATATYPE_NULL == target_datatype) { + rc = MPI_ERR_TYPE; + } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) { + rc = MPI_ERR_DISP; + } else if (notification_idx < 0) { + /* The upper bound depends on how many counters the *target* has + attached, which only the osc module can see, so the range check + proper happens there. */ + rc = MPI_ERR_RMA_NOTIFICATION; + } else { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count); + if (OMPI_SUCCESS == rc) { + OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, target_datatype, target_count); + } + } + OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); + } + + if (NULL == win->w_osc_module->osc_rput_notify) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + + if (MPI_PROC_NULL == target_rank) { + *request = &ompi_request_empty; + return MPI_SUCCESS; + } + + rc = win->w_osc_module->osc_rput_notify(origin_addr, origin_count, origin_datatype, + target_rank, target_disp, target_count, + target_datatype, notification_idx, win, + request); + OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); +} diff --git a/ompi/mpi/c/win_get_notify_value.c.in b/ompi/mpi/c/win_get_notify_value.c.in index 27df94e1e82..4dfcafbab05 100644 --- a/ompi/mpi/c/win_get_notify_value.c.in +++ b/ompi/mpi/c/win_get_notify_value.c.in @@ -36,6 +36,10 @@ PROTOTYPE ERROR_CLASS win_get_notify_value(WIN win, INT notification_idx, ELEMEN OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); } + if (NULL == win->w_osc_module->osc_win_get_notify_value) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + rc = win->w_osc_module->osc_win_get_notify_value(win, notification_idx, value); OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); } diff --git a/ompi/mpi/c/win_reset_notify_value.c.in b/ompi/mpi/c/win_reset_notify_value.c.in index 68b462a510e..09a132555f5 100644 --- a/ompi/mpi/c/win_reset_notify_value.c.in +++ b/ompi/mpi/c/win_reset_notify_value.c.in @@ -36,6 +36,10 @@ PROTOTYPE ERROR_CLASS win_reset_notify_value(WIN win, INT notification_idx, ELEM OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME); } + if (NULL == win->w_osc_module->osc_win_reset_notify_value) { + return OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_UNSUPPORTED_OPERATION, FUNC_NAME); + } + rc = win->w_osc_module->osc_win_reset_notify_value(win, notification_idx, value); OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME); } diff --git a/ompi/runtime/ompi_spc.c b/ompi/runtime/ompi_spc.c index e7653e27c39..5e6a3dbb339 100644 --- a/ompi/runtime/ompi_spc.c +++ b/ompi/runtime/ompi_spc.c @@ -73,9 +73,11 @@ static const ompi_spc_event_t ompi_spc_events_desc[OMPI_SPC_NUM_COUNTERS] = { SET_COUNTER_ARRAY(OMPI_SPC_PUT, "The number of times MPI_Put was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_PUT_NOTIFY, "The number of times MPI_Put_notify was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_RPUT, "The number of times MPI_Rput was called.", false, false), + SET_COUNTER_ARRAY(OMPI_SPC_RPUT_NOTIFY, "The number of times MPI_Rput_notify was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_GET, "The number of times MPI_Get was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_GET_NOTIFY, "The number of times MPI_Get_notify was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_RGET, "The number of times MPI_Rget was called.", false, false), + SET_COUNTER_ARRAY(OMPI_SPC_RGET_NOTIFY, "The number of times MPI_Rget_notify was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_PROBE, "The number of times MPI_Probe was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_IPROBE, "The number of times MPI_Iprobe was called.", false, false), SET_COUNTER_ARRAY(OMPI_SPC_BCAST, "The number of times MPI_Bcast was called.", false, false), diff --git a/ompi/runtime/ompi_spc.h b/ompi/runtime/ompi_spc.h index 03f58dd2504..5aebb282de8 100644 --- a/ompi/runtime/ompi_spc.h +++ b/ompi/runtime/ompi_spc.h @@ -60,9 +60,11 @@ typedef enum ompi_spc_counters { OMPI_SPC_PUT, OMPI_SPC_PUT_NOTIFY, OMPI_SPC_RPUT, + OMPI_SPC_RPUT_NOTIFY, OMPI_SPC_GET, OMPI_SPC_GET_NOTIFY, OMPI_SPC_RGET, + OMPI_SPC_RGET_NOTIFY, OMPI_SPC_PROBE, OMPI_SPC_IPROBE, OMPI_SPC_BCAST, From 655f1ffbdf8c3fe2230f946b3aadecb437215e3e Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Mon, 10 Aug 2026 20:45:47 -0400 Subject: [PATCH 21/24] ompi: add the MPI-5.1 notification window attributes MPI-5.1 section 12.2.6, Table 12.1 caches three attributes on every window: MPI_WIN_NOTIFICATION_NUM_SB, the number of notification counters the implementation supports efficiently; MPI_WIN_NOTIFICATION_NUM_UB, the upper bound on that number; and MPI_WIN_NOTIFICATION_VALUE_UB, the upper bound on a counter value. Without them a program has no portable way to ask how many counters it may request, since MPI_WIN_GET_NUM_NOTIFY reports how many are attached rather than how many are available. The values come from a new osc_win_get_notify_bounds entry point on the osc module, queried once per window while it is configured. A component that does not implement notified communication leaves the entry point NULL and all three attributes read zero, which is the honest answer for such a window and is consistent with its notified operations returning MPI_ERR_UNSUPPORTED_OPERATION. For osc/sm the bounds follow the reservation: with an mpi_assert_max_num_notify assertion both NUM_SB and NUM_UB are that value, since the window was sized for exactly it; without one, NUM_SB is what was reserved and nothing bounds NUM_UB short of the notification index type, because the counters grow on demand. The keyvals are appended after MPI_FT so that the existing predefined values stay put, with matching entries in mpif-values.py to keep the C and Fortran numbering identical. The predefined-keyval bitmap is already bounded by MPI_ATTR_PREDEFINED_KEY_MAX and needed no change. Table 12.1 types VALUE_UB as MPI_Count *, and the attribute machinery has no MPI_Count slot -- every other predefined attribute is integer- or address-valued. It is stored as an MPI_Aint, which is the same width wherever Open MPI runs now that 32-bit environments are unsupported; the reasoning is recorded at the call site so the choice does not later read as a type error. Signed-off-by: Joseph Antony --- ompi/attribute/attribute_predefined.c | 8 +++++- ompi/include/mpi.h.in | 8 ++++++ ompi/include/mpif-values.py | 3 +++ ompi/mca/osc/osc.h | 20 ++++++++++++++ ompi/mca/osc/sm/osc_sm.h | 5 ++++ ompi/mca/osc/sm/osc_sm_comm.c | 31 +++++++++++++++++++++ ompi/mca/osc/sm/osc_sm_component.c | 1 + ompi/win/win.c | 39 +++++++++++++++++++++++++++ 8 files changed, 114 insertions(+), 1 deletion(-) diff --git a/ompi/attribute/attribute_predefined.c b/ompi/attribute/attribute_predefined.c index 3bc1849dc52..781bdbb70dd 100644 --- a/ompi/attribute/attribute_predefined.c +++ b/ompi/attribute/attribute_predefined.c @@ -143,6 +143,9 @@ int ompi_attr_create_predefined_keyvals(void) OMPI_SUCCESS != (rc = create_win(MPI_WIN_CREATE_FLAVOR)) || OMPI_SUCCESS != (rc = create_win(MPI_WIN_MODEL)) || OMPI_SUCCESS != (rc = create_comm(MPI_FT, false)) || /* not #if conditional on OPAL_ENABLE_FT_MPI for ABI */ + OMPI_SUCCESS != (rc = create_win(MPI_WIN_NOTIFICATION_NUM_SB)) || + OMPI_SUCCESS != (rc = create_win(MPI_WIN_NOTIFICATION_NUM_UB)) || + OMPI_SUCCESS != (rc = create_win(MPI_WIN_NOTIFICATION_VALUE_UB)) || 0) { ret = rc; } @@ -227,7 +230,10 @@ int ompi_attr_free_predefined(void) OMPI_SUCCESS != (rc = free_win(MPI_WIN_SIZE)) || OMPI_SUCCESS != (rc = free_win(MPI_WIN_DISP_UNIT)) || OMPI_SUCCESS != (rc = free_win(MPI_WIN_CREATE_FLAVOR)) || - OMPI_SUCCESS != (rc = free_win(MPI_WIN_MODEL))) { + OMPI_SUCCESS != (rc = free_win(MPI_WIN_MODEL)) || + OMPI_SUCCESS != (rc = free_win(MPI_WIN_NOTIFICATION_NUM_SB)) || + OMPI_SUCCESS != (rc = free_win(MPI_WIN_NOTIFICATION_NUM_UB)) || + OMPI_SUCCESS != (rc = free_win(MPI_WIN_NOTIFICATION_VALUE_UB))) { ret = rc; } diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index d259c5ab4f3..6ac8c447985 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -674,6 +674,14 @@ enum { /* MPI-4 */ MPI_FT, /* used by OPAL_ENABLE_FT_MPI */ + + /* MPI-5.1 notified RMA (section 12.2.6, Table 12.1). Appended here rather + than beside the other MPI_WIN_* keyvals so that the existing values stay + put; the Annex A.1.1 attribute-key table assigns these no ABI value. */ + MPI_WIN_NOTIFICATION_NUM_SB, + MPI_WIN_NOTIFICATION_NUM_UB, + MPI_WIN_NOTIFICATION_VALUE_UB, + MPI_ATTR_PREDEFINED_KEY_MAX, }; diff --git a/ompi/include/mpif-values.py b/ompi/include/mpif-values.py index 62cd9c4e421..bfaca964abf 100755 --- a/ompi/include/mpif-values.py +++ b/ompi/include/mpif-values.py @@ -195,6 +195,9 @@ 'MPI_WIN_CREATE_FLAVOR': 10, 'MPI_WIN_MODEL': 11, 'MPI_FT': 12, + 'MPI_WIN_NOTIFICATION_NUM_SB': 13, + 'MPI_WIN_NOTIFICATION_NUM_UB': 14, + 'MPI_WIN_NOTIFICATION_VALUE_UB': 15, 'MPI_WIN_FLAVOR_CREATE': 1, 'MPI_WIN_FLAVOR_ALLOCATE': 2, 'MPI_WIN_FLAVOR_DYNAMIC': 3, diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index 74197cd3ac3..8ba670e8903 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -266,6 +266,25 @@ typedef int (*ompi_osc_base_module_win_get_num_notify_fn_t)(struct ompi_win_t *w int target_rank, int *num_notifications); +/* Supplies the three notification-related window attributes of MPI-5.1 + * section 12.2.6, Table 12.1, which are cached on the window at creation: + * + * num_sb MPI_WIN_NOTIFICATION_NUM_SB suggested maximum number of + * counters, i.e. how many the + * component supports efficiently + * num_ub MPI_WIN_NOTIFICATION_NUM_UB upper bound on the number of + * counters + * value_ub MPI_WIN_NOTIFICATION_VALUE_UB upper bound on a counter value + * + * Local, and called once per window from ompi_win_t configuration. A component + * that does not implement notified communication leaves this NULL, and all + * three attributes are then cached as zero -- an honest report that no + * notification counter can be attached to such a window. */ +typedef int (*ompi_osc_base_module_win_get_notify_bounds_fn_t)(struct ompi_win_t *win, + int *num_sb, + int *num_ub, + OMPI_MPI_COUNT_TYPE *value_ub); + typedef int (*ompi_osc_base_module_accumulate_fn_t)(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, @@ -526,6 +545,7 @@ struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_win_reset_notify_value_fn_t osc_win_reset_notify_value; ompi_osc_base_module_win_set_num_notify_fn_t osc_win_set_num_notify; ompi_osc_base_module_win_get_num_notify_fn_t osc_win_get_num_notify; + ompi_osc_base_module_win_get_notify_bounds_fn_t osc_win_get_notify_bounds; ompi_osc_base_module_rput_notify_fn_t osc_rput_notify; ompi_osc_base_module_rget_notify_fn_t osc_rget_notify; ompi_osc_base_module_accumulate_notify_fn_t osc_accumulate_notify; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index 75ea8cffebe..375b851fc06 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -220,6 +220,11 @@ int ompi_osc_sm_win_get_num_notify(struct ompi_win_t *win, int target_rank, int *num_notifications); +int ompi_osc_sm_win_get_notify_bounds(struct ompi_win_t *win, + int *num_sb, + int *num_ub, + OMPI_MPI_COUNT_TYPE *value_ub); + int ompi_osc_sm_accumulate(const void *origin_addr, size_t origin_count, struct ompi_datatype_t *origin_dt, diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 410c440dd0a..5510e52c3bc 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -410,6 +410,37 @@ ompi_osc_sm_win_get_num_notify(struct ompi_win_t *win, return OMPI_SUCCESS; } +int +ompi_osc_sm_win_get_notify_bounds(struct ompi_win_t *win, + int *num_sb, + int *num_ub, + OMPI_MPI_COUNT_TYPE *value_ub) +{ + ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; + + if (0 != module->notify_max_assert) { + /* The window was sized on the strength of mpi_assert_max_num_notify, so + * that value is both the hard bound and the number we can serve without + * further allocation. */ + *num_sb = (int) module->notify_max_assert; + *num_ub = (int) module->notify_max_assert; + } else { + /* MPI-5.1 section 12.6.1: NUM_SB is what the implementation "supports + * efficiently", which here is what was reserved at window creation -- + * beyond it MPI_WIN_SET_NUM_NOTIFY has to build a new shared segment. + * Nothing bounds NUM_UB short of the type of the notification index + * itself, since growth is on demand. */ + *num_sb = (int) mca_osc_sm_component.num_notify_counters; + *num_ub = INT_MAX; + } + + /* Counters are int64_t and only ever incremented by one per notified + * operation, so the representable maximum is the real bound. */ + *value_ub = (OMPI_MPI_COUNT_TYPE) INT64_MAX; + + return OMPI_SUCCESS; +} + int ompi_osc_sm_rput(const void *origin_addr, size_t origin_count, diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index b315fed97d5..2aee3c2723c 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -88,6 +88,7 @@ ompi_osc_sm_module_t ompi_osc_sm_module_template = { .osc_win_reset_notify_value = ompi_osc_sm_win_reset_notify_value, .osc_win_set_num_notify = ompi_osc_sm_win_set_num_notify, .osc_win_get_num_notify = ompi_osc_sm_win_get_num_notify, + .osc_win_get_notify_bounds = ompi_osc_sm_win_get_notify_bounds, .osc_accumulate = ompi_osc_sm_accumulate, .osc_accumulate_notify = ompi_osc_sm_accumulate_notify, .osc_compare_and_swap = ompi_osc_sm_compare_and_swap, diff --git a/ompi/win/win.c b/ompi/win/win.c index aff2aa61ea1..69d096e53e9 100644 --- a/ompi/win/win.c +++ b/ompi/win/win.c @@ -249,6 +249,45 @@ config_window(void *base, size_t size, ptrdiff_t disp_unit, MPI_WIN_MODEL, model, true); if (OMPI_SUCCESS != ret) return ret; + /* MPI-5.1 section 12.2.6, Table 12.1: the notification bounds are cached on + * every window, whether or not its component implements notified + * communication. A component that does not leaves the query NULL and the + * attributes read as zero -- no counter may be attached to such a window, + * which is exactly what MPI_Win_set_num_notify would report by returning + * MPI_ERR_UNSUPPORTED_OPERATION. */ + int notify_num_sb = 0, notify_num_ub = 0; + MPI_Count notify_value_ub = 0; + + if (NULL != win->w_osc_module->osc_win_get_notify_bounds) { + ret = win->w_osc_module->osc_win_get_notify_bounds(win, ¬ify_num_sb, + ¬ify_num_ub, + ¬ify_value_ub); + if (OMPI_SUCCESS != ret) return ret; + } + + ret = ompi_attr_set_int(WIN_ATTR, win, + &win->w_keyhash, + MPI_WIN_NOTIFICATION_NUM_SB, notify_num_sb, true); + if (OMPI_SUCCESS != ret) return ret; + + ret = ompi_attr_set_int(WIN_ATTR, win, + &win->w_keyhash, + MPI_WIN_NOTIFICATION_NUM_UB, notify_num_ub, true); + if (OMPI_SUCCESS != ret) return ret; + + /* MPI-5.1 Table 12.1 types this attribute MPI_Count *, and the attribute + * machinery has no MPI_Count slot -- every other predefined attribute is + * integer- or address-valued. Storing it as an MPI_Aint is safe because + * MPI_Aint tracks the pointer width and Open MPI no longer supports 32-bit + * environments, so the two are the same width wherever this runs and the + * value round-trips to the user unchanged. Should 32-bit ever come back, + * this needs a real MPI_Count slot in attribute_value_t instead. */ + ret = ompi_attr_set_aint(WIN_ATTR, win, + &win->w_keyhash, + MPI_WIN_NOTIFICATION_VALUE_UB, + (MPI_Aint) notify_value_ub, true); + if (OMPI_SUCCESS != ret) return ret; + win->w_f_to_c_index = opal_pointer_array_add(&ompi_mpi_windows, win); if (-1 == win->w_f_to_c_index) return OMPI_ERR_OUT_OF_RESOURCE; From 7623174a69f7fc6d3ae80409ec0457a09827483c Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Mon, 10 Aug 2026 20:45:55 -0400 Subject: [PATCH 22/24] ompi/test: add notified RMA tests Covers counter management, all eight notified operations in their blocking and request-based forms, notification index errors, growth past the reserved capacity, the mpi_assert_max_num_notify bound, and the three notification window attributes. A second test forces osc/rdma and checks that every notified entry point reports MPI_ERR_UNSUPPORTED_OPERATION without moving any data, and that the attributes read zero. That is the contract which lets components that do not implement the chapter remain untouched, so it is worth testing directly rather than assuming. Both are single-process tests wired into make check, so the shared segment growth path is exercised only in its single-rank form, where the counters are a plain heap allocation. The collective path -- segment creation, broadcast, attach, the status allreduce and the barrier before unlink -- needs a multi-rank test that this harness cannot host. Signed-off-by: Joseph Antony --- .gitignore | 2 + ompi/test/general/Makefile.am | 10 + ompi/test/general/win_notify.c | 594 +++++++++++++++++++++ ompi/test/general/win_notify_unsupported.c | 151 ++++++ 4 files changed, 757 insertions(+) create mode 100644 ompi/test/general/win_notify.c create mode 100644 ompi/test/general/win_notify_unsupported.c diff --git a/.gitignore b/.gitignore index a6eece7b97b..86ab1392aec 100644 --- a/.gitignore +++ b/.gitignore @@ -276,6 +276,8 @@ ompi/test/general/proc ompi/test/general/request ompi/test/general/seq_tracker ompi/test/general/win +ompi/test/general/win_notify +ompi/test/general/win_notify_unsupported ompi/test/monitoring/monitoring_test ompi/test/monitoring/check_monitoring diff --git a/ompi/test/general/Makefile.am b/ompi/test/general/Makefile.am index d3f06dab347..3ec643ca0a8 100644 --- a/ompi/test/general/Makefile.am +++ b/ompi/test/general/Makefile.am @@ -43,6 +43,8 @@ check_PROGRAMS = \ info_mpi \ request \ win \ + win_notify \ + win_notify_unsupported \ instance \ file \ message @@ -108,6 +110,14 @@ win_SOURCES = win.c win_LDADD = $(ompi_test_ldadd) win_DEPENDENCIES = $(ompi_test_ldadd) +win_notify_SOURCES = win_notify.c +win_notify_LDADD = $(ompi_test_ldadd) +win_notify_DEPENDENCIES = $(ompi_test_ldadd) + +win_notify_unsupported_SOURCES = win_notify_unsupported.c +win_notify_unsupported_LDADD = $(ompi_test_ldadd) +win_notify_unsupported_DEPENDENCIES = $(ompi_test_ldadd) + instance_SOURCES = instance.c instance_LDADD = $(ompi_test_ldadd) instance_DEPENDENCIES = $(ompi_test_ldadd) diff --git a/ompi/test/general/win_notify.c b/ompi/test/general/win_notify.c new file mode 100644 index 00000000000..05c2550024c --- /dev/null +++ b/ompi/test/general/win_notify.c @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2026 Joseph Antony. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +/* + * Unit test for notified RMA communication (MPI-5.1 section 12.6): all + * eight notified communication operations, the notification counter + * management calls, and the counter accessors. + * + * Single process on MPI_COMM_SELF, so the target of every operation is + * this process itself. That is enough to pin down the semantics this test + * cares about -- that each notified operation moves the data its + * non-notified counterpart would, and then increments exactly one + * notification counter by exactly one -- without needing a launcher. + * + * osc/sm is forced because it is currently the only osc component that + * implements the notified operations; on any other component the module's + * notify function pointers are NULL. + * + * Note: the library is compiled with -DNDEBUG, so assert() is a no-op + * here -- all verification must go through test_verify(). + */ + +#include "ompi_config.h" + +#include +#include +#include +#include + +#include "support.h" + +#include "mpi.h" + +#define WIN_COUNT 8 +#define NUM_NOTIFY 4 + +/* Comfortably more than the osc_sm_num_notify_counters default of 16, so that + * asking for this many forces the counters to be reallocated. */ +#define NUM_NOTIFY_GROWN 100 + +static void test_counter_management(void); +static void test_blocking_ops(void); +static void test_request_ops(void); +static void test_notify_idx_errors(void); +static void test_counter_growth(void); +static void test_max_num_notify_assertion(void); +static void test_notify_attributes(void); + +/* Read notification counter "idx" and check it against "expect". */ +static void check_counter(MPI_Win win, int idx, MPI_Count expect, + const char *what) +{ + MPI_Count value = -1; + int rc = MPI_Win_get_notify_value(win, idx, &value); + test_verify(what, MPI_SUCCESS == rc && expect == value); +} + +int main(int argc, char *argv[]) +{ + /* Must be set before MPI_Init: component selection happens there. */ + setenv("OMPI_MCA_osc", "sm", 1); + + test_init("ompi win_notify"); + + int rc = MPI_Init(&argc, &argv); + test_verify("MPI_Init succeeds", MPI_SUCCESS == rc); + + test_counter_management(); + test_blocking_ops(); + test_request_ops(); + test_notify_idx_errors(); + test_counter_growth(); + test_max_num_notify_assertion(); + test_notify_attributes(); + + int r = test_finalize(); + MPI_Finalize(); + return r; +} + +/* ------------------------------------------------------------------ */ + +/* MPI-5.1 section 12.6.1: MPI_WIN_SET_NUM_NOTIFY / MPI_WIN_GET_NUM_NOTIFY, + * and the reset-to-zero behavior of the former. */ +static void test_counter_management(void) +{ + int *base = NULL; + MPI_Win win = MPI_WIN_NULL; + + int rc = MPI_Win_allocate(WIN_COUNT * sizeof(int), sizeof(int), + MPI_INFO_NULL, MPI_COMM_SELF, &base, &win); + test_verify("Win_allocate succeeds", MPI_SUCCESS == rc); + if (MPI_SUCCESS != rc) { + return; + } + + /* MPI-5.1 section 12.6.1 does not state how many counters are attached + * before the first MPI_WIN_SET_NUM_NOTIFY, and osc/sm and osc/ucx + * currently disagree (osc/sm pre-attaches its full reserved capacity, + * osc/ucx starts at zero -- see the note in osc_sm_component.c). So + * only require that the query works and reports something sane; a + * portable program must call MPI_WIN_SET_NUM_NOTIFY first regardless. */ + int num = -1; + rc = MPI_Win_get_num_notify(win, 0, &num); + test_verify("Win_get_num_notify succeeds before set", MPI_SUCCESS == rc); + test_verify("initial attached count is non-negative", num >= 0); + + rc = MPI_Win_set_num_notify(win, MPI_INFO_NULL, NUM_NOTIFY); + test_verify("Win_set_num_notify succeeds", MPI_SUCCESS == rc); + + /* "A subsequent call to MPI_WIN_GET_NUM_NOTIFY will return the value + * given to MPI_WIN_SET_NUM_NOTIFY." */ + num = -1; + rc = MPI_Win_get_num_notify(win, 0, &num); + test_verify("Win_get_num_notify returns what was set", + MPI_SUCCESS == rc && NUM_NOTIFY == num); + + /* All counters start at zero. */ + for (int i = 0; i < NUM_NOTIFY; ++i) { + check_counter(win, i, 0, "counter is zero after set_num_notify"); + } + + /* Bump a counter, then check that set_num_notify resets it: "All + * notification counters (both existing and newly attached) are reset to + * zero by this call." */ + MPI_Win_lock_all(0, win); + int src = 1; + rc = MPI_Put_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, 2, win); + test_verify("Put_notify succeeds", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + check_counter(win, 2, 1, "counter advanced before reset"); + MPI_Win_unlock_all(win); + + rc = MPI_Win_set_num_notify(win, MPI_INFO_NULL, NUM_NOTIFY); + test_verify("Win_set_num_notify succeeds again", MPI_SUCCESS == rc); + check_counter(win, 2, 0, "set_num_notify resets existing counters"); + + /* MPI_WIN_RESET_NOTIFY_VALUE is an atomic fetch-and-zero. */ + MPI_Win_lock_all(0, win); + rc = MPI_Put_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, 1, win); + test_verify("Put_notify succeeds for reset test", MPI_SUCCESS == rc); + rc = MPI_Put_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, 1, win); + test_verify("second Put_notify succeeds for reset test", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + MPI_Win_unlock_all(win); + + MPI_Count value = -1; + rc = MPI_Win_reset_notify_value(win, 1, &value); + test_verify("Win_reset_notify_value returns the prior value", + MPI_SUCCESS == rc && 2 == value); + check_counter(win, 1, 0, "Win_reset_notify_value zeroes the counter"); + + MPI_Win_free(&win); +} + +/* The four blocking notified operations. */ +static void test_blocking_ops(void) +{ + int *base = NULL; + MPI_Win win = MPI_WIN_NULL; + + int rc = MPI_Win_allocate(WIN_COUNT * sizeof(int), sizeof(int), + MPI_INFO_NULL, MPI_COMM_SELF, &base, &win); + test_verify("Win_allocate succeeds (blocking ops)", MPI_SUCCESS == rc); + if (MPI_SUCCESS != rc) { + return; + } + rc = MPI_Win_set_num_notify(win, MPI_INFO_NULL, NUM_NOTIFY); + test_verify("Win_set_num_notify succeeds (blocking ops)", MPI_SUCCESS == rc); + + memset(base, 0, WIN_COUNT * sizeof(int)); + + /* Notified operations are permitted only during a passive target + * epoch (MPI-5.1 section 12.3). */ + MPI_Win_lock_all(0, win); + + /* --- MPI_PUT_NOTIFY --- */ + int src = 42; + rc = MPI_Put_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, 0, win); + test_verify("Put_notify succeeds", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + test_verify("Put_notify moved the data", 42 == base[0]); + check_counter(win, 0, 1, "Put_notify incremented its counter by one"); + + /* --- MPI_GET_NOTIFY --- */ + int dst = 0; + rc = MPI_Get_notify(&dst, 1, MPI_INT, 0, 0, 1, MPI_INT, 0, win); + test_verify("Get_notify succeeds", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + test_verify("Get_notify moved the data", 42 == dst); + check_counter(win, 0, 2, "Get_notify incremented its counter by one"); + + /* --- MPI_ACCUMULATE_NOTIFY --- */ + src = 8; + rc = MPI_Accumulate_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, MPI_SUM, + 1, win); + test_verify("Accumulate_notify succeeds", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + test_verify("Accumulate_notify applied the op", 50 == base[0]); + check_counter(win, 1, 1, "Accumulate_notify incremented its counter by one"); + check_counter(win, 0, 2, "Accumulate_notify left other counters alone"); + + /* MPI_REPLACE takes the other branch in the osc/sm accumulate path. */ + src = 7; + rc = MPI_Accumulate_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, MPI_REPLACE, + 1, win); + test_verify("Accumulate_notify with MPI_REPLACE succeeds", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + test_verify("Accumulate_notify applied MPI_REPLACE", 7 == base[0]); + check_counter(win, 1, 2, "Accumulate_notify/REPLACE incremented its counter"); + + /* --- MPI_GET_ACCUMULATE_NOTIFY --- */ + src = 3; + int result = -1; + rc = MPI_Get_accumulate_notify(&src, 1, MPI_INT, &result, 1, MPI_INT, + 0, 0, 1, MPI_INT, MPI_SUM, 2, win); + test_verify("Get_accumulate_notify succeeds", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + test_verify("Get_accumulate_notify fetched the prior value", 7 == result); + test_verify("Get_accumulate_notify applied the op", 10 == base[0]); + check_counter(win, 2, 1, + "Get_accumulate_notify incremented its counter by one"); + + /* MPI_NO_OP fetches without modifying, and still notifies: the window + * was read, which is an access the notification covers. */ + result = -1; + rc = MPI_Get_accumulate_notify(&src, 1, MPI_INT, &result, 1, MPI_INT, + 0, 0, 1, MPI_INT, MPI_NO_OP, 2, win); + test_verify("Get_accumulate_notify with MPI_NO_OP succeeds", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + test_verify("Get_accumulate_notify/NO_OP fetched the value", 10 == result); + test_verify("Get_accumulate_notify/NO_OP left the window alone", 10 == base[0]); + check_counter(win, 2, 2, + "Get_accumulate_notify/NO_OP incremented its counter"); + + MPI_Win_unlock_all(win); + MPI_Win_free(&win); +} + +/* The four request-based notified operations. Completion of the request + * indicates completion at the origin (MPI-5.1 section 12.6.4). */ +static void test_request_ops(void) +{ + int *base = NULL; + MPI_Win win = MPI_WIN_NULL; + + int rc = MPI_Win_allocate(WIN_COUNT * sizeof(int), sizeof(int), + MPI_INFO_NULL, MPI_COMM_SELF, &base, &win); + test_verify("Win_allocate succeeds (request ops)", MPI_SUCCESS == rc); + if (MPI_SUCCESS != rc) { + return; + } + rc = MPI_Win_set_num_notify(win, MPI_INFO_NULL, NUM_NOTIFY); + test_verify("Win_set_num_notify succeeds (request ops)", MPI_SUCCESS == rc); + + memset(base, 0, WIN_COUNT * sizeof(int)); + + MPI_Win_lock_all(0, win); + + MPI_Request req = MPI_REQUEST_NULL; + + /* --- MPI_RPUT_NOTIFY --- */ + int src = 42; + rc = MPI_Rput_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, 0, win, &req); + test_verify("Rput_notify succeeds", MPI_SUCCESS == rc); + rc = MPI_Wait(&req, MPI_STATUS_IGNORE); + test_verify("Wait on Rput_notify request succeeds", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + test_verify("Rput_notify moved the data", 42 == base[0]); + check_counter(win, 0, 1, "Rput_notify incremented its counter by one"); + + /* --- MPI_RGET_NOTIFY --- */ + int dst = 0; + rc = MPI_Rget_notify(&dst, 1, MPI_INT, 0, 0, 1, MPI_INT, 0, win, &req); + test_verify("Rget_notify succeeds", MPI_SUCCESS == rc); + rc = MPI_Wait(&req, MPI_STATUS_IGNORE); + test_verify("Wait on Rget_notify request succeeds", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + test_verify("Rget_notify moved the data", 42 == dst); + check_counter(win, 0, 2, "Rget_notify incremented its counter by one"); + + /* --- MPI_RACCUMULATE_NOTIFY --- */ + src = 8; + rc = MPI_Raccumulate_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, MPI_SUM, + 1, win, &req); + test_verify("Raccumulate_notify succeeds", MPI_SUCCESS == rc); + rc = MPI_Wait(&req, MPI_STATUS_IGNORE); + test_verify("Wait on Raccumulate_notify request succeeds", MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + test_verify("Raccumulate_notify applied the op", 50 == base[0]); + check_counter(win, 1, 1, "Raccumulate_notify incremented its counter by one"); + + /* --- MPI_RGET_ACCUMULATE_NOTIFY --- */ + src = 3; + int result = -1; + rc = MPI_Rget_accumulate_notify(&src, 1, MPI_INT, &result, 1, MPI_INT, + 0, 0, 1, MPI_INT, MPI_SUM, 2, win, &req); + test_verify("Rget_accumulate_notify succeeds", MPI_SUCCESS == rc); + rc = MPI_Wait(&req, MPI_STATUS_IGNORE); + test_verify("Wait on Rget_accumulate_notify request succeeds", + MPI_SUCCESS == rc); + MPI_Win_flush(0, win); + test_verify("Rget_accumulate_notify fetched the prior value", 50 == result); + test_verify("Rget_accumulate_notify applied the op", 53 == base[0]); + check_counter(win, 2, 1, + "Rget_accumulate_notify incremented its counter by one"); + + MPI_Win_unlock_all(win); + MPI_Win_free(&win); +} + +/* MPI-5.1 section 12.6: "Initiating a notified communication operation that + * references a notification counter that is out of range at the target is + * erroneous", reported as MPI_ERR_RMA_NOTIFICATION. */ +static void test_notify_idx_errors(void) +{ + int *base = NULL; + MPI_Win win = MPI_WIN_NULL; + + int rc = MPI_Win_allocate(WIN_COUNT * sizeof(int), sizeof(int), + MPI_INFO_NULL, MPI_COMM_SELF, &base, &win); + test_verify("Win_allocate succeeds (error cases)", MPI_SUCCESS == rc); + if (MPI_SUCCESS != rc) { + return; + } + MPI_Win_set_errhandler(win, MPI_ERRORS_RETURN); + + rc = MPI_Win_set_num_notify(win, MPI_INFO_NULL, NUM_NOTIFY); + test_verify("Win_set_num_notify succeeds (error cases)", MPI_SUCCESS == rc); + + memset(base, 0, WIN_COUNT * sizeof(int)); + + MPI_Win_lock_all(0, win); + + int src = 1; + int result = 0; + MPI_Request req = MPI_REQUEST_NULL; + + /* Negative index: rejected by the binding's parameter check. */ + rc = MPI_Put_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, -1, win); + test_verify("Put_notify rejects a negative index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Accumulate_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, MPI_SUM, + -1, win); + test_verify("Accumulate_notify rejects a negative index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Get_accumulate_notify(&src, 1, MPI_INT, &result, 1, MPI_INT, + 0, 0, 1, MPI_INT, MPI_SUM, -1, win); + test_verify("Get_accumulate_notify rejects a negative index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Rput_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, -1, win, &req); + test_verify("Rput_notify rejects a negative index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Rget_notify(&result, 1, MPI_INT, 0, 0, 1, MPI_INT, -1, win, &req); + test_verify("Rget_notify rejects a negative index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Raccumulate_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, MPI_SUM, + -1, win, &req); + test_verify("Raccumulate_notify rejects a negative index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Rget_accumulate_notify(&src, 1, MPI_INT, &result, 1, MPI_INT, + 0, 0, 1, MPI_INT, MPI_SUM, -1, win, &req); + test_verify("Rget_accumulate_notify rejects a negative index", + MPI_ERR_RMA_NOTIFICATION == rc); + + /* Index at or past the target's attached count: rejected by the osc + * module, which is the only layer that knows the target's count. */ + rc = MPI_Put_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, NUM_NOTIFY, win); + test_verify("Put_notify rejects an out-of-range index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Accumulate_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, MPI_SUM, + NUM_NOTIFY, win); + test_verify("Accumulate_notify rejects an out-of-range index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Get_accumulate_notify(&src, 1, MPI_INT, &result, 1, MPI_INT, + 0, 0, 1, MPI_INT, MPI_SUM, NUM_NOTIFY, win); + test_verify("Get_accumulate_notify rejects an out-of-range index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Raccumulate_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, MPI_SUM, + NUM_NOTIFY, win, &req); + test_verify("Raccumulate_notify rejects an out-of-range index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Rget_accumulate_notify(&src, 1, MPI_INT, &result, 1, MPI_INT, + 0, 0, 1, MPI_INT, MPI_SUM, NUM_NOTIFY, + win, &req); + test_verify("Rget_accumulate_notify rejects an out-of-range index", + MPI_ERR_RMA_NOTIFICATION == rc); + + /* An operation rejected for its index must not have touched the + * window, and must not have notified. */ + test_verify("a rejected notified operation does not touch the window", + 0 == base[0]); + for (int i = 0; i < NUM_NOTIFY; ++i) { + check_counter(win, i, 0, + "a rejected notified operation does not notify"); + } + + /* The accessors validate their index too. */ + MPI_Count value = -1; + rc = MPI_Win_get_notify_value(win, NUM_NOTIFY, &value); + test_verify("Win_get_notify_value rejects an out-of-range index", + MPI_ERR_RMA_NOTIFICATION == rc); + rc = MPI_Win_reset_notify_value(win, NUM_NOTIFY, &value); + test_verify("Win_reset_notify_value rejects an out-of-range index", + MPI_ERR_RMA_NOTIFICATION == rc); + + MPI_Win_unlock_all(win); + MPI_Win_free(&win); +} + +/* ------------------------------------------------------------------ */ + +/* MPI-5.1 section 12.2 defines the mpi_assert_max_num_notify info key with a + * default of 0, meaning "the implementation does not assume any limit on the + * number of notification counters". A window created without the key must + * therefore honour a request for more counters than osc/sm reserves up front, + * which it does by moving the counters to a larger allocation. */ +static void test_counter_growth(void) +{ + int *base = NULL; + MPI_Win win = MPI_WIN_NULL; + int rc; + + rc = MPI_Win_allocate(WIN_COUNT * sizeof(int), sizeof(int), MPI_INFO_NULL, + MPI_COMM_SELF, &base, &win); + test_verify("Win_allocate succeeds (growth)", MPI_SUCCESS == rc); + MPI_Win_set_errhandler(win, MPI_ERRORS_RETURN); + memset(base, 0, WIN_COUNT * sizeof(int)); + + rc = MPI_Win_set_num_notify(win, MPI_INFO_NULL, NUM_NOTIFY_GROWN); + test_verify("Win_set_num_notify grows past the reserved capacity", + MPI_SUCCESS == rc); + + int num = -1; + rc = MPI_Win_get_num_notify(win, 0, &num); + test_verify("Win_get_num_notify returns the grown count", + MPI_SUCCESS == rc && NUM_NOTIFY_GROWN == num); + + /* Every counter in the grown range must exist and read as zero. */ + for (int i = 0; i < NUM_NOTIFY_GROWN; ++i) { + check_counter(win, i, 0, "grown counter is zero"); + } + + MPI_Win_lock_all(0, win); + + /* An index only reachable after the growth must actually work end to end: + * the operation moves data and lands on the right counter. */ + int src = 99; + rc = MPI_Put_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, + NUM_NOTIFY_GROWN - 1, win); + test_verify("Put_notify succeeds on a counter that only growth provided", + MPI_SUCCESS == rc); + test_verify("Put_notify moved the data after growth", 99 == base[0]); + check_counter(win, NUM_NOTIFY_GROWN - 1, 1, + "the grown counter advanced by one"); + check_counter(win, 0, 0, "the grown counter did not disturb its neighbours"); + + /* One past the grown range is still out of range. */ + rc = MPI_Put_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, + NUM_NOTIFY_GROWN, win); + test_verify("Put_notify still rejects an index past the grown count", + MPI_ERR_RMA_NOTIFICATION == rc); + + MPI_Win_unlock_all(win); + MPI_Win_free(&win); +} + +/* A non-zero mpi_assert_max_num_notify is the user promising not to ask for + * more counters than that. osc/sm reserves exactly that many and holds the + * user to the promise rather than silently reallocating. */ +static void test_max_num_notify_assertion(void) +{ + int *base = NULL; + MPI_Win win = MPI_WIN_NULL; + MPI_Info info = MPI_INFO_NULL; + int rc; + + MPI_Info_create(&info); + MPI_Info_set(info, "mpi_assert_max_num_notify", "8"); + + rc = MPI_Win_allocate(WIN_COUNT * sizeof(int), sizeof(int), info, + MPI_COMM_SELF, &base, &win); + test_verify("Win_allocate succeeds with mpi_assert_max_num_notify", + MPI_SUCCESS == rc); + MPI_Info_free(&info); + MPI_Win_set_errhandler(win, MPI_ERRORS_RETURN); + memset(base, 0, WIN_COUNT * sizeof(int)); + + /* Up to the asserted bound is fine. */ + rc = MPI_Win_set_num_notify(win, MPI_INFO_NULL, 8); + test_verify("Win_set_num_notify accepts the asserted maximum", + MPI_SUCCESS == rc); + + int num = -1; + rc = MPI_Win_get_num_notify(win, 0, &num); + test_verify("Win_get_num_notify returns the asserted maximum", + MPI_SUCCESS == rc && 8 == num); + + /* Past it is an error rather than a reallocation: the window was sized on + * the strength of the assertion. */ + rc = MPI_Win_set_num_notify(win, MPI_INFO_NULL, 9); + test_verify("Win_set_num_notify refuses to exceed the asserted maximum", + MPI_ERR_ARG == rc); + + /* The refused call must not have disturbed the counters that do exist. */ + rc = MPI_Win_get_num_notify(win, 0, &num); + test_verify("a refused Win_set_num_notify leaves the count alone", + MPI_SUCCESS == rc && 8 == num); + + MPI_Win_lock_all(0, win); + int src = 7; + rc = MPI_Put_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, 7, win); + test_verify("Put_notify works on the last asserted counter", + MPI_SUCCESS == rc); + check_counter(win, 7, 1, "the last asserted counter advanced"); + MPI_Win_unlock_all(win); + + MPI_Win_free(&win); +} + +/* ------------------------------------------------------------------ */ + +/* MPI-5.1 section 12.2.6, Table 12.1: the three notification bounds are cached + * on every window at creation. NUM_SB and NUM_UB are int *, VALUE_UB is + * MPI_Count *. */ +static void test_notify_attributes(void) +{ + int *num_sb = NULL, *num_ub = NULL; + MPI_Count *value_ub = NULL; + int *base = NULL; + MPI_Win win = MPI_WIN_NULL; + MPI_Info info = MPI_INFO_NULL; + int flag = 0, rc; + + /* Without an assertion the reservation bounds what is served without + * reallocation, and nothing bounds what may be requested. */ + rc = MPI_Win_allocate(WIN_COUNT * sizeof(int), sizeof(int), MPI_INFO_NULL, + MPI_COMM_SELF, &base, &win); + test_verify("Win_allocate succeeds (attributes)", MPI_SUCCESS == rc); + MPI_Win_set_errhandler(win, MPI_ERRORS_RETURN); + + rc = MPI_Win_get_attr(win, MPI_WIN_NOTIFICATION_NUM_SB, &num_sb, &flag); + test_verify("MPI_WIN_NOTIFICATION_NUM_SB is present", + MPI_SUCCESS == rc && flag && NULL != num_sb); + test_verify("MPI_WIN_NOTIFICATION_NUM_SB is positive", *num_sb > 0); + + rc = MPI_Win_get_attr(win, MPI_WIN_NOTIFICATION_NUM_UB, &num_ub, &flag); + test_verify("MPI_WIN_NOTIFICATION_NUM_UB is present", + MPI_SUCCESS == rc && flag && NULL != num_ub); + test_verify("NUM_UB is unbounded when no assertion was given", + INT_MAX == *num_ub); + + /* A suggested maximum above the hard maximum would be nonsense. */ + test_verify("NUM_SB does not exceed NUM_UB", *num_sb <= *num_ub); + + rc = MPI_Win_get_attr(win, MPI_WIN_NOTIFICATION_VALUE_UB, &value_ub, &flag); + test_verify("MPI_WIN_NOTIFICATION_VALUE_UB is present", + MPI_SUCCESS == rc && flag && NULL != value_ub); + test_verify("VALUE_UB is the full range of the counter type", + INT64_MAX == *value_ub); + + /* Asking for exactly NUM_SB counters must not need a reallocation, and + * must be accepted. */ + int sb = *num_sb; + rc = MPI_Win_set_num_notify(win, MPI_INFO_NULL, sb); + test_verify("Win_set_num_notify accepts NUM_SB counters", MPI_SUCCESS == rc); + + MPI_Win_free(&win); + + /* With an assertion, both bounds collapse onto the asserted value. */ + MPI_Info_create(&info); + MPI_Info_set(info, "mpi_assert_max_num_notify", "8"); + rc = MPI_Win_allocate(WIN_COUNT * sizeof(int), sizeof(int), info, + MPI_COMM_SELF, &base, &win); + test_verify("Win_allocate succeeds (asserted attributes)", MPI_SUCCESS == rc); + MPI_Info_free(&info); + MPI_Win_set_errhandler(win, MPI_ERRORS_RETURN); + + rc = MPI_Win_get_attr(win, MPI_WIN_NOTIFICATION_NUM_UB, &num_ub, &flag); + test_verify("NUM_UB reports the asserted maximum", + MPI_SUCCESS == rc && flag && 8 == *num_ub); + + rc = MPI_Win_get_attr(win, MPI_WIN_NOTIFICATION_NUM_SB, &num_sb, &flag); + test_verify("NUM_SB reports the asserted maximum", + MPI_SUCCESS == rc && flag && 8 == *num_sb); + + MPI_Win_free(&win); +} diff --git a/ompi/test/general/win_notify_unsupported.c b/ompi/test/general/win_notify_unsupported.c new file mode 100644 index 00000000000..ac5754502f9 --- /dev/null +++ b/ompi/test/general/win_notify_unsupported.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2026 Joseph Antony. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +/* + * Notified RMA (MPI-5.1 section 12.6) is optional: an osc component that + * does not implement it leaves the corresponding entries of the module + * struct NULL. Every notified entry point must report that as + * MPI_ERR_UNSUPPORTED_OPERATION rather than calling through a NULL + * function pointer. + * + * osc/rdma is forced because it is a general-purpose component that does + * not implement any of these, so it exercises the guard on all twelve + * entry points. If it cannot be selected in this build the test reports + * that and passes trivially. + * + * Note: the library is compiled with -DNDEBUG, so assert() is a no-op + * here -- all verification must go through test_verify(). + */ + +#include "ompi_config.h" + +#include +#include + +#include "support.h" + +#include "mpi.h" + +#define WIN_COUNT 8 + +int main(int argc, char *argv[]) +{ + /* Must be set before MPI_Init: component selection happens there. */ + setenv("OMPI_MCA_osc", "rdma", 1); + + test_init("ompi win_notify_unsupported"); + + int rc = MPI_Init(&argc, &argv); + test_verify("MPI_Init succeeds", MPI_SUCCESS == rc); + + int *base = NULL; + MPI_Win win = MPI_WIN_NULL; + rc = MPI_Win_allocate(WIN_COUNT * sizeof(int), sizeof(int), MPI_INFO_NULL, + MPI_COMM_SELF, &base, &win); + if (MPI_SUCCESS != rc) { + test_comment("osc/rdma not selectable in this build; skipping"); + int r = test_finalize(); + MPI_Finalize(); + return r; + } + MPI_Win_set_errhandler(win, MPI_ERRORS_RETURN); + memset(base, 0, WIN_COUNT * sizeof(int)); + + int src = 1; + int result = 0; + MPI_Count value = 0; + int num = 0; + MPI_Request req = MPI_REQUEST_NULL; + + /* Counter management and the accessors are usable outside an epoch. */ + rc = MPI_Win_set_num_notify(win, MPI_INFO_NULL, 4); + test_verify("Win_set_num_notify reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + rc = MPI_Win_get_num_notify(win, 0, &num); + test_verify("Win_get_num_notify reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + rc = MPI_Win_get_notify_value(win, 0, &value); + test_verify("Win_get_notify_value reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + rc = MPI_Win_reset_notify_value(win, 0, &value); + test_verify("Win_reset_notify_value reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + + MPI_Win_lock_all(0, win); + + /* The four blocking communication operations. */ + rc = MPI_Put_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, 0, win); + test_verify("Put_notify reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + rc = MPI_Get_notify(&result, 1, MPI_INT, 0, 0, 1, MPI_INT, 0, win); + test_verify("Get_notify reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + rc = MPI_Accumulate_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, MPI_SUM, + 0, win); + test_verify("Accumulate_notify reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + rc = MPI_Get_accumulate_notify(&src, 1, MPI_INT, &result, 1, MPI_INT, + 0, 0, 1, MPI_INT, MPI_SUM, 0, win); + test_verify("Get_accumulate_notify reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + + /* The four request-based communication operations. */ + rc = MPI_Rput_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, 0, win, &req); + test_verify("Rput_notify reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + rc = MPI_Rget_notify(&result, 1, MPI_INT, 0, 0, 1, MPI_INT, 0, win, &req); + test_verify("Rget_notify reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + rc = MPI_Raccumulate_notify(&src, 1, MPI_INT, 0, 0, 1, MPI_INT, MPI_SUM, + 0, win, &req); + test_verify("Raccumulate_notify reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + rc = MPI_Rget_accumulate_notify(&src, 1, MPI_INT, &result, 1, MPI_INT, + 0, 0, 1, MPI_INT, MPI_SUM, 0, win, &req); + test_verify("Rget_accumulate_notify reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + + /* The guard sits ahead of the MPI_PROC_NULL no-op, so an unsupported + * operation is reported identically no matter what the target is. */ + rc = MPI_Put_notify(&src, 1, MPI_INT, MPI_PROC_NULL, 0, 1, MPI_INT, 0, win); + test_verify("Put_notify to MPI_PROC_NULL reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + rc = MPI_Rput_notify(&src, 1, MPI_INT, MPI_PROC_NULL, 0, 1, MPI_INT, 0, + win, &req); + test_verify("Rput_notify to MPI_PROC_NULL reports unsupported", + MPI_ERR_UNSUPPORTED_OPERATION == rc); + + /* Nothing above should have moved any data. */ + test_verify("no unsupported operation touched the window", 0 == base[0]); + + /* MPI-5.1 section 12.2.6: the notification bounds are cached on every + * window, including one whose component cannot do notified communication at + * all. Reporting zero there is the honest answer, and is consistent with + * every operation above having been refused. */ + int *num_sb = NULL, *num_ub = NULL; + MPI_Count *value_ub = NULL; + int flag = 0; + + rc = MPI_Win_get_attr(win, MPI_WIN_NOTIFICATION_NUM_SB, &num_sb, &flag); + test_verify("NUM_SB is present and zero without notification support", + MPI_SUCCESS == rc && flag && NULL != num_sb && 0 == *num_sb); + rc = MPI_Win_get_attr(win, MPI_WIN_NOTIFICATION_NUM_UB, &num_ub, &flag); + test_verify("NUM_UB is present and zero without notification support", + MPI_SUCCESS == rc && flag && NULL != num_ub && 0 == *num_ub); + rc = MPI_Win_get_attr(win, MPI_WIN_NOTIFICATION_VALUE_UB, &value_ub, &flag); + test_verify("VALUE_UB is present and zero without notification support", + MPI_SUCCESS == rc && flag && NULL != value_ub && 0 == *value_ub); + + MPI_Win_unlock_all(win); + MPI_Win_free(&win); + + int r = test_finalize(); + MPI_Finalize(); + return r; +} From a809de809e83417cfdd690c8ea56c3761445a436 Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Tue, 11 Aug 2026 21:27:25 -0400 Subject: [PATCH 23/24] osc/sm: trim the notified RMA comments to the essentials The notified communication code carried long block comments that restated the standard at length and recorded design deliberation. Reduce them to short notes that say what the code does and cite the relevant MPI-5.1 section, so the comment density matches the surrounding osc/sm sources. No functional change. Signed-off-by: Joseph Antony --- ompi/include/mpi.h.in | 4 +- ompi/mca/osc/osc.h | 20 ----- ompi/mca/osc/sm/osc_sm.h | 41 +--------- ompi/mca/osc/sm/osc_sm_comm.c | 126 ++--------------------------- ompi/mca/osc/sm/osc_sm_component.c | 39 +-------- 5 files changed, 11 insertions(+), 219 deletions(-) diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index 6ac8c447985..59b80615828 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -675,9 +675,7 @@ enum { /* MPI-4 */ MPI_FT, /* used by OPAL_ENABLE_FT_MPI */ - /* MPI-5.1 notified RMA (section 12.2.6, Table 12.1). Appended here rather - than beside the other MPI_WIN_* keyvals so that the existing values stay - put; the Annex A.1.1 attribute-key table assigns these no ABI value. */ + /* MPI-5.1 used in notified RMA */ MPI_WIN_NOTIFICATION_NUM_SB, MPI_WIN_NOTIFICATION_NUM_UB, MPI_WIN_NOTIFICATION_VALUE_UB, diff --git a/ompi/mca/osc/osc.h b/ompi/mca/osc/osc.h index 8ba670e8903..10748625db6 100644 --- a/ompi/mca/osc/osc.h +++ b/ompi/mca/osc/osc.h @@ -253,33 +253,14 @@ typedef int (*ompi_osc_base_module_win_reset_notify_value_fn_t)(struct ompi_win_ int notify, OMPI_MPI_COUNT_TYPE *value); -/* MPI-5.1 section 12.6.1. Blocking, synchronizing collective; sets the number - * of notification counters attached at the calling MPI process to exactly - * num_notifications and resets every counter to zero. */ typedef int (*ompi_osc_base_module_win_set_num_notify_fn_t)(struct ompi_win_t *win, struct opal_info_t *info, int num_notifications); -/* MPI-5.1 section 12.6.1. Local; returns the number of notification counters - * attached at target_rank. */ typedef int (*ompi_osc_base_module_win_get_num_notify_fn_t)(struct ompi_win_t *win, int target_rank, int *num_notifications); -/* Supplies the three notification-related window attributes of MPI-5.1 - * section 12.2.6, Table 12.1, which are cached on the window at creation: - * - * num_sb MPI_WIN_NOTIFICATION_NUM_SB suggested maximum number of - * counters, i.e. how many the - * component supports efficiently - * num_ub MPI_WIN_NOTIFICATION_NUM_UB upper bound on the number of - * counters - * value_ub MPI_WIN_NOTIFICATION_VALUE_UB upper bound on a counter value - * - * Local, and called once per window from ompi_win_t configuration. A component - * that does not implement notified communication leaves this NULL, and all - * three attributes are then cached as zero -- an honest report that no - * notification counter can be attached to such a window. */ typedef int (*ompi_osc_base_module_win_get_notify_bounds_fn_t)(struct ompi_win_t *win, int *num_sb, int *num_ub, @@ -501,7 +482,6 @@ typedef int (*ompi_osc_base_module_flush_local_all_fn_t)(struct ompi_win_t *win) * free to create a structure that inherits this one for use as the * module structure. */ - struct ompi_osc_base_module_4_0_0_t { ompi_osc_base_module_win_shared_query_fn_t osc_win_shared_query; diff --git a/ompi/mca/osc/sm/osc_sm.h b/ompi/mca/osc/sm/osc_sm.h index 375b851fc06..c4c38536246 100644 --- a/ompi/mca/osc/sm/osc_sm.h +++ b/ompi/mca/osc/sm/osc_sm.h @@ -26,14 +26,7 @@ typedef opal_atomic_uint64_t osc_sm_post_atomic_type_t; /* Per-rank notification counter capacity reserved inline in the main shared * segment at window creation, and the value reported as * MPI_WIN_NOTIFICATION_NUM_SB -- the number of counters osc/sm supports without - * any further allocation. Overridden by the osc_sm_num_notify_counters MCA - * parameter, and per window by the mpi_assert_max_num_notify info key. - * - * This is a reservation, not a limit. When no info assertion was given, - * MPI_WIN_SET_NUM_NOTIFY may ask for more than this and osc/sm will move the - * counters to a larger, separately allocated shared segment; see - * ompi_osc_sm_win_set_num_notify(). How many counters are actually *attached* - * is a third, per-rank quantity (MPI-5.1 section 12.6.1). */ + * any further allocation. */ #define OSC_SM_DEFAULT_NOTIFY_COUNTERS 16 /* data shared across all peers */ @@ -60,20 +53,8 @@ struct ompi_osc_sm_node_state_t { opal_atomic_int32_t complete_count; ompi_osc_sm_lock_t lock; opal_atomic_lock_t accumulate_lock; - /* Number of notification counters currently *attached* at this rank - * (MPI-5.1 section 12.6.1). Lives in the shared segment so that an origin - * can validate a notification index against the target's attached count - * without any communication. */ uint32_t notify_counter_count; - /* Number of counters currently *reserved* for this rank, i.e. how many it - * may attach without reallocating. This is the rank's - * MPI_WIN_NOTIFICATION_NUM_UB when the window was created with an - * mpi_assert_max_num_notify assertion. */ uint32_t notify_counter_capacity; - /* Offset of this rank's counters within whichever segment currently holds - * them -- the main segment initially, an overflow segment after a growth. - * An offset rather than a pointer because the segment is mapped at a - * different address in every process. */ uint64_t notify_counter_offset; }; typedef struct ompi_osc_sm_node_state_t ompi_osc_sm_node_state_t; @@ -112,25 +93,9 @@ struct ompi_osc_sm_module_t { void **bases; ptrdiff_t *disp_units; - /* notify_bases[i] is *this* process's address for rank i's notification - * counters. Private to each process, since the segment holding the - * counters is mapped at a different address in every process, and - * recomputed by ompi_osc_sm_refresh_notify_bases() whenever the counters - * move. Typed atomic so that plain loads are atomic (and never hoisted out - * of a caller's polling loop) while remote origins increment the same - * location with opal_atomic_add(). */ opal_atomic_int64_t **notify_bases; - /* Overflow segment holding the counters once MPI_WIN_SET_NUM_NOTIFY has - * grown them past what was reserved inline in the main segment. NULL base - * while the counters still live in the main segment. For a single-rank - * window there is no shared segment at all and notify_bases[0] is a plain - * heap allocation owned by this module. */ opal_shmem_ds_t notify_seg_ds; void *notify_segment_base; - /* Value of the mpi_assert_max_num_notify info key, or 0 if none was given. - * Non-zero makes the reservation a hard cap: the user asserted they would - * not exceed it, so MPI_WIN_SET_NUM_NOTIFY refuses to grow past it rather - * than silently reallocating. */ unsigned int notify_max_assert; @@ -159,10 +124,6 @@ int ompi_osc_sm_detach(struct ompi_win_t *win, const void *base); int ompi_osc_sm_free(struct ompi_win_t *win); -/* Recompute notify_bases[] from the segment that currently holds the counters. - * Must be called by every MPI process after the counters move, and at window - * creation. Not used for single-rank windows, whose counters are a plain heap - * allocation. */ void ompi_osc_sm_refresh_notify_bases(ompi_osc_sm_module_t *module); diff --git a/ompi/mca/osc/sm/osc_sm_comm.c b/ompi/mca/osc/sm/osc_sm_comm.c index 5510e52c3bc..4be92da0bc5 100644 --- a/ompi/mca/osc/sm/osc_sm_comm.c +++ b/ompi/mca/osc/sm/osc_sm_comm.c @@ -27,27 +27,12 @@ #include "osc_sm.h" -/* Where this process finds the target's notification counters. A single - * indexed load: the address is precomputed per target by - * ompi_osc_sm_refresh_notify_bases() so that neither the single-rank special - * case nor the possibility that the counters have been moved to an overflow - * segment costs anything on the path of every notified operation. */ static inline opal_atomic_int64_t * osc_sm_target_notify_base(ompi_osc_sm_module_t *module, int target) { return module->notify_bases[target]; } -/* MPI-5.1 section 12.6.1: "The notification counter referenced by a notified - * communication operation must be attached to the window at the target before - * the operation is initiated at the origin. Initiating a notified - * communication operation that references a notification counter that is out of - * range at the target is erroneous." - * - * The check is therefore against the *target's* attached count, and it must - * happen before any data is moved -- otherwise an erroneous call would still - * have overwritten the target window (or, for get, the origin buffer) by the - * time the error is reported. */ static inline int osc_sm_check_notify_idx(ompi_osc_sm_module_t *module, int target, int notify) { @@ -58,23 +43,6 @@ osc_sm_check_notify_idx(ompi_osc_sm_module_t *module, int target, int notify) return OMPI_SUCCESS; } -/* Publish the notification for an operation in the accumulate family. - * - * The fence is a full barrier rather than opal_atomic_wmb() because every - * accumulate-family operation both reads and writes the target window: plain - * accumulate is a read-modify-write of the target for any op other than - * MPI_REPLACE, and get-accumulate additionally copies the target's prior value - * out to the result buffer. MPI-5.1 section 12.6.4 requires that "the window - * locations have been accessed and that the notification counter has then been - * updated (in that order)" -- accesses include loads, so a store-store fence - * would not constrain the reads. opal_atomic_add() is relaxed (see - * opal/include/opal/sys/atomic_stdc.h) and supplies no ordering of its own. - * - * Called after the accumulate lock has been dropped. Holding the lock across - * the increment is unnecessary: the fence already guarantees this operation's - * accesses are visible before its own increment lands, and a concurrent origin - * whose accumulate becomes visible earlier than its increment does not violate - * anything the standard promises about a counter that merely counts. */ static inline void osc_sm_notify_accumulate_done(ompi_osc_sm_module_t *module, int target, int notify) { @@ -96,17 +64,6 @@ ompi_osc_sm_win_get_notify_value(struct ompi_win_t *win, return ret; } - /* Acquire ordering: sample the counter first, then fence, so that window - * loads issued by the caller after this call cannot be satisfied by values - * read before the notification was observed. A barrier placed ahead of the - * counter load would order nothing useful. MPI-5.1 section 12.6.2 requires - * this procedure to synchronize the public and private window copies as if - * MPI_WIN_SYNC had been called; osc/sm is a unified-memory-model component, - * so the barrier is the whole of that synchronization. - * - * The load itself is atomic because the counters are opal_atomic_int64_t: - * remote origins bump the same location concurrently, and the standard's - * usage model is to poll this procedure in a loop. */ *value = (OMPI_MPI_COUNT_TYPE) osc_sm_target_notify_base(module, rank)[notify]; opal_atomic_rmb(); @@ -127,9 +84,7 @@ ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, return ret; } - /* Atomically swap the counter to 0 and return the previous value. Must be - * a single atomic so that increments arriving from other MPI processes - * between the read and the zeroing are not lost. */ + /* Atomically swap the counter to 0 and return the previous value. */ *value = (OMPI_MPI_COUNT_TYPE) opal_atomic_swap_64( &osc_sm_target_notify_base(module, rank)[notify], 0); opal_atomic_rmb(); @@ -140,10 +95,7 @@ ompi_osc_sm_win_reset_notify_value(struct ompi_win_t *win, /* Move every rank's notification counters into a newly created shared segment * sized for the capacities in new_caps. Collective over the window's * communicator; every MPI process must call it with an identical new_caps. - * - * Only reachable when the window was created without an - * mpi_assert_max_num_notify assertion, since that assertion is precisely a - * promise that this will not be needed. */ + */ static int osc_sm_grow_notify_counters(ompi_osc_sm_module_t *module, const unsigned long *new_caps, unsigned long new_count) @@ -168,18 +120,11 @@ osc_sm_grow_notify_counters(ompi_osc_sm_module_t *module, const unsigned long *n memset(&new_seg_ds, 0, sizeof(new_seg_ds)); if (0 == rank) { - /* The cid alone does not distinguish successive segments for the same - * window, so include the generation implied by whether we already have - * an overflow segment plus the new size. */ ret = opal_asprintf(&data_file, "%s" OPAL_PATH_SEP "osc_sm_notify.%s.%x.%d.%s.%lu", mca_osc_sm_component.backing_directory, ompi_process_info.nodename, OMPI_PROC_MY_NAME->jobid, (int) OMPI_PROC_MY_NAME->vpid, ompi_comm_print_cid(module->comm), total_counters); if (ret > 0) { - /* On failure leave new_seg_ds zeroed; the empty seg_name is the - * signal to every other MPI process that this collective failed, - * so that all of them return an error together instead of some - * hanging in the bcast that follows. */ (void) opal_shmem_segment_create(&new_seg_ds, data_file, seg_size); free(data_file); } @@ -199,11 +144,7 @@ osc_sm_grow_notify_counters(ompi_osc_sm_module_t *module, const unsigned long *n new_base = opal_shmem_segment_attach(&new_seg_ds); /* Attach can fail at some MPI processes and not others. Agree on the - * outcome before touching any shared state: if even one process could not - * map the new segment, every process must keep using the old one, or those - * that moved would be incrementing counters that those that stayed never - * read. Nothing above this point has been mutated, so backing out is just - * dropping our own new mapping. */ + * outcome before touching any shared state */ status = (NULL == new_base) ? 1 : 0; ret = module->comm->c_coll->coll_allreduce(MPI_IN_PLACE, &status, 1, MPI_INT, MPI_MAX, module->comm, @@ -234,17 +175,9 @@ osc_sm_grow_notify_counters(ompi_osc_sm_module_t *module, const unsigned long *n ompi_osc_sm_refresh_notify_bases(module); - /* Zero our own counters in their new home. This is also the first touch of - * these pages: if the backing filesystem cannot supply them the fault - * surfaces here rather than at some later notified operation. */ memset((void *) module->notify_bases[rank], 0, module->node_states[rank].notify_counter_capacity * sizeof(int64_t)); - /* Only now raise the attached count to what was asked for. Until the - * space behind it exists, the count must not exceed the capacity: an origin - * validates notification indices against this count, so a count larger than - * the allocation would let a notified operation write past the end of our - * counters. */ module->node_states[rank].notify_counter_count = (uint32_t) new_count; opal_atomic_wmb(); @@ -297,36 +230,11 @@ ompi_osc_sm_win_set_num_notify(struct ompi_win_t *win, return MPI_ERR_ARG; } - /* When the window was created with an mpi_assert_max_num_notify value the - * user asserted they would not exceed it, and we reserved exactly that - * many. Hold them to it rather than silently reallocating: honouring the - * assertion is the only reason the reservation is not generous. */ if (0 != module->notify_max_assert && requested > (unsigned long) module->notify_max_assert) { return MPI_ERR_ARG; } - /* MPI-5.1 section 12.6.1: "A subsequent call to MPI_WIN_GET_NUM_NOTIFY will - * return the value given to MPI_WIN_SET_NUM_NOTIFY." The count is set to - * exactly what was asked for -- note this differs from earlier drafts of - * the chapter, which forbade decreasing it. - * - * "All notification counters (both existing and newly attached) are reset - * to zero by this call." Zero the whole reserved region rather than just - * the attached prefix, so that counters left over from a previous, larger - * attachment cannot resurface if the count is raised again. It is - * erroneous to call this while an access epoch is open, so no origin can be - * incrementing our counters concurrently and plain stores are sufficient. - * - * Done before the allgather so that the allgather doubles as the - * synchronization the standard requires: once it returns, every MPI process - * has both reset its counters and published its new count. - * - * The published count is clamped to what we have actually allocated. When - * growth is needed it is raised to the requested value only once the larger - * allocation exists, so that a growth that fails leaves behind a count an - * origin can safely validate against rather than one that would admit - * writes past the end of our counters. */ memset((void *) module->notify_bases[rank], 0, module->node_states[rank].notify_counter_capacity * sizeof(int64_t)); module->node_states[rank].notify_counter_count = @@ -357,10 +265,6 @@ ompi_osc_sm_win_set_num_notify(struct ompi_win_t *win, return OMPI_ERR_TEMP_OUT_OF_RESOURCE; } - /* Ranks may pass different values, so the new layout cannot be computed - * without everyone's request. This also makes the grow/no-grow decision - * identical at every MPI process, which it must be: creating the new - * segment is itself collective. */ ret = module->comm->c_coll->coll_allgather(&requested, 1, MPI_UNSIGNED_LONG, new_caps, 1, MPI_UNSIGNED_LONG, module->comm, @@ -402,9 +306,6 @@ ompi_osc_sm_win_get_num_notify(struct ompi_win_t *win, return MPI_ERR_RANK; } - /* MPI-5.1 section 12.6.1: local procedure returning the number of counters - * attached at target_rank. Every rank's count is published in the shared - * segment by MPI_WIN_SET_NUM_NOTIFY, so this is a plain read. */ *num_notifications = (int) module->node_states[target_rank].notify_counter_count; return OMPI_SUCCESS; @@ -419,17 +320,9 @@ ompi_osc_sm_win_get_notify_bounds(struct ompi_win_t *win, ompi_osc_sm_module_t *module = (ompi_osc_sm_module_t *) win->w_osc_module; if (0 != module->notify_max_assert) { - /* The window was sized on the strength of mpi_assert_max_num_notify, so - * that value is both the hard bound and the number we can serve without - * further allocation. */ *num_sb = (int) module->notify_max_assert; *num_ub = (int) module->notify_max_assert; } else { - /* MPI-5.1 section 12.6.1: NUM_SB is what the implementation "supports - * efficiently", which here is what was reserved at window creation -- - * beyond it MPI_WIN_SET_NUM_NOTIFY has to build a new shared segment. - * Nothing bounds NUM_UB short of the type of the notification index - * itself, since growth is on demand. */ *num_sb = (int) mca_osc_sm_component.num_notify_counters; *num_ub = INT_MAX; } @@ -519,9 +412,7 @@ ompi_osc_sm_rput_notify(const void *origin_addr, } /* Release ordering: the data must be visible at the target before the - * notification is (MPI-5.1 section 12.3, "The notification counter will be - * updated at the target only after the completion of the data movement - * operation at the target"). */ + * notification is */ opal_atomic_wmb(); opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); @@ -610,12 +501,6 @@ ompi_osc_sm_rget_notify(void *origin_addr, return ret; } - /* Full barrier, not opal_atomic_rmb(): the notification tells the target - * that this get has read the window, so the loads above must not be - * reordered after the counter increment below -- that is a load-before-store - * constraint, which a load-load fence does not express. opal_atomic_add() - * is relaxed (see opal/include/opal/sys/atomic_stdc.h) and supplies no - * ordering of its own. */ opal_atomic_mb(); opal_atomic_add(&osc_sm_target_notify_base(module, target)[notify], 1); @@ -933,8 +818,7 @@ ompi_osc_sm_put_notify(const void *origin_addr, return ret; } - /* Release ordering: the data must be visible at the target before the - * notification is (MPI-5.1 section 12.3, "The notification counter will be + /* (MPI-5.1 section 12.3, "The notification counter will be * updated at the target only after the completion of the data movement * operation at the target"). */ opal_atomic_wmb(); diff --git a/ompi/mca/osc/sm/osc_sm_component.c b/ompi/mca/osc/sm/osc_sm_component.c index 2aee3c2723c..055fb460ee7 100644 --- a/ompi/mca/osc/sm/osc_sm_component.c +++ b/ompi/mca/osc/sm/osc_sm_component.c @@ -172,18 +172,7 @@ static int component_register (void) } -/* Read the mpi_assert_max_num_notify info key (MPI-5.1 section 12.2). - * - * A non-zero value is an assertion by the user that no call to - * MPI_WIN_SET_NUM_NOTIFY on this window will ask for more counters than this, - * which lets us reserve exactly that many and never reallocate. The key's - * default is 0, which the standard defines as "no limit is assumed" -- so it is - * not a request for zero counters, it means we pick, and we must stay able to - * grow on demand later. - * - * Returns the number of counters to reserve per MPI process; *assert_value is - * the raw key value (0 when absent), which the caller keeps to decide whether - * growth is permitted. */ +/* Read the mpi_assert_max_num_notify info key (MPI-5.1 section 12.2). */ static int osc_sm_reserved_notify_counters(opal_info_t *info, unsigned int *assert_value, unsigned int *reserved) { @@ -363,16 +352,7 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis if (NULL == module->posts) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; module->posts[0] = (osc_sm_post_atomic_type_t *) (module->posts + 1); - /* Notification counters for the single process case. There is no - * shared segment here, so they are a plain heap allocation owned by - * this module and reached through notify_bases[0]. - * - * NOTE: osc/sm pre-attaches the reserved capacity, whereas osc/ucx - * starts at zero and requires MPI_WIN_SET_NUM_NOTIFY before any counter - * may be referenced. MPI-5.1 section 12.6.1 does not state what the - * initial attached count is, so neither is provably wrong, but the - * divergence means a program that omits MPI_WIN_SET_NUM_NOTIFY works - * here and fails on ucx. Left as-is pending a decision. */ + /* Notification counters for the single process case. */ module->notify_bases[0] = calloc(notify_reserved, sizeof(int64_t)); if (NULL == module->notify_bases[0]) return OMPI_ERR_TEMP_OUT_OF_RESOURCE; module->node_states[0].notify_counter_capacity = notify_reserved; @@ -537,11 +517,7 @@ component_select(struct ompi_win_t *win, void **base, size_t size, ptrdiff_t dis ompi_osc_sm_refresh_notify_bases(module); - /* Zero only this process's own counters. A freshly created segment - * already reads as zero, but do not depend on the backing store for - * that; zeroing just our own slice keeps the cost proportional to what - * we reserved instead of touching -- and so committing -- every page of - * every rank's region. */ + /* Zero only this process's own counters. */ memset((void *) module->notify_bases[ompi_comm_rank(module->comm)], 0, notify_reserved * sizeof(int64_t)); @@ -706,10 +682,6 @@ ompi_osc_sm_free(struct ompi_win_t *win) module->comm->c_coll->coll_barrier(module->comm, module->comm->c_coll->coll_barrier_module); - /* The counters live either inline in the main segment or, once - * MPI_WIN_SET_NUM_NOTIFY grew them, in an overflow segment of their - * own. Either way they are shared memory, so there is nothing to - * free -- only the overflow mapping to drop. */ if (NULL != module->notify_segment_base) { opal_shmem_segment_detach (&module->notify_seg_ds); } @@ -776,10 +748,7 @@ ompi_osc_sm_get_info(struct ompi_win_t *win, struct opal_info_t **info_used) (module->noncontig) ? "true" : "false"); } - /* Report the assertion back only when one was actually given. Its default - * is 0, meaning "no limit is assumed", and osc/sm honours that by growing on - * demand rather than by adopting any particular bound -- so there is no - * value to report in that case. */ + /* Report the assertion back only when one was actually given. */ if (0 != module->notify_max_assert) { char value_str[16]; snprintf(value_str, sizeof(value_str), "%u", module->notify_max_assert); From 414b9f1b8e0ed40b9e192b7a78b08dd6f440834d Mon Sep 17 00:00:00 2001 From: Joseph Antony Date: Wed, 12 Aug 2026 00:53:11 -0400 Subject: [PATCH 24/24] osc: validate target_rank in MPI_Win_get_num_notify MPI_WIN_GET_NUM_NOTIFY takes target_rank as a nonnegative integer in the group of the window, but the frontend did not validate it. The osc/sm and osc/ucx backends both range-check it and return MPI_ERR_RANK, so this was not a crash, but argument validation belongs in the frontend under MPI_PARAM_CHECK, consistent with the notified communication operations and with MPI_Win_shared_query. MPI_PROC_NULL is deliberately not accepted here: unlike the notified communication operations, the spec specifies target_rank as nonnegative. Signed-off-by: Joseph Antony Co-Authored-By: Claude Opus 5 --- ompi/mpi/c/win_get_num_notify.c.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ompi/mpi/c/win_get_num_notify.c.in b/ompi/mpi/c/win_get_num_notify.c.in index 9ec6b60b5bc..790a740c65a 100644 --- a/ompi/mpi/c/win_get_num_notify.c.in +++ b/ompi/mpi/c/win_get_num_notify.c.in @@ -27,6 +27,11 @@ PROTOTYPE ERROR_CLASS win_get_num_notify(WIN win, INT target_rank, INT_OUT num_n if (ompi_win_invalid(win)) { return OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_WIN, FUNC_NAME); + } else if (ompi_win_peer_invalid(win, target_rank)) { + /* target_rank is specified as a nonnegative integer in the group of + * the window; unlike the notified communication operations, + * MPI_PROC_NULL is not permitted here. */ + rc = MPI_ERR_RANK; } else if (NULL == num_notifications) { rc = MPI_ERR_ARG; }