Repository navigation
UCT/IB/DC/RC: Purge internal pending ops to avoid dispatching them when EP failed - #7711
Conversation
|
replaces #7704 |
|
|
||
| ucs_assert_always(iface->config.fc_enabled); | ||
| status = uct_rc_fc_ctrl(&ep->super.super, UCT_RC_EP_FC_PURE_GRANT, NULL); | ||
| if (ep->flags & (UCT_RC_EP_FLAG_FAILED | UCT_RC_EP_FLAG_FLUSH_CANCEL)) { |
|
imo calling purge with certain callback in 2 places is better than adding special paths (new ifs) in more places, like it is done here |
| void uct_rc_ep_pending_purge_warn_cb(uct_pending_req_t *self, void *arg) | ||
| { | ||
| uct_rc_ep_t *ep = arg; | ||
| ucs_warn("ep=%p: pending request %p(%s) was not purged", ep, self, |
IMO it's safer to not send grand and ep_check when ep is in a failed state, rather than going over the pending queue several times and removing the operation. @dmitrygx in which places would we need to clean internal pending reqs (and keep user's pending reqs)? |
fd0ec27 to
cac4723
Compare
brminich
left a comment
There was a problem hiding this comment.
why need to introduce internal purging functions? Can't we just use special callbacks for purge?
I checked it, unfortunately we can't do or I don't see a way how to do it |
what is the problem? set of parameters may be passed as pointer to structure |
we can't use |
It should be possible, please check |
but how to do it w/o introducing a new common function which accepts callbacks |
|
I created it, the name of this callback is |
| } | ||
|
|
||
| uct_rc_txqp_purge_outstanding(iface, &ep->super.txqp, ep_status, pi, 0); | ||
| uct_rc_ep_pending_purge_internal(&ep->super); |
There was a problem hiding this comment.
looks like you can call something like below:
ucs_arbiter_group_purge(&iface->tx.arbiter, &ep->arb_group, uct_rc_ep_arbiter_purge_internal_cb, NULL);
| void uct_rc_ep_pending_purge_internal(uct_rc_ep_t *ep) | ||
| { | ||
| uct_rc_iface_t *iface = ucs_derived_of(ep->super.super.iface, | ||
| uct_rc_iface_t); | ||
| uct_purge_cb_args_t args = { | ||
| (uct_pending_purge_callback_t)ucs_empty_function_do_assert_void, | ||
| NULL | ||
| }; | ||
|
|
||
| ucs_arbiter_group_purge(&iface->tx.arbiter, &ep->arb_group, | ||
| uct_rc_ep_arbiter_purge_internal_cb, &args); | ||
| } |
There was a problem hiding this comment.
no need in this func, uct_rc_ep_arbiter_purge_internal_cb does not do anything with args
| count = uct_rc_verbs_get_tx_res_count(ep, wc); | ||
| uct_rc_txqp_purge_outstanding(iface, &ep->super.txqp, ep_status, | ||
| ep->txcnt.ci + count, 0); | ||
| uct_rc_ep_pending_purge_internal(&ep->super); |
There was a problem hiding this comment.
can call ucs_arbiter_group_purge
| void *priv_args[2] = {ep, arg}; | ||
| uct_purge_cb_args_t args = {cb, priv_args}; | ||
| void *priv_args[2] = {ep, arg}; | ||
| uct_purge_cb_args_t args = {cb, priv_args}; |
There was a problem hiding this comment.
you pass arg as NULL from uct_dc_mlx5_iface_set_ep_failed
There was a problem hiding this comment.
but I pass user's arg from uct_dc_mlx5_ep_pending_purge, so we should use args here
| uct_dc_mlx5_ep_rand_arb_group(iface, ep), | ||
| uct_dc_mlx5_ep_arbiter_purge_cb, &args); | ||
| return; | ||
| arbiter_cb, &args); |
There was a problem hiding this comment.
looks like with rand scheme it should segfault
There was a problem hiding this comment.
why? it should work the same way as previously
|
|
||
| uct_rc_txqp_purge_outstanding(iface, &ep->super.txqp, ep_status, pi, 0); | ||
| ucs_arbiter_group_purge(&iface->tx.arbiter, &ep->super.arb_group, | ||
| uct_rc_ep_arbiter_purge_internal_cb, &args); |
There was a problem hiding this comment.
you can pass NULL instead of args
| uct_rc_txqp_purge_outstanding(iface, &ep->super.txqp, ep_status, | ||
| ep->txcnt.ci + count, 0); | ||
| ucs_arbiter_group_purge(&iface->tx.arbiter, &ep->super.arb_group, | ||
| uct_rc_ep_arbiter_purge_internal_cb, &args); |
|
|
||
| void uct_rc_ep_pending_purge_warn_cb(uct_pending_req_t *self, void *arg) | ||
| { | ||
| uct_rc_ep_t *ep = arg; |
There was a problem hiding this comment.
better cast to uct_ep, because you invoke this cb from dc ep destructor and dc ep is not inherited from rc
| return UCS_ARBITER_CB_RESULT_RESCHED_GROUP; | ||
| } | ||
|
|
||
| /* Non-internal request was found */ |
| } else if (ucs_likely(req->func != uct_rc_ep_fc_grant)) { | ||
| result = uct_rc_ep_arbiter_purge_internal_cb(arbiter, group, elem, arg); | ||
| if (ucs_likely(result != UCS_ARBITER_CB_RESULT_REMOVE_ELEM)) { | ||
| /* Invoke user's callback only if it is not internal FC message */ |
There was a problem hiding this comment.
comment is not valid anymore
| ucs_mpool_put(req); | ||
| } else if (ucs_likely(req->func != uct_rc_ep_fc_grant)) { | ||
| result = uct_rc_ep_arbiter_purge_internal_cb(arbiter, group, elem, arg); | ||
| if (ucs_likely(result != UCS_ARBITER_CB_RESULT_REMOVE_ELEM)) { |
There was a problem hiding this comment.
i'd avoid likely - it is purge + KA probability is supposed to be higher than just FC
| ucs_status_t ep_status) | ||
| { | ||
| uct_ib_iface_t *ib_iface = &iface->super.super.super; | ||
| void *priv_args[2] = {ep, NULL}; |
There was a problem hiding this comment.
you can pass just ep as a private arg, you do not need 2 args
| ucs_arbiter_cb_result_t result; | ||
|
|
||
| result = uct_dc_mlx5_ep_arbiter_purge_internal_cb(arbiter, group, elem, | ||
| arg); |
There was a problem hiding this comment.
you can pass ep pointer here instead of arg
| void **priv_args = cb_args->arg; | ||
| uct_dc_mlx5_ep_t *ep = priv_args[0]; |
There was a problem hiding this comment.
you can assume arg is a pointer to ep, you do not need to pass an array of args here
1029b7c to
acd7350
Compare
|
@yosefe could you review pls? |
acd7350 to
2ca1f08
Compare
What
Purge internal pending ops to avoid dispatching them when EP failed.
Why ?
Fixes:
EP check operation was scheduled on UCT EP internally, i.e. UCP EP doesn't put it on a pending queue, but then UCP EP failed.
And EP check operation stucked on UCT EP's pending queue and then it was dispatched and we got an assertion failure.
How ?