Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fd32e7c
UCS/RCACHE: Adds capability for merging adjacent rcache regions
william-gallagher-nv Sep 17, 2026
82d4c05
UCS/RCACHE: Add test cases
william-gallagher-nv Sep 19, 2026
e1d9bad
UCS/RACHE: Add test coverage
william-gallagher-nv Sep 22, 2026
545a4d4
UCS/RACHE: Allow ROCM MD initialization to respect merge setting
william-gallagher-nv Sep 22, 2026
f964120
UCS/RCACHE: Check adjacent regions for memtype, flags and allocation
william-gallagher-nv Sep 23, 2026
d025653
UCS/RCACHE: Initialize pointers with NULL to fix build
william-gallagher-nv Sep 23, 2026
c9d22be
UCS/RCACHE: Fix imported memh handling
william-gallagher-nv Sep 24, 2026
11f4dd9
UCS/RCACHE: Add test that exercise full merge path
william-gallagher-nv Sep 26, 2026
8a8bd22
UCS/RCACHE: Fix gtest memory leak and whitespace cleanup
william-gallagher-nv Sep 28, 2026
234006f
UCS/RCACHE: Add test variant to toggle memtype cache
william-gallagher-nv Sep 28, 2026
39ef7f5
UCS/RACHE: Fixes gtest mapped_buffer parameters
william-gallagher-nv Sep 28, 2026
3cf0b92
UCS/RCACHE: Applies const where possible
william-gallagher-nv Sep 29, 2026
d8852da
UCS/RCACHE: Formatting and whitespace cleanup
william-gallagher-nv Sep 29, 2026
975dee1
UCS/RCACHE: Verify number of existing rcache regions
william-gallagher-nv Sep 30, 2026
d9ed313
Merge branch 'master' into rcache-merge-adjacent
william-gallagher-nv Sep 30, 2026
b55e24d
UCS/RCACHE: Skip merge for regions with different protection
william-gallagher-nv Oct 1, 2026
7286f58
UCS/RCACHE: Add check to prevent merging memory from different devices
william-gallagher-nv Oct 8, 2026
06e7e84
Merge branch 'master' into rcache-merge-adjacent
william-gallagher-nv Oct 13, 2026
f9d76e4
Merge branch 'master' into rcache-merge-adjacent
william-gallagher-nv Oct 20, 2026
0b3b872
Merge branch 'master' into rcache-merge-adjacent
william-gallagher-nv Oct 26, 2026
0ee9e0c
UCS/RACHE: Skip merge if first region is not registered
william-gallagher-nv Nov 2, 2026
8f6fb0b
UCS/RCACHE: Clang Format
william-gallagher-nv Nov 2, 2026
ab90c1b
Merge branch 'master' into rcache-merge-adjacent
william-gallagher-nv Nov 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 59 additions & 6 deletions src/ucs/memory/rcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ ucs_config_field_t ucs_config_rcache_table[] = {
"Purge registration cache upon fork",
ucs_offsetof(ucs_rcache_config_t, purge_on_fork), UCS_CONFIG_TYPE_BOOL},

{"RCACHE_MERGE_ADJACENT", "n", "Merge adjacent registration cache regions",
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
ucs_offsetof(ucs_rcache_config_t, merge_adjacent), UCS_CONFIG_TYPE_BOOL},

{NULL}
};

Expand Down Expand Up @@ -191,8 +194,14 @@ void ucs_rcache_set_params(ucs_rcache_params_t *rcache_params,
rcache_params->max_regions = rcache_config->max_regions;
rcache_params->max_size = rcache_config->max_size;
rcache_params->max_unreleased = rcache_config->max_unreleased;
rcache_params->flags = !rcache_config->purge_on_fork ? 0 :
UCS_RCACHE_FLAG_PURGE_ON_FORK;

if (rcache_config->purge_on_fork) {
rcache_params->flags |= UCS_RCACHE_FLAG_PURGE_ON_FORK;
}

if (rcache_config->merge_adjacent) {
rcache_params->flags |= UCS_RCACHE_FLAG_MERGE_ADJACENT;
}
}

static size_t ucs_rcache_stat_max_pow2()
Expand Down Expand Up @@ -817,11 +826,48 @@ ucs_rcache_check_overlap_one(ucs_rcache_t *rcache, ucs_pgt_addr_t *start,
return UCS_OK;
}

static int ucs_rcache_check_adj_size(ucs_pgt_addr_t start, ucs_pgt_addr_t end,
const ucs_rcache_region_t *adj_region)
{
return (end - start) >= (adj_region->super.end - adj_region->super.start);
}

static void ucs_rcache_check_adj_regions(ucs_rcache_t *rcache,
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
ucs_pgt_addr_t start,
ucs_pgt_addr_t end, size_t alignment,
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
ucs_list_link_t *list)
{
ucs_pgt_region_t *pgt_left, *pgt_right;
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
ucs_rcache_region_t *region_left, *region_right;

pgt_left = ucs_pgtable_lookup(&rcache->pgtable, start - 1);
pgt_right = ucs_pgtable_lookup(&rcache->pgtable, end);

if (pgt_left != NULL && pgt_right == NULL) {
region_left = ucs_derived_of(pgt_left, ucs_rcache_region_t);
if (ucs_rcache_check_adj_size(start, end, region_left)) {
ucs_list_add_tail(list, &region_left->tmp_list);
}
} else if (pgt_left == NULL && pgt_right != NULL) {
region_right = ucs_derived_of(pgt_right, ucs_rcache_region_t);
if (ucs_rcache_check_adj_size(start, end, region_right)) {
ucs_list_add_tail(list, &region_right->tmp_list);
}
} else if (pgt_left != NULL && pgt_right != NULL) {
/* Fill in a gap between two existing registrations */
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
region_left = ucs_derived_of(pgt_left, ucs_rcache_region_t);
region_right = ucs_derived_of(pgt_right, ucs_rcache_region_t);
ucs_list_add_tail(list, &region_left->tmp_list);
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
ucs_list_add_tail(list, &region_right->tmp_list);
}
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
}

/* Lock must be held */
static ucs_status_t
ucs_rcache_check_overlap(ucs_rcache_t *rcache, void *arg, ucs_pgt_addr_t *start,
ucs_pgt_addr_t *end, size_t *alignment, int *prot,
int *merged, ucs_rcache_region_t **region_p)
ucs_rcache_check_neighbors(ucs_rcache_t *rcache, void *arg,
ucs_pgt_addr_t *start, ucs_pgt_addr_t *end,
size_t *alignment, int *prot, int *merged,
ucs_rcache_region_t **region_p)
{
ucs_rcache_region_t *region, *tmp;
ucs_pgt_addr_t old_start, old_end;
Expand Down Expand Up @@ -874,6 +920,13 @@ ucs_rcache_check_overlap(ucs_rcache_t *rcache, void *arg, ucs_pgt_addr_t *start,
ucs_list_head_init(&region_list);
ucs_rcache_find_regions(rcache, *start, old_start - 1, &region_list);
ucs_rcache_find_regions(rcache, old_end, *end - 1, &region_list);

if (rcache->params.flags & UCS_RCACHE_FLAG_MERGE_ADJACENT) {
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
if (ucs_list_is_empty(&region_list)) {
ucs_rcache_check_adj_regions(rcache, *start, *end, *alignment,
&region_list);
}
}
} while (!ucs_list_is_empty(&region_list));

return UCS_OK;
Expand Down Expand Up @@ -937,7 +990,7 @@ ucs_status_t ucs_rcache_create_region(ucs_rcache_t *rcache, void *address,
/* Check overlap with existing regions */
/* coverity[double_unlock] */
/* coverity[double_lock] */
status = UCS_PROFILE_CALL(ucs_rcache_check_overlap, rcache, arg, &start,
status = UCS_PROFILE_CALL(ucs_rcache_check_neighbors, rcache, arg, &start,
&end, &alignment, &prot, &merged, &region);
if (status == UCS_ERR_ALREADY_EXISTS) {
/* Found a matching region (it could have been added after we released
Expand Down
10 changes: 6 additions & 4 deletions src/ucs/memory/rcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ enum {
* Rcache flags.
*/
enum {
UCS_RCACHE_FLAG_NO_PFN_CHECK = UCS_BIT(0), /**< PFN check not supported for this rcache */
UCS_RCACHE_FLAG_PURGE_ON_FORK = UCS_BIT(1), /**< purge rcache on fork */
UCS_RCACHE_FLAG_SYNC_EVENTS = UCS_BIT(2), /**< Synchronize memory events handling */
UCS_RCACHE_FLAG_NEED_LRU_LOCK = UCS_BIT(3), /**< rcache not protected by other lock */
UCS_RCACHE_FLAG_NO_PFN_CHECK = UCS_BIT(0), /**< PFN check not supported for this rcache */
UCS_RCACHE_FLAG_PURGE_ON_FORK = UCS_BIT(1), /**< purge rcache on fork */
UCS_RCACHE_FLAG_SYNC_EVENTS = UCS_BIT(2), /**< Synchronize memory events handling */
UCS_RCACHE_FLAG_NEED_LRU_LOCK = UCS_BIT(3), /**< rcache not protected by other lock */
UCS_RCACHE_FLAG_MERGE_ADJACENT = UCS_BIT(4) /**< Merge adjacent rcache regions */
};

/*
Expand Down Expand Up @@ -168,6 +169,7 @@ struct ucs_rcache_config {
size_t max_size; /**< Maximal size of mapped memory */
size_t max_unreleased; /**< Threshold for triggering a cleanup */
int purge_on_fork; /**< Enable/disable rcache purge on fork */
int merge_adjacent; /**< Enable/disable rcache adjacent region merge */
};


Expand Down
97 changes: 96 additions & 1 deletion test/gtest/ucs/test_rcache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ get_default_rcache_params(void *context, const ucs_rcache_ops_t *ops)
1000,
ops,
context,
0,
/* Temp for testing merge code. */
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
UCS_RCACHE_FLAG_MERGE_ADJACENT,
ULONG_MAX,
SIZE_MAX};

Expand Down Expand Up @@ -407,6 +408,100 @@ UCS_MT_TEST_F(test_rcache, merge, 6) {
munmap(mem, size1 + pad + size2);
}

UCS_TEST_F(test_rcache, merge_adjacent) {
/*
* 0 1 2 256 pages
* +----------+----------+-------------+-----------+
* | region0 | region1 | ... | region255 |
* +----------+----------+-------------+-----------+
*
* Add 256 regions in ascending order and verify that they are merged into a single region.
Comment thread
william-gallagher-nv marked this conversation as resolved.
Resolved
*/
static const size_t region_count = 256;
static const size_t size = ucs_get_page_size();
static const size_t total_size = region_count * size;
void *mem = NULL;

void *ptrs[region_count];
region *regions[region_count];
region *regions_2[region_count];

EXPECT_EQ(posix_memalign(&mem, ucs_get_page_size(), total_size), 0);
memset(mem, 0, total_size);

for (size_t i = 0; i < region_count; ++i) {
ptrs[i] = (char*)mem + i * size;
regions[i] = get(ptrs[i], size);
}

region *last = regions[region_count - 1];

EXPECT_EQ(last->super.super.start, (uintptr_t)mem);
EXPECT_EQ(last->super.super.end, (uintptr_t)mem + total_size);

for (size_t i = 0; i < region_count - 1; ++i) {
regions_2[i] = get(ptrs[i], size);
EXPECT_NE(regions_2[i], regions[i]);
EXPECT_EQ(regions_2[i], last);
}

for (size_t i = 0; i < region_count - 1; ++i) {
put(regions[i]);
put(regions_2[i]);
}
put(last);

free(mem);
}

UCS_TEST_F(test_rcache, merge_adjacent_high_to_low) {
/*
* 0 1 2 256 pages
* +----------+----------+-------------+-----------+
* | region0 | region1 | ... | region255 |
* +----------+----------+-------------+-----------+
*
* Add 256 regions in descending order and verify that they are merged
* into a single region.
*/
static const size_t region_count = 256;
static const size_t size = ucs_get_page_size();
static const size_t total_size = region_count * size;
void *mem = NULL;

void *ptrs[region_count];
region *regions[region_count];
region *regions_2[region_count];

EXPECT_EQ(posix_memalign(&mem, ucs_get_page_size(), total_size), 0);
memset(mem, 0, total_size);

for (size_t i = region_count; i > 0; --i) {
size_t idx = i - 1;
ptrs[idx] = (char*)mem + idx * size;
regions[idx] = get(ptrs[idx], size);
}

region *last = regions[0];

EXPECT_EQ(last->super.super.start, (uintptr_t)mem);
EXPECT_EQ(last->super.super.end, (uintptr_t)mem + total_size);

for (size_t i = 1; i < region_count; ++i) {
regions_2[i] = get(ptrs[i], size);
EXPECT_NE(regions_2[i], regions[i]);
EXPECT_EQ(regions_2[i], last);
}

for (size_t i = 1; i < region_count; ++i) {
put(regions[i]);
put(regions_2[i]);
}
put(last);

free(mem);
}

UCS_TEST_F(test_rcache, merge_aligned)
{
/*
Expand Down
Loading