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(), &params, &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(), &params, &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(), &params, &memh[0]);
249     ASSERT_UCS_OK(status);
250 
251     params.address = dummy;
252     status = ucp_mem_map(sender().ucph(), &params, &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(), &params, &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(), &params, &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(), &params, &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