1 /**
2 * Copyright (C) Mellanox Technologies Ltd. 2001-2015.  ALL RIGHTS RESERVED.
3 * Copyright (c) UT-Battelle, LLC. 2015. ALL RIGHTS RESERVED.
4 *
5 * See file LICENSE for terms.
6 */
7 
8 #include "test_ucp_memheap.h"
9 
10 #include <common/test_helpers.h>
11 #include <ucs/sys/sys.h>
12 
13 
14 std::vector<ucp_test_param>
enum_test_params(const ucp_params_t & ctx_params,const std::string & name,const std::string & test_case_name,const std::string & tls)15 test_ucp_memheap::enum_test_params(const ucp_params_t& ctx_params,
16                                    const std::string& name,
17                                    const std::string& test_case_name,
18                                    const std::string& tls)
19 {
20     std::vector<ucp_test_param> result;
21     generate_test_params_variant(ctx_params, name,
22                                  test_case_name, tls, 0, result);
23     generate_test_params_variant(ctx_params, name,
24                                  test_case_name + "/map_nb",
25                                  tls, UCP_MEM_MAP_NONBLOCK, result);
26     return result;
27 }
28 
test_nonblocking_implicit_stream_xfer(nonblocking_send_func_t send,size_t size,int max_iter,size_t alignment,bool malloc_allocate,bool is_ep_flush)29 void test_ucp_memheap::test_nonblocking_implicit_stream_xfer(nonblocking_send_func_t send,
30                                                              size_t size, int max_iter,
31                                                              size_t alignment,
32                                                              bool malloc_allocate,
33                                                              bool is_ep_flush)
34 {
35     void *memheap;
36     size_t memheap_size;
37     ucp_mem_map_params_t params;
38     ucp_mem_attr_t mem_attr;
39     ucs_status_t status;
40 
41     memheap = NULL;
42     memheap_size = max_iter * size + alignment;
43 
44     if (max_iter == DEFAULT_ITERS) {
45         max_iter = 300 / ucs::test_time_multiplier();
46     }
47 
48     if (size == DEFAULT_SIZE) {
49         size = ucs_max((size_t)ucs::rand() % (12 * UCS_KBYTE), alignment);
50     }
51     memheap_size = max_iter * size + alignment;
52 
53     sender().connect(&receiver(), get_ep_params());
54 
55     params.field_mask = UCP_MEM_MAP_PARAM_FIELD_ADDRESS |
56                         UCP_MEM_MAP_PARAM_FIELD_LENGTH |
57                         UCP_MEM_MAP_PARAM_FIELD_FLAGS;
58     params.length     = memheap_size;
59     params.flags      = GetParam().variant;
60     if (malloc_allocate) {
61         memheap = malloc(memheap_size);
62         params.address = memheap;
63         params.flags   = params.flags & (~(UCP_MEM_MAP_ALLOCATE|UCP_MEM_MAP_FIXED));
64     } else if (params.flags & UCP_MEM_MAP_FIXED) {
65         params.address = ucs::mmap_fixed_address();
66     } else {
67         params.address = NULL;
68         params.flags  |= UCP_MEM_MAP_ALLOCATE;
69     }
70 
71     ucp_mem_h memh;
72     status = ucp_mem_map(receiver().ucph(), &params, &memh);
73     ASSERT_UCS_OK(status);
74 
75     mem_attr.field_mask = UCP_MEM_ATTR_FIELD_ADDRESS |
76                           UCP_MEM_ATTR_FIELD_LENGTH;
77     status = ucp_mem_query(memh, &mem_attr);
78     ASSERT_UCS_OK(status);
79 
80     EXPECT_GE(mem_attr.length, memheap_size);
81     if (!malloc_allocate) {
82         memheap = mem_attr.address;
83     }
84     memset(memheap, 0, memheap_size);
85 
86     void *rkey_buffer;
87     size_t rkey_buffer_size;
88     status = ucp_rkey_pack(receiver().ucph(), memh, &rkey_buffer, &rkey_buffer_size);
89     ASSERT_UCS_OK(status);
90 
91     ucp_rkey_h rkey;
92     status = ucp_ep_rkey_unpack(sender().ep(), rkey_buffer, &rkey);
93     ASSERT_UCS_OK(status);
94 
95     std::string expected_data[300];
96     assert (max_iter <= 300);
97 
98     for (int i = 0; i < max_iter; ++i) {
99         expected_data[i].resize(size);
100 
101         ucs::fill_random(expected_data[i]);
102 
103         ucs_assert(size * i + alignment <= memheap_size);
104 
105         char *ptr = (char*)memheap + alignment + i * size;
106         (this->*send)(&sender(), size, (void*)ptr, rkey, expected_data[i]);
107 
108         ASSERT_UCS_OK(status);
109 
110     }
111 
112     if (is_ep_flush) {
113         flush_ep(sender());
114     } else {
115         flush_worker(sender());
116     }
117 
118     for (int i = 0; i < max_iter; ++i) {
119         char *ptr = (char*)memheap + alignment + i * size;
120         EXPECT_EQ(expected_data[i].substr(0, 20),
121                   std::string(ptr, expected_data[i].length()).substr(0, 20)) <<
122                         ((void*)ptr);
123     }
124 
125     ucp_rkey_destroy(rkey);
126 
127     disconnect(sender());
128 
129     ucp_rkey_buffer_release(rkey_buffer);
130     status = ucp_mem_unmap(receiver().ucph(), memh);
131     ASSERT_UCS_OK(status);
132 
133     if (malloc_allocate) {
134         free(memheap);
135     }
136 }
137 
138 /* NOTE: alignment is ignored if memheap_size is not default */
test_blocking_xfer(blocking_send_func_t send,size_t memheap_size,int max_iter,size_t alignment,bool malloc_allocate,bool is_ep_flush)139 void test_ucp_memheap::test_blocking_xfer(blocking_send_func_t send,
140                                           size_t memheap_size, int max_iter,
141                                           size_t alignment,
142                                           bool malloc_allocate,
143                                           bool is_ep_flush)
144 {
145     ucp_mem_map_params_t params;
146     ucp_mem_attr_t mem_attr;
147     ucs_status_t status;
148     size_t size;
149     int zero_offset = 0;
150 
151     if (max_iter == DEFAULT_ITERS) {
152         max_iter = 300 / ucs::test_time_multiplier();
153     }
154 
155     if (memheap_size == DEFAULT_SIZE) {
156         memheap_size = 3 * UCS_KBYTE;
157         zero_offset = 1;
158     }
159 
160     sender().connect(&receiver(), get_ep_params());
161 
162     /* avoid deadlock for blocking rma/amo */
163     flush_worker(sender());
164 
165     ucp_mem_h memh;
166     void *memheap = NULL;
167 
168     params.field_mask = UCP_MEM_MAP_PARAM_FIELD_ADDRESS |
169                         UCP_MEM_MAP_PARAM_FIELD_LENGTH |
170                         UCP_MEM_MAP_PARAM_FIELD_FLAGS;
171     params.length     = memheap_size;
172     params.flags      = GetParam().variant;
173     if (malloc_allocate) {
174         memheap = malloc(memheap_size);
175         params.address = memheap;
176         params.flags   = params.flags & (~(UCP_MEM_MAP_ALLOCATE|UCP_MEM_MAP_FIXED));
177     } else if (params.flags & UCP_MEM_MAP_FIXED) {
178         params.address = ucs::mmap_fixed_address();
179         params.flags |= UCP_MEM_MAP_ALLOCATE;
180     } else {
181         params.address = NULL;
182         params.flags |= UCP_MEM_MAP_ALLOCATE;
183     }
184 
185     status = ucp_mem_map(receiver().ucph(), &params, &memh);
186     ASSERT_UCS_OK(status);
187 
188     mem_attr.field_mask = UCP_MEM_ATTR_FIELD_ADDRESS |
189                           UCP_MEM_ATTR_FIELD_LENGTH;
190     status = ucp_mem_query(memh, &mem_attr);
191     ASSERT_UCS_OK(status);
192     EXPECT_GE(mem_attr.length, memheap_size);
193     if (!memheap) {
194         memheap = mem_attr.address;
195     }
196     memset(memheap, 0, memheap_size);
197 
198     void *rkey_buffer;
199     size_t rkey_buffer_size;
200     status = ucp_rkey_pack(receiver().ucph(), memh, &rkey_buffer, &rkey_buffer_size);
201     ASSERT_UCS_OK(status);
202 
203     ucp_rkey_h rkey;
204     status = ucp_ep_rkey_unpack(sender().ep(), rkey_buffer, &rkey);
205     ASSERT_UCS_OK(status);
206 
207     ucp_rkey_buffer_release(rkey_buffer);
208 
209     for (int i = 0; i < max_iter; ++i) {
210         size_t offset;
211 
212         if (!zero_offset) {
213             size = ucs_max(ucs::rand() % (memheap_size - alignment - 1), alignment);
214             offset = ucs::rand() % (memheap_size - size - alignment);
215         } else {
216             size = memheap_size;
217             offset = 0;
218         }
219 
220         offset = ucs_align_up(offset, alignment);
221 
222         ucs_assert(((((uintptr_t)memheap + offset)) % alignment) == 0);
223         ucs_assert(size + offset <= memheap_size);
224 
225         std::string expected_data;
226         expected_data.resize(size);
227 
228         ucs::fill_random(expected_data);
229         (this->*send)(&sender(), size, (void*)((uintptr_t)memheap + offset),
230                       rkey, expected_data);
231 
232         if (is_ep_flush) {
233             flush_ep(sender());
234         } else {
235             flush_worker(sender());
236         }
237 
238         EXPECT_EQ(expected_data,
239                   std::string((char*)memheap + offset, expected_data.length()));
240 
241         expected_data.clear();
242     }
243 
244     ucp_rkey_destroy(rkey);
245 
246     disconnect(sender());
247 
248     status = ucp_mem_unmap(receiver().ucph(), memh);
249     ASSERT_UCS_OK(status);
250 
251     if (malloc_allocate) {
252         free(memheap);
253     }
254 }
255