UCT/IB/MLX5: add WQE token and completion suppress - #11684
Conversation
738e18e to
35acf5a
Compare
e311e37 to
d3448c3
Compare
796b669 to
2d1fe63
Compare
2d1fe63 to
3b2ec01
Compare
evgeny-leksikov
left a comment
There was a problem hiding this comment.
let's move UCP changes to next PR for simplisity.
Please keep here only UCT API + IMPL + new UCT tests with new behavior:
ep_invalidate(NO_COMPLETION)
post new ops // to be consistent we need to post WQEs here
short_progress_loop // make sure no completions
purge_outstanding(EP) // all completions (for ops before and after invaslidate) appears here
| void *arg; | ||
|
|
||
| /** Completion status for purging all outstanding operations. */ | ||
| ucs_status_t status; |
There was a problem hiding this comment.
is this in or out parameter? what is purpose of the status? I would expect that status of any outstanding operation is unknown.
| if (!(ep->super.ext_flags & UCT_RC_EP_EXT_FLAG_FAILOVER_ARMED)) { | ||
| outstanding = txwq->bb_max - uct_rc_txqp_available(&ep->super.txqp); | ||
| txwq->ft_ci = txwq->prev_sw_pi - outstanding; | ||
| ep->super.ext_flags |= UCT_RC_EP_EXT_FLAG_FAILOVER_ARMED; |
There was a problem hiding this comment.
how does it work? AFAIR per offline discussion, ep_invalidate should suppress completions only by new flag in uct_ep_invalidate_params_t
| outstanding = txwq->bb_max - uct_rc_txqp_available(&ep->super.txqp); | ||
| txwq->ft_ci = txwq->prev_sw_pi - outstanding; | ||
| ep->super.ext_flags |= UCT_RC_EP_EXT_FLAG_FAILOVER_ARMED; | ||
| ucs_assert(txwq->ft_ci == txwq->hw_ci); |
There was a problem hiding this comment.
how about to swap the logic:
assign txwq->ft_ci = txwq->hw_ci
and assert the calculation only for debugging
| base_iface = ucs_derived_of(&iface->super.super.super, uct_base_iface_t); | ||
| is_flush_cancel = ep->super.flags & UCT_RC_EP_FLAG_FLUSH_CANCEL; | ||
| if ((base_iface->err_handler == NULL) || is_flush_cancel) { | ||
| uct_rc_txqp_purge_outstanding(iface, &ep->super.txqp, ep_status, pi, 0); | ||
| } |
There was a problem hiding this comment.
can we simplify? smth like
if (!(ep->super.flags & UCT_RC_EP_FLAG_SUPPRESS_COMPLETIONS)) {
uct_rc_txqp_purge_outstanding(iface, &ep->super.txqp, ep_status, pi, 0);
}
| uint32_t next_token; /* Token assigned to the next packet */ | ||
| uint32_t *tokens; /* Token indexed by WQEBB */ | ||
| uint16_t token_mask; /* Mask for token array */ |
There was a problem hiding this comment.
why do we need the array? can we get each wqe size traversing WQ during purge?
|
|
||
| enum { | ||
| /* Failover owns this endpoint's outstanding WQEs and send operations. */ | ||
| UCT_RC_EP_EXT_FLAG_FAILOVER_ARMED = UCS_BIT(0) |
934ec35 to
70dd829
Compare
| */ | ||
| typedef enum { | ||
| /** Move the endpoint QP to the error state. */ | ||
| UCT_EP_INVALIDATE_FLAG_MODIFY_QP_TO_ERR = UCS_BIT(0), |
There was a problem hiding this comment.
- why needed?
- we dont use IB terms in UCX API
| * Suppress completion of outstanding operations by the normal endpoint | ||
| * error path. The caller transfers outstanding-operation ownership to an | ||
| * external provider and is responsible for completing them. This state | ||
| * remains active until endpoint cancellation or destruction. This flag | ||
| * does not modify QP state. | ||
| */ | ||
| UCT_EP_INVALIDATE_FLAG_SUPPRESS_COMPLETIONS = UCS_BIT(1) |
There was a problem hiding this comment.
IMO "suppress" is not correct wording here since completions of posted operations won't be handled by normal iface_progress and that's user's responsibility to "purge" them.
| * @ref uct_ep_outstanding_purge_params_t::cb is invoked once for each | ||
| * undelivered outstanding operation, in the original endpoint posting order. | ||
| * The transport delegates outstanding-operation classification to its | ||
| * external provider. The provider invokes @ref |
There was a problem hiding this comment.
what is external provider?
| * in the original endpoint posting order. No transport-local status purge is | ||
| * provided by this API. |
There was a problem hiding this comment.
why need to mention status here?
| !(params->field_mask & UCT_EP_INVALIDATE_PARAM_FIELD_FLAGS)) { | ||
| return UCS_ERR_INVALID_PARAM; |
There was a problem hiding this comment.
does not it break compatibility?
| uct_rc_mlx5_base_ep_is_connected(tl_ep, params); | ||
| } | ||
|
|
||
| static void uct_rc_gga_iface_handle_failure(uct_ib_iface_t *ib_iface, void *arg, |
There was a problem hiding this comment.
why do we need special err_hadler for GGA?
| message_length = length + sizeof(*am); | ||
| fm_ce_se |= uct_rc_iface_tx_moderation(&iface->super, txqp, MLX5_WQE_CTRL_CQ_UPDATE); |
| ucs_trace_poll("rc_mlx5 iface %p tx_cqe: ep %p qpn 0x%x hw_ci %d", iface, | ||
| ep, qp_num, hw_ci); | ||
|
|
||
| ucs_assert(!(ep->flags & UCT_RC_MLX5_EP_FLAG_SUPPRESS_COMPLETIONS)); |
| txwq->prev_sw_pi = UINT16_MAX; | ||
| #if UCS_ENABLE_ASSERT | ||
| txwq->ft_ci = UINT16_MAX; | ||
| txwq->next_token = 0; |
There was a problem hiding this comment.
is it still needed?
There was a problem hiding this comment.
IMO, yes.
- For ft_ci:
- ft_ci is used to save which wqe to start purge.
- ft_ci is set when invalidate being called.
- ft_ci will be updated by plugin, so we can retry/reentrant from last pos.
- ft_ci might be diff from hw_ci.
- For next token:
- Used to track token for each message.
- Used to correct token when message is partially delivered.
There was a problem hiding this comment.
ft_ci is clear, my question is about next_token:
Used to correct psn when message is partially delivered
what does happen is this case?
I do not see why we cannot just repost full message:
- In case of put/get, previously arrived data will be over written.
- What happens in case of send? I would expect it should not generate CQE (with err) on sender side and it mean that data will be dropped and we need to resend full message any way.
do I miss something else?
There was a problem hiding this comment.
As discussed offline, next token is the first token for the next message. We can't distinguish whether it's first or middle from HW.
There was a problem hiding this comment.
IMO we need to repost entire undelivered QWE, even if failure happened in the middle. Otherwise we lose data [0; first_failed_packet) for SEND op code, partially delivered QWE won't consume CQE and (partial) data will be dropped on receiver side.
| if (qp->type == UCT_IB_MLX5_OBJ_TYPE_DEVX) { | ||
| char in[UCT_IB_MLX5DV_ST_SZ_BYTES(query_qp_in)] = {}; | ||
| char out[UCT_IB_MLX5DV_ST_SZ_BYTES(query_qp_out)] = {}; | ||
| void *qpc; | ||
| int ret; | ||
|
|
||
| UCT_IB_MLX5DV_SET(query_qp_in, in, opcode, | ||
| UCT_IB_MLX5_CMD_OP_QUERY_QP); | ||
| UCT_IB_MLX5DV_SET(query_qp_in, in, qpn, qp->qp_num); | ||
| ret = mlx5dv_devx_obj_query(qp->devx.obj, in, sizeof(in), out, | ||
| sizeof(out)); | ||
| if (ret != 0) { | ||
| return UCS_ERR_IO_ERROR; | ||
| } | ||
|
|
||
| qpc = UCT_IB_MLX5DV_ADDR_OF(query_qp_out, out, qpc); | ||
| *psn = UCT_IB_MLX5DV_GET(qpc, qpc, next_send_psn); | ||
| return UCS_OK; | ||
| } |
There was a problem hiding this comment.
why do we have it in tests?
There was a problem hiding this comment.
To make sure token calculation matches with HW.
cc80d4e to
f9f10bf
Compare
| /** | ||
| * Defer completion of outstanding operations to the caller. The normal | ||
| * endpoint error path will not complete these operations; the caller must | ||
| * purge them with @ref uct_ep_outstanding_purge. A successful purge returns | ||
| * ownership of subsequent operations to UCT. | ||
| */ | ||
| UCT_EP_INVALIDATE_FLAG_DEFER_COMPLETIONS = UCS_BIT(0) |
There was a problem hiding this comment.
| /** | |
| * Defer completion of outstanding operations to the caller. The normal | |
| * endpoint error path will not complete these operations; the caller must | |
| * purge them with @ref uct_ep_outstanding_purge. A successful purge returns | |
| * ownership of subsequent operations to UCT. | |
| */ | |
| UCT_EP_INVALIDATE_FLAG_DEFER_COMPLETIONS = UCS_BIT(0) | |
| /** | |
| * Do not complete outstanding operations. UCT will not invoke completion | |
| * callbacks for issued operations when the endpoint is invalidated; | |
| * the caller must complete them with @ref uct_ep_outstanding_purge. | |
| */ | |
| UCT_EP_INVALIDATE_FLAG_NO_COMPLETIONS = UCS_BIT(0) |
| * This routine invalidates the endpoint and moves it to the error state. | ||
| * All the incomplete and subsequent operations on the endpoint will be | ||
| * completed with error. | ||
| * Incomplete operations are completed with error unless | ||
| * @ref UCT_EP_INVALIDATE_FLAG_DEFER_COMPLETIONS transfers their ownership to | ||
| * the caller. |
There was a problem hiding this comment.
pls revert, we dont need to mention all possible flags in the function description, only basic behavior
| * uct_ep_outstanding_purge_field_t. @ref | ||
| * UCT_EP_OUTSTANDING_FIELD_RX_TOKEN and @ref | ||
| * UCT_EP_OUTSTANDING_FIELD_CB are required. */ | ||
| * UCT_EP_OUTSTANDING_FIELD_CB are required for token-based purging. */ |
There was a problem hiding this comment.
do we have "something-else"-based purging? are rx_tocken and cb mandatory? check doc for field_mask in other params-like structures, it's only for compatibility, keep fields self-documented and add cross references when it's really needed
|
|
||
| #if HAVE_MLX5_MMO | ||
| if ((qp_type == IBV_QPT_RC) && (opcode != MLX5_OPCODE_NOP) && | ||
| (opcode != MLX5_OPCODE_MMO)) { |
There was a problem hiding this comment.
why is MMO exception?
| return status; | ||
| } | ||
|
|
||
| if ((params != NULL) && |
There was a problem hiding this comment.
I think check params == NULL is redundant, if we call it somewhere this way, let's fix it.
| !(ep->super.flags & UCT_RC_MLX5_EP_FLAG_DEFER_COMPLETIONS)) { | ||
| ep->super.flags |= UCT_RC_MLX5_EP_FLAG_DEFER_COMPLETIONS; |
There was a problem hiding this comment.
- Is it correct to call
ep_invalidatetwice?
There was a problem hiding this comment.
Added assertion instead.
| status = uct_ib_mlx5_ext_ep_outstanding_purge(tl_ep, params); | ||
| if (status == UCS_OK) { | ||
| ep->flags &= ~UCT_RC_MLX5_EP_FLAG_DEFER_COMPLETIONS; | ||
| } | ||
|
|
||
| return status; |
There was a problem hiding this comment.
code style:
| status = uct_ib_mlx5_ext_ep_outstanding_purge(tl_ep, params); | |
| if (status == UCS_OK) { | |
| ep->flags &= ~UCT_RC_MLX5_EP_FLAG_DEFER_COMPLETIONS; | |
| } | |
| return status; | |
| status = uct_ib_mlx5_ext_ep_outstanding_purge(tl_ep, params); | |
| if (status != UCS_OK) { | |
| return status; | |
| } | |
| ep->flags &= ~UCT_RC_MLX5_EP_FLAG_DEFER_COMPLETIONS; | |
| return UCS_OK; |
| void uct_rc_mlx5_ep_update_tx_res(uct_ep_h tl_ep) | ||
| { | ||
| UCT_RC_MLX5_BASE_EP_DECL(tl_ep, iface, ep); | ||
| uct_ib_mlx5_txwq_t *txwq = &ep->tx.wq; | ||
| uint16_t available; | ||
|
|
||
| ucs_assert(ep->flags & UCT_RC_MLX5_EP_FLAG_DEFER_COMPLETIONS); | ||
| available = txwq->bb_max - (txwq->prev_sw_pi - txwq->hw_ci); | ||
| ucs_assert(available >= uct_rc_txqp_available(&ep->super.txqp)); | ||
| if (available > uct_rc_txqp_available(&ep->super.txqp)) { | ||
| uct_rc_mlx5_iface_update_tx_res(&iface->super, ep, txwq->hw_ci); | ||
| } | ||
| } |
There was a problem hiding this comment.
is this new function? where is it called from?
There was a problem hiding this comment.
- Renamed to
uct_rc_mlx5_ep_update_tx_res - Refactored
uct_rc_mlx5_iface_update_tx_res.- Normal path will update both iface and qp tx credits.
- No completion path will update iface tx credits only.
- Uct purge will update QP tx credits once fnished.
ed603a8 to
b99a63c
Compare
What?
Save tokens on the tx side and add support for completion suppress.
Why?
Need to keep tokens on the tx side so the plugin can purge outstanding operations using tokens received from the remote side.
Need to suppress the completions ailover and tx progress do not act on the wqe and pending operations together.
How?
Add completion suppress support in uct ep invalidte.
Add an flag to indicate the completion ownership moved to plugin.