1 /**
2 * Copyright (C) Mellanox Technologies Ltd. 2001-2015. ALL RIGHTS RESERVED.
3 *
4 * See file LICENSE for terms.
5 */
6
7 #include "test_ucp_memheap.h"
8 extern "C" {
9 #include <ucp/core/ucp_context.h>
10 #include <ucp/core/ucp_mm.h>
11 #include <ucp/core/ucp_ep.inl>
12 }
13
14 class test_ucp_mmap : public test_ucp_memheap {
15 public:
get_ctx_params()16 static ucp_params_t get_ctx_params() {
17 ucp_params_t params = ucp_test::get_ctx_params();
18 params.features |= UCP_FEATURE_RMA;
19 return params;
20 }
21
rand_flags()22 static int rand_flags() {
23 if ((ucs::rand() % 2) == 0) {
24 return 0;
25 } else {
26 return UCP_MEM_MAP_NONBLOCK;
27 }
28 }
29
init()30 virtual void init() {
31 ucs::skip_on_address_sanitizer();
32 test_ucp_memheap::init();
33 }
34
35 protected:
36 bool resolve_rma(entity *e, ucp_rkey_h rkey);
37 bool resolve_amo(entity *e, ucp_rkey_h rkey);
38 bool resolve_rma_bw(entity *e, ucp_rkey_h rkey);
39 void test_length0(unsigned flags);
40 void test_rkey_management(entity *e, ucp_mem_h memh, bool is_dummy);
41 };
42
resolve_rma(entity * e,ucp_rkey_h rkey)43 bool test_ucp_mmap::resolve_rma(entity *e, ucp_rkey_h rkey)
44 {
45 ucs_status_t status;
46
47 {
48 scoped_log_handler slh(hide_errors_logger);
49 status = UCP_RKEY_RESOLVE(rkey, e->ep(), rma);
50 }
51
52 if (status == UCS_OK) {
53 EXPECT_NE(UCP_NULL_LANE, rkey->cache.rma_lane);
54 return true;
55 } else if (status == UCS_ERR_UNREACHABLE) {
56 EXPECT_EQ(UCP_NULL_LANE, rkey->cache.rma_lane);
57 return false;
58 } else {
59 UCS_TEST_ABORT("Invalid status from UCP_RKEY_RESOLVE");
60 }
61 }
62
resolve_amo(entity * e,ucp_rkey_h rkey)63 bool test_ucp_mmap::resolve_amo(entity *e, ucp_rkey_h rkey)
64 {
65 ucs_status_t status;
66
67 {
68 scoped_log_handler slh(hide_errors_logger);
69 status = UCP_RKEY_RESOLVE(rkey, e->ep(), amo);
70 }
71
72 if (status == UCS_OK) {
73 EXPECT_NE(UCP_NULL_LANE, rkey->cache.amo_lane);
74 return true;
75 } else if (status == UCS_ERR_UNREACHABLE) {
76 EXPECT_EQ(UCP_NULL_LANE, rkey->cache.amo_lane);
77 return false;
78 } else {
79 UCS_TEST_ABORT("Invalid status from UCP_RKEY_RESOLVE");
80 }
81 }
82
resolve_rma_bw(entity * e,ucp_rkey_h rkey)83 bool test_ucp_mmap::resolve_rma_bw(entity *e, ucp_rkey_h rkey)
84 {
85 ucp_ep_config_t *ep_config = ucp_ep_config(e->ep());
86 ucp_lane_index_t lane;
87 uct_rkey_t uct_rkey;
88
89 lane = ucp_rkey_find_rma_lane(e->ucph(), ep_config, UCS_MEMORY_TYPE_HOST,
90 ep_config->tag.rndv.get_zcopy_lanes, rkey, 0,
91 &uct_rkey);
92 if (lane != UCP_NULL_LANE) {
93 return true;
94 } else {
95 return false;
96 }
97 }
98
test_rkey_management(entity * e,ucp_mem_h memh,bool is_dummy)99 void test_ucp_mmap::test_rkey_management(entity *e, ucp_mem_h memh, bool is_dummy)
100 {
101 size_t rkey_size;
102 void *rkey_buffer;
103 ucs_status_t status;
104
105 /* Some transports don't support memory registration, so the memory
106 * can be inaccessible remotely. But it should always be possible
107 * to pack/unpack a key, even if empty. */
108 status = ucp_rkey_pack(e->ucph(), memh, &rkey_buffer, &rkey_size);
109 if (status == UCS_ERR_UNSUPPORTED && !is_dummy) {
110 return;
111 }
112 ASSERT_UCS_OK(status);
113
114 EXPECT_EQ(ucp_rkey_packed_size(e->ucph(), memh->md_map), rkey_size);
115
116 /* Unpack remote key buffer */
117 ucp_rkey_h rkey;
118 status = ucp_ep_rkey_unpack(e->ep(), rkey_buffer, &rkey);
119 if (status == UCS_ERR_UNREACHABLE && !is_dummy) {
120 ucp_rkey_buffer_release(rkey_buffer);
121 return;
122 }
123 ASSERT_UCS_OK(status);
124
125 /* Test ucp_rkey_packed_md_map() */
126 EXPECT_EQ(rkey->md_map, ucp_rkey_packed_md_map(rkey_buffer));
127
128 bool have_rma = resolve_rma(e, rkey);
129 bool have_amo = resolve_amo(e, rkey);
130 bool have_rma_bw = resolve_rma_bw(e, rkey);
131
132 /* Test that lane resolution on the remote key returns consistent results */
133 for (int i = 0; i < 10; ++i) {
134 switch (ucs::rand() % 3) {
135 case 0:
136 EXPECT_EQ(have_rma, resolve_rma(e, rkey));
137 break;
138 case 1:
139 EXPECT_EQ(have_amo, resolve_amo(e, rkey));
140 break;
141 case 2:
142 EXPECT_EQ(have_rma_bw, resolve_rma_bw(e, rkey));
143 break;
144 }
145 }
146
147 /* Test obtaining direct-access pointer */
148 void *ptr;
149 status = ucp_rkey_ptr(rkey, (uint64_t)memh->address, &ptr);
150 if (status == UCS_OK) {
151 EXPECT_EQ(0, memcmp(memh->address, ptr, memh->length));
152 } else {
153 EXPECT_EQ(UCS_ERR_UNREACHABLE, status);
154 }
155
156 ucp_rkey_destroy(rkey);
157 ucp_rkey_buffer_release(rkey_buffer);
158 }
159
160
UCS_TEST_P(test_ucp_mmap,alloc)161 UCS_TEST_P(test_ucp_mmap, alloc) {
162 ucs_status_t status;
163 bool is_dummy;
164
165 sender().connect(&sender(), get_ep_params());
166
167 for (int i = 0; i < 1000 / ucs::test_time_multiplier(); ++i) {
168 size_t size = ucs::rand() % (UCS_MBYTE);
169
170 ucp_mem_h memh;
171 ucp_mem_map_params_t params;
172
173 params.field_mask = UCP_MEM_MAP_PARAM_FIELD_ADDRESS |
174 UCP_MEM_MAP_PARAM_FIELD_LENGTH |
175 UCP_MEM_MAP_PARAM_FIELD_FLAGS;
176 params.address = NULL;
177 params.length = size;
178 params.flags = rand_flags() | UCP_MEM_MAP_ALLOCATE;
179
180 status = ucp_mem_map(sender().ucph(), ¶ms, &memh);
181 ASSERT_UCS_OK(status);
182
183 is_dummy = (size == 0);
184 test_rkey_management(&sender(), memh, is_dummy);
185
186 status = ucp_mem_unmap(sender().ucph(), memh);
187 ASSERT_UCS_OK(status);
188 }
189 }
190
UCS_TEST_P(test_ucp_mmap,reg)191 UCS_TEST_P(test_ucp_mmap, reg) {
192
193 ucs_status_t status;
194 bool is_dummy;
195
196 sender().connect(&sender(), get_ep_params());
197
198 for (int i = 0; i < 1000 / ucs::test_time_multiplier(); ++i) {
199 size_t size = ucs::rand() % (UCS_MBYTE);
200
201 void *ptr = malloc(size);
202 ucs::fill_random(ptr, size);
203
204 ucp_mem_h memh;
205 ucp_mem_map_params_t params;
206
207 params.field_mask = UCP_MEM_MAP_PARAM_FIELD_ADDRESS |
208 UCP_MEM_MAP_PARAM_FIELD_LENGTH |
209 UCP_MEM_MAP_PARAM_FIELD_FLAGS;
210 params.address = ptr;
211 params.length = size;
212 params.flags = rand_flags();
213
214 status = ucp_mem_map(sender().ucph(), ¶ms, &memh);
215 ASSERT_UCS_OK(status);
216
217 is_dummy = (size == 0);
218 test_rkey_management(&sender(), memh, is_dummy);
219
220 status = ucp_mem_unmap(sender().ucph(), memh);
221 ASSERT_UCS_OK(status);
222
223 free(ptr);
224 }
225 }
226
test_length0(unsigned flags)227 void test_ucp_mmap::test_length0(unsigned flags)
228 {
229 ucs_status_t status;
230 int buf_num = 2;
231 ucp_mem_h memh[buf_num];
232 int dummy[1];
233 ucp_mem_map_params_t params;
234 int i;
235
236 sender().connect(&sender(), get_ep_params());
237
238 /* Check that ucp_mem_map accepts any value for buffer if size is 0 and
239 * UCP_MEM_FLAG_ZERO_REG flag is passed to it. */
240
241 params.field_mask = UCP_MEM_MAP_PARAM_FIELD_ADDRESS |
242 UCP_MEM_MAP_PARAM_FIELD_LENGTH |
243 UCP_MEM_MAP_PARAM_FIELD_FLAGS;
244 params.address = NULL;
245 params.length = 0;
246 params.flags = rand_flags() | flags;
247
248 status = ucp_mem_map(sender().ucph(), ¶ms, &memh[0]);
249 ASSERT_UCS_OK(status);
250
251 params.address = dummy;
252 status = ucp_mem_map(sender().ucph(), ¶ms, &memh[1]);
253 ASSERT_UCS_OK(status);
254
255 for (i = 0; i < buf_num; i++) {
256 test_rkey_management(&sender(), memh[i], true);
257 status = ucp_mem_unmap(sender().ucph(), memh[i]);
258 ASSERT_UCS_OK(status);
259 }
260 }
261
UCS_TEST_P(test_ucp_mmap,reg0)262 UCS_TEST_P(test_ucp_mmap, reg0) {
263 test_length0(0);
264 }
265
UCS_TEST_P(test_ucp_mmap,alloc0)266 UCS_TEST_P(test_ucp_mmap, alloc0) {
267 test_length0(UCP_MEM_MAP_ALLOCATE);
268 }
269
UCS_TEST_P(test_ucp_mmap,alloc_advise)270 UCS_TEST_P(test_ucp_mmap, alloc_advise) {
271 ucs_status_t status;
272 bool is_dummy;
273
274 sender().connect(&sender(), get_ep_params());
275
276 size_t size = 128 * UCS_MBYTE;
277
278 ucp_mem_h memh;
279 ucp_mem_map_params_t params;
280 ucp_mem_attr_t attr;
281 ucp_mem_advise_params_t advise_params;
282
283 params.field_mask = UCP_MEM_MAP_PARAM_FIELD_ADDRESS |
284 UCP_MEM_MAP_PARAM_FIELD_LENGTH |
285 UCP_MEM_MAP_PARAM_FIELD_FLAGS;
286 params.address = NULL;
287 params.length = size;
288 params.flags = UCP_MEM_MAP_NONBLOCK | UCP_MEM_MAP_ALLOCATE;
289
290 status = ucp_mem_map(sender().ucph(), ¶ms, &memh);
291 ASSERT_UCS_OK(status);
292
293 attr.field_mask = UCP_MEM_ATTR_FIELD_ADDRESS | UCP_MEM_ATTR_FIELD_LENGTH;
294 status = ucp_mem_query(memh, &attr);
295 ASSERT_UCS_OK(status);
296 EXPECT_GE(attr.length, size);
297
298 advise_params.field_mask = UCP_MEM_ADVISE_PARAM_FIELD_ADDRESS |
299 UCP_MEM_ADVISE_PARAM_FIELD_LENGTH |
300 UCP_MEM_ADVISE_PARAM_FIELD_ADVICE;
301 advise_params.address = attr.address;
302 advise_params.length = size;
303 advise_params.advice = UCP_MADV_WILLNEED;
304 status = ucp_mem_advise(sender().ucph(), memh, &advise_params);
305 ASSERT_UCS_OK(status);
306
307 is_dummy = (size == 0);
308 test_rkey_management(&sender(), memh, is_dummy);
309
310 status = ucp_mem_unmap(sender().ucph(), memh);
311 ASSERT_UCS_OK(status);
312 }
313
UCS_TEST_P(test_ucp_mmap,reg_advise)314 UCS_TEST_P(test_ucp_mmap, reg_advise) {
315
316 ucs_status_t status;
317 bool is_dummy;
318
319 sender().connect(&sender(), get_ep_params());
320
321 size_t size = 128 * UCS_MBYTE;
322
323 void *ptr = malloc(size);
324 ucs::fill_random(ptr, size);
325
326 ucp_mem_h memh;
327 ucp_mem_map_params_t params;
328 ucp_mem_attr_t mem_attr;
329 ucp_mem_advise_params_t advise_params;
330
331 params.field_mask = UCP_MEM_MAP_PARAM_FIELD_ADDRESS |
332 UCP_MEM_MAP_PARAM_FIELD_LENGTH |
333 UCP_MEM_MAP_PARAM_FIELD_FLAGS;
334 params.address = ptr;
335 params.length = size;
336 params.flags = UCP_MEM_MAP_NONBLOCK;
337
338 status = ucp_mem_map(sender().ucph(), ¶ms, &memh);
339 ASSERT_UCS_OK(status);
340
341 mem_attr.field_mask = UCP_MEM_ATTR_FIELD_ADDRESS;
342 status = ucp_mem_query(memh, &mem_attr);
343 ASSERT_UCS_OK(status);
344
345 advise_params.field_mask = UCP_MEM_ADVISE_PARAM_FIELD_ADDRESS |
346 UCP_MEM_ADVISE_PARAM_FIELD_LENGTH |
347 UCP_MEM_ADVISE_PARAM_FIELD_ADVICE;
348 advise_params.address = mem_attr.address;
349 advise_params.length = size;
350 advise_params.advice = UCP_MADV_WILLNEED;
351 status = ucp_mem_advise(sender().ucph(), memh, &advise_params);
352 ASSERT_UCS_OK(status);
353 is_dummy = (size == 0);
354 test_rkey_management(&sender(), memh, is_dummy);
355
356 status = ucp_mem_unmap(sender().ucph(), memh);
357 ASSERT_UCS_OK(status);
358
359 free(ptr);
360 }
361
UCS_TEST_P(test_ucp_mmap,fixed)362 UCS_TEST_P(test_ucp_mmap, fixed) {
363 ucs_status_t status;
364 bool is_dummy;
365
366 sender().connect(&sender(), get_ep_params());
367
368 for (int i = 0; i < 1000 / ucs::test_time_multiplier(); ++i) {
369 size_t size = (i + 1) * ((i % 2) ? 1000 : 1);
370 void *ptr = ucs::mmap_fixed_address();
371
372 ucp_mem_h memh;
373 ucp_mem_map_params_t params;
374
375 params.field_mask = UCP_MEM_MAP_PARAM_FIELD_ADDRESS |
376 UCP_MEM_MAP_PARAM_FIELD_LENGTH |
377 UCP_MEM_MAP_PARAM_FIELD_FLAGS;
378 params.address = ptr;
379 params.length = size;
380 params.flags = UCP_MEM_MAP_FIXED | UCP_MEM_MAP_ALLOCATE;
381
382 status = ucp_mem_map(sender().ucph(), ¶ms, &memh);
383 ASSERT_UCS_OK(status);
384 EXPECT_EQ(memh->address, ptr);
385 EXPECT_GE(memh->length, size);
386
387 is_dummy = (size == 0);
388 test_rkey_management(&sender(), memh, is_dummy);
389
390 status = ucp_mem_unmap(sender().ucph(), memh);
391 ASSERT_UCS_OK(status);
392 }
393 }
394
395 UCP_INSTANTIATE_TEST_CASE(test_ucp_mmap)
396