Skip to content

Commit dc7cd14

Browse files
authored
Merge branch 'master' into dscp-prio
2 parents e94c746 + ed0bc4d commit dc7cd14

20 files changed

Lines changed: 1097 additions & 239 deletions

File tree

src/ucp/core/ucp_context.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ static ucs_config_field_t ucp_context_config_table[] = {
461461
ucs_offsetof(ucp_context_config_t, dynamic_tl_progress_factor),
462462
UCS_CONFIG_TYPE_TIME_UNITS},
463463

464-
{"RESOLVE_REMOTE_EP_ID", "n",
464+
{"RESOLVE_REMOTE_EP_ID", "auto",
465465
"Defines whether resolving remote endpoint ID is required or not when\n"
466466
"creating a local endpoint. 'auto' means resolving remote endpoint ID only\n"
467467
"in case of error handling and keepalive enabled.",

src/ucp/core/ucp_ep.c

Lines changed: 246 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,13 +1826,250 @@ ucs_status_t ucp_ep_reconfig_clear_failed_lanes(ucp_ep_h ep,
18261826
return UCS_OK;
18271827
}
18281828

1829-
/* Prepare failed lanes for recovery; return the subset to pack into
1830-
* LANES_ADDR_REQUEST. */
1829+
/* Install an empty wireup proxy on the lane, replacing any failed-stub UCT
1830+
* EP left by a preceding ucp_ep_failover_reconfig(). The inner UCT EP is
1831+
* attached separately by ucp_ep_recovery_set_next_ep(). */
1832+
static ucs_status_t
1833+
ucp_ep_recovery_install_wireup_ep(ucp_ep_h ep, ucp_lane_index_t lane)
1834+
{
1835+
uct_ep_h old_uct_ep = ucp_ep_get_lane(ep, lane);
1836+
uct_ep_h wireup_ep_uct;
1837+
ucs_status_t status;
1838+
1839+
ucs_assert(old_uct_ep != NULL);
1840+
if (ucp_wireup_ep_test(old_uct_ep)) {
1841+
return UCS_OK;
1842+
}
1843+
1844+
if (!ucp_is_uct_ep_failed(old_uct_ep)) {
1845+
/* The lane has been already recovered */
1846+
return UCS_ERR_NO_PROGRESS;
1847+
}
1848+
1849+
status = ucp_wireup_ep_create(ep, &wireup_ep_uct);
1850+
if (status != UCS_OK) {
1851+
return status;
1852+
}
1853+
1854+
ucs_trace("ep %p: recovery lane[%d] %p -> wireup_ep %p", ep, lane,
1855+
old_uct_ep, wireup_ep_uct);
1856+
ucp_ep_set_lane(ep, lane, wireup_ep_uct);
1857+
uct_ep_destroy(old_uct_ep);
1858+
return UCS_OK;
1859+
}
1860+
1861+
/* Idempotently ensure the lane's wireup proxy has an inner transport EP. */
1862+
static ucs_status_t
1863+
ucp_ep_recovery_set_next_ep(ucp_ep_h ep, ucp_lane_index_t lane,
1864+
const ucp_address_entry_t *ae)
1865+
{
1866+
const ucp_ep_config_key_t *cfg_key = &ucp_ep_config(ep)->key;
1867+
const ucp_rsc_index_t rsc_index = cfg_key->lanes[lane].rsc_index;
1868+
const unsigned path_index = cfg_key->lanes[lane].path_index;
1869+
uct_ep_h proxy = ucp_ep_get_lane(ep, lane);
1870+
ucp_wireup_ep_t *wireup_ep = ucp_wireup_ep(proxy);
1871+
uct_ep_h next_ep;
1872+
ucs_status_t status;
1873+
1874+
ucs_assertv(wireup_ep != NULL, "ep %p lane %d: expected wireup proxy",
1875+
ep, lane);
1876+
1877+
if (wireup_ep->super.uct_ep != NULL) {
1878+
return UCS_OK;
1879+
}
1880+
1881+
if (ae == NULL) {
1882+
ucs_assert(ucp_ep_is_lane_p2p(ep, lane));
1883+
return ucp_wireup_ep_connect(proxy, 0, rsc_index, path_index, 0, NULL);
1884+
}
1885+
1886+
status = ucp_wireup_iface_ep_create(ucp_worker_iface(ep->worker, rsc_index),
1887+
ae, path_index, &next_ep);
1888+
if (status != UCS_OK) {
1889+
return status;
1890+
}
1891+
1892+
ucp_wireup_ep_set_next_ep(proxy, next_ep, rsc_index);
1893+
return UCS_OK;
1894+
}
1895+
1896+
/**
1897+
* @brief Find a CONNECT_TO_IFACE address entry for the specified lane.
1898+
*
1899+
* Returns the reachable entry whose memory domain index and system device
1900+
* match the lane's recorded destination, to keep the rebuilt lane bound to
1901+
* the same peer device. Returns NULL if no such entry exists.
1902+
*/
1903+
static const ucp_address_entry_t *
1904+
ucp_ep_recovery_find_iface_addr(ucp_ep_h ep, ucp_lane_index_t lane,
1905+
const ucp_unpacked_address_t *remote_address)
1906+
{
1907+
const ucp_ep_config_key_lane_t *cfg_lane =
1908+
&ucp_ep_config(ep)->key.lanes[lane];
1909+
const ucp_rsc_index_t rsc_index = cfg_lane->rsc_index;
1910+
const ucp_address_entry_t *ae;
1911+
1912+
ucp_unpacked_address_for_each(ae, remote_address) {
1913+
if ((ae->iface_addr != NULL) &&
1914+
(ae->md_index == cfg_lane->dst_md_index) &&
1915+
(ae->sys_dev == cfg_lane->dst_sys_dev) &&
1916+
ucp_wireup_is_reachable(ep, 0, rsc_index, ae, NULL, 0)) {
1917+
return ae;
1918+
}
1919+
}
1920+
1921+
return NULL;
1922+
}
1923+
1924+
/* Rebuild one CONNECT_TO_IFACE lane: find peer iface addr -> install empty
1925+
* wireup proxy -> create fully-connected inner UCT EP and attach it -> mark
1926+
* ready. */
1927+
static ucs_status_t
1928+
ucp_ep_recovery_rebuild_iface_lane(
1929+
ucp_ep_h ep, ucp_lane_index_t lane,
1930+
const ucp_unpacked_address_t *remote_address)
1931+
{
1932+
const ucp_address_entry_t *ae;
1933+
ucs_status_t status;
1934+
1935+
ae = ucp_ep_recovery_find_iface_addr(ep, lane, remote_address);
1936+
if (ae == NULL) {
1937+
ucs_debug("ep %p: no remote iface address for lane %d", ep, lane);
1938+
return UCS_ERR_UNREACHABLE;
1939+
}
1940+
1941+
status = ucp_ep_recovery_install_wireup_ep(ep, lane);
1942+
if (status != UCS_OK) {
1943+
return status;
1944+
}
1945+
1946+
status = ucp_ep_recovery_set_next_ep(ep, lane, ae);
1947+
if (status != UCS_OK) {
1948+
ucs_diag("ep %p: set_next_ep failed for recovery iface lane %d: %s",
1949+
ep, lane, ucs_status_string(status));
1950+
return status;
1951+
}
1952+
1953+
ucp_wireup_update_flags(ep, UCS_BIT(lane),
1954+
UCP_WIREUP_EP_FLAG_READY |
1955+
UCP_WIREUP_EP_FLAG_REMOTE_CONNECTED);
1956+
ucs_debug("ep %p: recovered iface-lane[%d] via rsc[%d]", ep, lane,
1957+
ucp_ep_get_rsc_index(ep, lane));
1958+
return UCS_OK;
1959+
}
1960+
1961+
/* Rebuild one p2p (CONNECT_TO_EP) lane. Flow: find peer ep_addr ->
1962+
* install empty wireup proxy -> ensure iface-only inner UCT EP ->
1963+
* connect_to_ep_v2 against peer ep_addr -> mark ready. */
1964+
static ucs_status_t
1965+
ucp_ep_recovery_rebuild_p2p_lane(
1966+
ucp_ep_h ep, ucp_lane_index_t lane,
1967+
const ucp_unpacked_address_t *remote_address)
1968+
{
1969+
const ucp_address_entry_t *address_entry;
1970+
const ucp_address_entry_ep_addr_t *ep_entry;
1971+
ucp_lane_index_t remote_lane;
1972+
ucs_status_t status;
1973+
1974+
/* Symmetric assumption: the peer's lane index mirrors ours.
1975+
* ucp_address_pack() with lanes2remote==NULL stamps the sender-side local
1976+
* lane as the remote_lane tag in the ep_addr, so we look up by our own
1977+
* lane index. */
1978+
remote_lane = lane;
1979+
status = ucp_wireup_find_remote_p2p_addr(ep, remote_lane, remote_address,
1980+
&address_entry, &ep_entry);
1981+
if (status != UCS_OK) {
1982+
ucs_debug("ep %p: no remote ep_addr for p2p lane %d", ep, lane);
1983+
return status;
1984+
}
1985+
1986+
status = ucp_ep_recovery_install_wireup_ep(ep, lane);
1987+
if (status != UCS_OK) {
1988+
return status;
1989+
}
1990+
1991+
status = ucp_ep_recovery_set_next_ep(ep, lane, NULL);
1992+
if (status != UCS_OK) {
1993+
return status;
1994+
}
1995+
1996+
status = ucp_wireup_ep_connect_to_ep_v2(ucp_ep_get_lane(ep, lane),
1997+
address_entry, ep_entry);
1998+
if (status != UCS_OK) {
1999+
ucs_diag("ep %p: connect_to_ep_v2 failed for recovery p2p lane %d: %s",
2000+
ep, lane, ucs_status_string(status));
2001+
return status;
2002+
}
2003+
2004+
ucp_wireup_update_flags(ep, UCS_BIT(lane),
2005+
UCP_WIREUP_EP_FLAG_READY |
2006+
UCP_WIREUP_EP_FLAG_REMOTE_CONNECTED);
2007+
ucs_debug("ep %p: recovered p2p-lane[%d] via rsc[%d]", ep, lane,
2008+
ucp_ep_get_rsc_index(ep, lane));
2009+
return UCS_OK;
2010+
}
2011+
2012+
/* For each lane in `lanes_to_rebuild`, bring its UCT resources back online.
2013+
* Dispatches to the iface-connect or p2p helper based on lane type. Returns
2014+
* the bitmap of lanes successfully rebuilt; lanes not in the returned bitmap
2015+
* stay UCP_LANE_TYPE_FAILED and will be retried on a future recovery round. */
2016+
ucp_lane_map_t
2017+
ucp_ep_recovery_rebuild_lanes(ucp_ep_h ep, ucp_lane_map_t lanes_to_rebuild,
2018+
const ucp_unpacked_address_t *remote_address)
2019+
{
2020+
ucp_lane_map_t rebuilt = 0;
2021+
ucp_lane_index_t lane;
2022+
ucs_status_t status;
2023+
2024+
ucs_for_each_bit(lane, lanes_to_rebuild) {
2025+
if (ucp_ep_is_lane_p2p(ep, lane)) {
2026+
status = ucp_ep_recovery_rebuild_p2p_lane(ep, lane,
2027+
remote_address);
2028+
} else {
2029+
status = ucp_ep_recovery_rebuild_iface_lane(ep, lane,
2030+
remote_address);
2031+
}
2032+
2033+
if (status == UCS_OK) {
2034+
rebuilt |= UCS_BIT(lane);
2035+
}
2036+
}
2037+
2038+
return rebuilt;
2039+
}
2040+
2041+
/* Replace failed UCT stubs with wireup proxies for the given lane set and,
2042+
* for p2p lanes, create their iface-only inner transport EP so that the
2043+
* local ep_addr is available to ucp_address_pack() at REQUEST-send time.
2044+
* Returns the bitmap of lanes that ended up with the full proxy state
2045+
* required to appear in LANES_ADDR_REQUEST. Lanes that failed to reach
2046+
* that state are excluded so they don't get packed (which would try to
2047+
* read addresses from a half-built proxy). */
18312048
static ucp_lane_map_t
18322049
ucp_ep_recovery_prepare_lanes(ucp_ep_h ep, ucp_lane_map_t lanes)
18332050
{
1834-
/* TODO: lane rebuild is not implemented yet. */
1835-
return 0;
2051+
ucp_lane_map_t lane_map = 0;
2052+
ucp_lane_index_t lane;
2053+
2054+
ucs_for_each_bit(lane, lanes) {
2055+
if (ucp_ep_recovery_install_wireup_ep(ep, lane) != UCS_OK) {
2056+
continue;
2057+
}
2058+
2059+
/* For p2p lanes the ep_addr has to exist before we pack the
2060+
* REQUEST (ucp_address_pack iterates p2p_lanes and calls
2061+
* uct_ep_get_address on each). On failure the lane stays with an
2062+
* empty proxy and is skipped from this round; the next recovery
2063+
* round will retry. */
2064+
if (ucp_ep_is_lane_p2p(ep, lane) &&
2065+
(ucp_ep_recovery_set_next_ep(ep, lane, NULL) != UCS_OK)) {
2066+
continue;
2067+
}
2068+
2069+
lane_map |= UCS_BIT(lane);
2070+
}
2071+
2072+
return lane_map;
18362073
}
18372074

18382075
/* Send a LANES_ADDR_REQUEST for the currently failed lanes. */
@@ -1957,6 +2194,11 @@ int ucp_ep_recovery_progress(ucp_ep_h ep)
19572194

19582195
failed &= ~recovered;
19592196
if (failed == 0) {
2197+
/* All failed lanes recovered - drop the retry state so a later
2198+
* round (failed == 0) does not trip the recovery_arg == NULL
2199+
* assertion. */
2200+
ucs_free(ep->ext->recovery_arg);
2201+
ep->ext->recovery_arg = NULL;
19602202
goto done;
19612203
}
19622204

src/ucp/core/ucp_ep.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,15 @@ ucs_status_t ucp_ep_recovery_arm(ucp_ep_h ep);
10171017
int ucp_ep_recovery_progress(ucp_ep_h ep);
10181018

10191019

1020+
/**
1021+
* Rebuild UCT endpoints for the given set of currently-failed lanes using the
1022+
* peer addresses in @a remote_address. Returns the bitmap of lanes rebuilt.
1023+
*/
1024+
ucp_lane_map_t
1025+
ucp_ep_recovery_rebuild_lanes(ucp_ep_h ep, ucp_lane_map_t lanes_to_rebuild,
1026+
const ucp_unpacked_address_t *remote_address);
1027+
1028+
10201029
/**
10211030
* Mark a subset of lanes as UCP_LANE_TYPE_FAILED and arm recovery.
10221031
*/

src/ucp/proto/proto_multi.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,6 @@ static ucp_sys_dev_map_t ucp_proto_multi_init_flush_sys_dev_mask(
160160
return UCS_BIT(key->sys_dev);
161161
}
162162

163-
/* Pack a device's PCI bus id (BDF) into a comparable key. Devices without a
164-
* bus id sort last, ordered by sys_dev to keep a deterministic total order. */
165163
static ucs_bus_id_bit_rep_t
166164
ucp_proto_multi_sys_dev_bus_id_key(ucs_sys_device_t sys_dev)
167165
{
@@ -177,14 +175,22 @@ ucp_proto_multi_sys_dev_bus_id_key(ucs_sys_device_t sys_dev)
177175
static int ucp_proto_multi_sys_dev_cmp(const void *pa, const void *pb,
178176
void *UCS_V_UNUSED arg)
179177
{
180-
const ucs_sys_device_t a = *(const ucs_sys_device_t*)pa;
181-
const ucs_sys_device_t b = *(const ucs_sys_device_t*)pb;
182-
ucs_bus_id_bit_rep_t key_a = ucp_proto_multi_sys_dev_bus_id_key(a);
183-
ucs_bus_id_bit_rep_t key_b = ucp_proto_multi_sys_dev_bus_id_key(b);
184-
185-
/* ascending order by PCI bus id so every rank on the node observes the
186-
* same ordering regardless of local device discovery order */
187-
return (key_a > key_b) - (key_a < key_b);
178+
const ucs_sys_device_t a = *(const ucs_sys_device_t*)pa;
179+
const ucs_sys_device_t b = *(const ucs_sys_device_t*)pb;
180+
ucs_bus_id_bit_rep_t key_a = ucp_proto_multi_sys_dev_bus_id_key(a);
181+
ucs_bus_id_bit_rep_t key_b = ucp_proto_multi_sys_dev_bus_id_key(b);
182+
uintptr_t user_value_a, user_value_b;
183+
184+
/* Sort by topology identity so every rank on the node observes the same
185+
* ordering regardless of local device discovery order. */
186+
if (key_a != key_b) {
187+
return (key_a > key_b) - (key_a < key_b);
188+
}
189+
190+
user_value_a = ucs_topo_sys_device_get_user_value(a);
191+
user_value_b = ucs_topo_sys_device_get_user_value(b);
192+
193+
return (user_value_a > user_value_b) - (user_value_a < user_value_b);
188194
}
189195

190196
static UCS_F_ALWAYS_INLINE ucs_sys_dev_distance_t

src/ucp/rndv/proto_rndv.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,44 @@ ucp_proto_rndv_md_map_to_remote(const ucp_proto_rndv_ctrl_init_params_t *params,
140140
return remote_md_map;
141141
}
142142

143+
/*
144+
* Estimate remote buffer flags from the packed rkey MD map. This is used only
145+
* for protocol estimation and assumes local and remote MDs have the same
146+
* required memory flags.
147+
*/
148+
static uint8_t
149+
ucp_proto_rndv_rkey_mem_flags_estimate(const ucp_proto_init_params_t *params)
150+
{
151+
ucp_context_h context = params->worker->context;
152+
const ucp_rkey_config_key_t *rkey_config_key = params->rkey_config_key;
153+
const ucp_ep_config_key_lane_t *lane_cfg;
154+
ucp_md_index_t md_index;
155+
uint8_t mem_flags = 0;
156+
157+
ucs_assert(rkey_config_key != NULL);
158+
159+
ucs_carray_for_each(lane_cfg, params->ep_config_key->lanes,
160+
params->ep_config_key->num_lanes) {
161+
if ((lane_cfg->rsc_index == UCP_NULL_RESOURCE) ||
162+
(lane_cfg->dst_md_index == UCP_NULL_RESOURCE)) {
163+
continue;
164+
}
165+
166+
if (!(rkey_config_key->md_map & UCS_BIT(lane_cfg->dst_md_index))) {
167+
continue;
168+
}
169+
170+
/*
171+
* Derive UCS_MEM_FLAG_REGISTRABLE from matching local MDs which
172+
* require it and whose remote MDs are present in the rkey.
173+
*/
174+
md_index = context->tl_rscs[lane_cfg->rsc_index].md_index;
175+
mem_flags |= context->tl_mds[md_index].attr.required_mem_flags;
176+
}
177+
178+
return mem_flags;
179+
}
180+
143181
/*
144182
* Init protocols that can be used by the remote peer
145183
* (assuming peer has the same configuration)
@@ -297,7 +335,7 @@ static ucp_proto_select_param_t ucp_proto_rndv_remote_select_param_init(
297335
*/
298336
mem_info.sys_dev = init_params->rkey_config_key->sys_dev;
299337
mem_info.type = init_params->rkey_config_key->mem_type;
300-
mem_info.flags = UCS_MEM_FLAG_REGISTRABLE;
338+
mem_info.flags = ucp_proto_rndv_rkey_mem_flags_estimate(init_params);
301339
ucp_proto_select_param_init(&remote_select_param, params->remote_op_id,
302340
op_attr_mask, 0, UCP_DATATYPE_CONTIG,
303341
&mem_info, 1);

0 commit comments

Comments
 (0)