1 
2 /**
3 * Copyright (C) Mellanox Technologies Ltd. 2001-2014.  ALL RIGHTS RESERVED.
4 * Copyright (C) UT-Battelle, LLC. 2014-2015. ALL RIGHTS RESERVED.
5 * See file LICENSE for terms.
6 */
7 extern "C" {
8 #include <uct/api/uct.h>
9 #include <uct/base/uct_iface.h>
10 
11 #include <ucs/time/time.h>
12 }
13 #include <common/test.h>
14 #include "uct_test.h"
15 #include "uct_p2p_test.h"
16 
17 #ifdef ENABLE_STATS
18 
19 #define EXPECT_STAT(_side, _uct_obj, _stat, _exp_val) \
20     do { \
21         uint64_t v = UCS_STATS_GET_COUNTER(_uct_obj(_side())->stats, _stat); \
22         EXPECT_EQ(get_cntr_init(UCS_PP_MAKE_STRING(_side), \
23                                 UCS_PP_MAKE_STRING(_stat)) + (_exp_val), v); \
24     } while (0)
25 
26 
27 class test_uct_stats : public uct_p2p_test {
28 public:
test_uct_stats()29     test_uct_stats() : uct_p2p_test(0), lbuf(NULL), rbuf(NULL) {
30         m_comp.func  = NULL;
31         m_comp.count = 0;
32     }
33 
init()34     virtual void init() {
35         stats_activate();
36         uct_p2p_test::init();
37 
38         // Sender EP
39         collect_cntr_init("sender", uct_ep(sender())->stats,
40                           UCS_PP_MAKE_STRING(UCT_EP_STAT_FLUSH),
41                           UCT_EP_STAT_FLUSH);
42         collect_cntr_init("sender", uct_ep(sender())->stats,
43                           UCS_PP_MAKE_STRING(UCT_EP_STAT_FLUSH_WAIT),
44                           UCT_EP_STAT_FLUSH_WAIT);
45         collect_cntr_init("sender", uct_ep(sender())->stats,
46                           UCS_PP_MAKE_STRING(UCT_EP_STAT_FENCE),
47                           UCT_EP_STAT_FENCE);
48         collect_cntr_init("sender", uct_ep(sender())->stats,
49                           UCS_PP_MAKE_STRING(UCT_EP_STAT_AM),
50                           UCT_EP_STAT_AM);
51         collect_cntr_init("sender", uct_ep(sender())->stats,
52                           UCS_PP_MAKE_STRING(UCT_EP_STAT_NO_RES),
53                           UCT_EP_STAT_NO_RES);
54         collect_cntr_init("sender", uct_ep(sender())->stats,
55                           UCS_PP_MAKE_STRING(UCT_EP_STAT_PENDING),
56                           UCT_EP_STAT_PENDING);
57         collect_cntr_init("sender", uct_ep(sender())->stats,
58                           UCS_PP_MAKE_STRING(UCT_EP_STAT_ATOMIC),
59                           UCT_EP_STAT_ATOMIC);
60 
61         // Sender IFACE
62         collect_cntr_init("sender", uct_iface(sender())->stats,
63                           UCS_PP_MAKE_STRING(UCT_IFACE_STAT_FLUSH),
64                           UCT_IFACE_STAT_FLUSH);
65         collect_cntr_init("sender", uct_iface(sender())->stats,
66                           UCS_PP_MAKE_STRING(UCT_IFACE_STAT_FLUSH_WAIT),
67                           UCT_IFACE_STAT_FLUSH_WAIT);
68         collect_cntr_init("sender", uct_iface(sender())->stats,
69                           UCS_PP_MAKE_STRING(UCT_IFACE_STAT_FENCE),
70                           UCT_IFACE_STAT_FENCE);
71 
72         // Receiver IFACE
73         collect_cntr_init("receiver", uct_iface(receiver())->stats,
74                           UCS_PP_MAKE_STRING(UCT_IFACE_STAT_RX_AM),
75                           UCT_IFACE_STAT_RX_AM);
76         collect_cntr_init("receiver", uct_iface(receiver())->stats,
77                           UCS_PP_MAKE_STRING(UCT_IFACE_STAT_RX_AM_BYTES),
78                           UCT_IFACE_STAT_RX_AM_BYTES);
79     }
80 
collect_cntr_init(std::string side,ucs_stats_node_t * stats_node,std::string stat_name,unsigned stat)81     void collect_cntr_init(std::string side, ucs_stats_node_t *stats_node,
82                            std::string stat_name, unsigned stat) {
83         cntr_init[side][stat_name] = UCS_STATS_GET_COUNTER(stats_node, stat);
84     }
85 
get_cntr_init(std::string side,std::string stat_name)86     size_t get_cntr_init(std::string side, std::string stat_name) {
87         return cntr_init[side][stat_name];
88     }
89 
init_bufs(size_t min,size_t max)90     void init_bufs(size_t min, size_t max)
91     {
92         size_t size = ucs_max(min, ucs_min(64ul, max));
93         lbuf = new mapped_buffer(size, 0, sender(), 0, sender().md_attr().cap.access_mem_type);
94         rbuf = new mapped_buffer(size, 0, receiver(), 0, sender().md_attr().cap.access_mem_type);
95     }
96 
cleanup()97     virtual void cleanup() {
98         flush();
99         delete lbuf;
100         delete rbuf;
101         uct_p2p_test::cleanup();
102         stats_restore();
103     }
104 
uct_ep(const entity & e)105     uct_base_ep_t *uct_ep(const entity &e)
106     {
107             return ucs_derived_of(e.ep(0), uct_base_ep_t);
108     }
109 
uct_iface(const entity & e)110     uct_base_iface_t *uct_iface(const entity &e)
111     {
112             return ucs_derived_of(e.iface(), uct_base_iface_t);
113     }
114 
am_handler(void * arg,void * data,size_t length,unsigned flags)115     static ucs_status_t am_handler(void *arg, void *data, size_t length,
116                                    unsigned flags) {
117         return UCS_OK;
118     }
119 
purge_cb(uct_pending_req_t * r,void * arg)120     static void purge_cb(uct_pending_req_t *r, void *arg)
121     {
122     }
123 
check_am_rx_counters(size_t len)124     void check_am_rx_counters(size_t len) {
125         uint64_t iface_rx_am_init = get_cntr_init("receiver",
126                                                   UCS_PP_MAKE_STRING(UCT_IFACE_STAT_RX_AM));
127         uint64_t v;
128 
129         ucs_time_t deadline = ucs::get_deadline();
130         do {
131             short_progress_loop();
132             v = UCS_STATS_GET_COUNTER(uct_iface(receiver())->stats, UCT_IFACE_STAT_RX_AM);
133         } while ((ucs_get_time() < deadline) && (v == iface_rx_am_init));
134 
135         EXPECT_STAT(receiver, uct_iface, UCT_IFACE_STAT_RX_AM, 1UL);
136         EXPECT_STAT(receiver, uct_iface, UCT_IFACE_STAT_RX_AM_BYTES, len);
137     }
138 
check_atomic_counters()139     void check_atomic_counters() {
140         EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_ATOMIC, 1UL);
141         /* give atomic chance to complete */
142         short_progress_loop();
143     }
144 
fill_tx_q(int n)145     int fill_tx_q(int n) {
146         int count_wait;
147         int i, max;
148         size_t len;
149 
150         max = (n == 0) ? 1024 : n;
151 
152         for (count_wait = i = 0; i < max; i++) {
153             len = uct_ep_am_bcopy(sender_ep(), 0, mapped_buffer::pack, lbuf, 0);
154             if (len != lbuf->length()) {
155                 if (n == 0) {
156                     return 1;
157                 }
158                 count_wait++;
159             }
160         }
161         return count_wait;
162     }
163 
init_completion()164     void init_completion() {
165         m_comp.count = 2;
166         m_comp.func  = NULL;
167     }
168 
wait_for_completion(ucs_status_t status)169     void wait_for_completion(ucs_status_t status) {
170 
171         EXPECT_TRUE(UCS_INPROGRESS == status || UCS_OK == status);
172         if (status == UCS_OK) {
173             --m_comp.count;
174         }
175 
176         ucs_time_t deadline = ucs::get_deadline();
177         do {
178             short_progress_loop();
179         } while ((ucs_get_time() < deadline) && (m_comp.count > 1));
180         EXPECT_EQ(1, m_comp.count);
181     }
182 
183 protected:
184     mapped_buffer *lbuf, *rbuf;
185     uct_completion_t m_comp;
186     std::map< std::string, std::map< std::string, uint64_t > > cntr_init;
187 };
188 
189 
190 /* test basic stat counters:
191  * am, put, get, amo, flush and fence
192  */
193 UCS_TEST_SKIP_COND_P(test_uct_stats, am_short,
194                      !check_caps(UCT_IFACE_FLAG_AM_SHORT))
195 {
196     uint64_t hdr=0xdeadbeef, send_data=0xfeedf00d;
197     ucs_status_t status;
198 
199     init_bufs(0, sender().iface_attr().cap.am.max_short);
200 
201     status = uct_iface_set_am_handler(receiver().iface(), 0, am_handler,
202                                       0, UCT_CB_FLAG_ASYNC);
203     EXPECT_UCS_OK(status);
204 
205     UCT_TEST_CALL_AND_TRY_AGAIN(uct_ep_am_short(sender_ep(), 0, hdr, &send_data,
206                                                 sizeof(send_data)), status);
207     EXPECT_UCS_OK(status);
208 
209     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_AM, 1UL);
210     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_BYTES_SHORT,
211                 sizeof(hdr) + sizeof(send_data));
212     check_am_rx_counters(sizeof(hdr) + sizeof(send_data));
213 }
214 
215 UCS_TEST_SKIP_COND_P(test_uct_stats, am_bcopy,
216                      !check_caps(UCT_IFACE_FLAG_AM_BCOPY))
217 {
218     ssize_t v;
219     ucs_status_t status;
220 
221     init_bufs(0, sender().iface_attr().cap.am.max_bcopy);
222 
223     status = uct_iface_set_am_handler(receiver().iface(), 0, am_handler, 0, UCT_CB_FLAG_ASYNC);
224     EXPECT_UCS_OK(status);
225 
226     UCT_TEST_CALL_AND_TRY_AGAIN(uct_ep_am_bcopy(sender_ep(), 0, mapped_buffer::pack,
227                                                 lbuf, 0), v);
228     EXPECT_EQ((ssize_t)lbuf->length(), v);
229 
230     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_AM, 1UL);
231     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_BYTES_BCOPY,
232                 lbuf->length());
233     check_am_rx_counters(lbuf->length());
234 }
235 
236 UCS_TEST_SKIP_COND_P(test_uct_stats, am_zcopy,
237                      !check_caps(UCT_IFACE_FLAG_AM_ZCOPY))
238 {
239     ucs_status_t status;
240 
241     init_bufs(0, sender().iface_attr().cap.am.max_zcopy);
242 
243     status = uct_iface_set_am_handler(receiver().iface(), 0, am_handler, 0, UCT_CB_FLAG_ASYNC);
244     EXPECT_UCS_OK(status);
245 
246     UCS_TEST_GET_BUFFER_IOV(iov, iovcnt, lbuf->ptr(), lbuf->length(), lbuf->memh(),
247                             sender().iface_attr().cap.am.max_iov);
248 
249     UCT_TEST_CALL_AND_TRY_AGAIN(uct_ep_am_zcopy(sender_ep(), 0, 0, 0,
250                                                 iov, iovcnt, 0, NULL), status);
251     EXPECT_TRUE(UCS_INPROGRESS == status || UCS_OK == status);
252 
253     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_AM, 1UL);
254     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_BYTES_ZCOPY,
255                 lbuf->length());
256     check_am_rx_counters(lbuf->length());
257 }
258 
259 
260 UCS_TEST_SKIP_COND_P(test_uct_stats, put_short,
261                      !check_caps(UCT_IFACE_FLAG_PUT_SHORT))
262 {
263     uint64_t send_data=0xfeedf00d;
264     ucs_status_t status;
265 
266     init_bufs(0, sender().iface_attr().cap.put.max_short);
267 
268     UCT_TEST_CALL_AND_TRY_AGAIN(uct_ep_put_short(sender_ep(), &send_data, sizeof(send_data),
269                                                  rbuf->addr(), rbuf->rkey()), status);
270     EXPECT_UCS_OK(status);
271 
272     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_PUT, 1UL);
273     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_BYTES_SHORT,
274                 sizeof(send_data));
275 }
276 
277 UCS_TEST_SKIP_COND_P(test_uct_stats, put_bcopy,
278                      !check_caps(UCT_IFACE_FLAG_PUT_BCOPY))
279 {
280     ssize_t v;
281 
282     init_bufs(0, sender().iface_attr().cap.put.max_bcopy);
283 
284     UCT_TEST_CALL_AND_TRY_AGAIN(uct_ep_put_bcopy(sender_ep(), mapped_buffer::pack, lbuf,
285                                                  rbuf->addr(), rbuf->rkey()), v);
286     EXPECT_EQ((ssize_t)lbuf->length(), v);
287 
288     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_PUT, 1UL);
289     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_BYTES_BCOPY,
290                 lbuf->length());
291 }
292 
293 UCS_TEST_SKIP_COND_P(test_uct_stats, put_zcopy,
294                      !check_caps(UCT_IFACE_FLAG_PUT_ZCOPY))
295 {
296     ucs_status_t status;
297 
298     init_bufs(0, sender().iface_attr().cap.put.max_zcopy);
299 
300     UCS_TEST_GET_BUFFER_IOV(iov, iovcnt, lbuf->ptr(), lbuf->length(), lbuf->memh(),
301                             sender().iface_attr().cap.put.max_iov);
302 
303     UCT_TEST_CALL_AND_TRY_AGAIN(
304         uct_ep_put_zcopy(sender_ep(), iov, iovcnt, rbuf->addr(),
305                          rbuf->rkey(), 0), status);
306     EXPECT_TRUE(UCS_INPROGRESS == status || UCS_OK == status);
307 
308     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_PUT, 1UL);
309     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_BYTES_ZCOPY,
310                 lbuf->length());
311 }
312 
313 
314 UCS_TEST_SKIP_COND_P(test_uct_stats, get_bcopy,
315                      !check_caps(UCT_IFACE_FLAG_GET_BCOPY))
316 {
317     ucs_status_t status;
318 
319     init_bufs(0, sender().iface_attr().cap.get.max_bcopy);
320 
321     init_completion();
322     UCT_TEST_CALL_AND_TRY_AGAIN(
323         uct_ep_get_bcopy(sender_ep(), (uct_unpack_callback_t)memcpy,
324                          lbuf->ptr(), lbuf->length(),
325                          rbuf->addr(), rbuf->rkey(), &m_comp), status);
326     wait_for_completion(status);
327 
328     short_progress_loop();
329     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_GET, 1UL);
330     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_BYTES_BCOPY,
331                 lbuf->length());
332 }
333 
334 UCS_TEST_SKIP_COND_P(test_uct_stats, get_zcopy,
335                      !check_caps(UCT_IFACE_FLAG_GET_ZCOPY))
336 {
337     ucs_status_t status;
338 
339     init_bufs(sender().iface_attr().cap.get.min_zcopy,
340               sender().iface_attr().cap.get.max_zcopy);
341 
342     UCS_TEST_GET_BUFFER_IOV(iov, iovcnt, lbuf->ptr(), lbuf->length(), lbuf->memh(),
343                             sender().iface_attr().cap.get.max_iov);
344 
345     init_completion();
346     UCT_TEST_CALL_AND_TRY_AGAIN(
347         uct_ep_get_zcopy(sender_ep(), iov, iovcnt, rbuf->addr(),
348                          rbuf->rkey(), &m_comp), status);
349     wait_for_completion(status);
350 
351     short_progress_loop();
352     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_GET, 1UL);
353     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_BYTES_ZCOPY,
354                 lbuf->length());
355 }
356 
357 #define TEST_STATS_ATOMIC_POST(_op, _val) \
358 UCS_TEST_SKIP_COND_P(test_uct_stats, atomic_post_ ## _op ## _val, \
359                      !check_atomics(UCS_BIT(UCT_ATOMIC_OP_ ## _op), OP ## _val)) \
360 { \
361     ucs_status_t status; \
362     init_bufs(sizeof(uint##_val##_t), sizeof(uint##_val##_t)); \
363     status = uct_ep_atomic ##_val##_post(sender_ep(), (UCT_ATOMIC_OP_ ## _op), \
364                                          1, rbuf->addr(), rbuf->rkey()); \
365     EXPECT_UCS_OK(status); \
366     check_atomic_counters(); \
367 }
368 
369 TEST_STATS_ATOMIC_POST(ADD, 32)
370 TEST_STATS_ATOMIC_POST(ADD, 64)
371 TEST_STATS_ATOMIC_POST(AND, 32)
372 TEST_STATS_ATOMIC_POST(AND, 64)
373 TEST_STATS_ATOMIC_POST(OR,  32)
374 TEST_STATS_ATOMIC_POST(OR,  64)
375 TEST_STATS_ATOMIC_POST(XOR, 32)
376 TEST_STATS_ATOMIC_POST(XOR, 64)
377 
378 
379 #define TEST_STATS_ATOMIC_FETCH(_op, _val) \
380 UCS_TEST_SKIP_COND_P(test_uct_stats, atomic_fetch_## _op ## _val, \
381                      !check_atomics(UCS_BIT(UCT_ATOMIC_OP_ ## _op), FOP ## _val)) \
382 { \
383     ucs_status_t status; \
384     uint##_val##_t result; \
385     \
386     init_bufs(sizeof(result), sizeof(result)); \
387     \
388     init_completion(); \
389     status = uct_ep_atomic##_val##_fetch(sender_ep(), (UCT_ATOMIC_OP_ ## _op), 1, \
390                                          &result, rbuf->addr(), rbuf->rkey(), &m_comp); \
391     wait_for_completion(status); \
392     \
393     check_atomic_counters(); \
394 }
395 
396 TEST_STATS_ATOMIC_FETCH(ADD,  32)
397 TEST_STATS_ATOMIC_FETCH(ADD,  64)
398 TEST_STATS_ATOMIC_FETCH(AND,  32)
399 TEST_STATS_ATOMIC_FETCH(AND,  64)
400 TEST_STATS_ATOMIC_FETCH(OR,   32)
401 TEST_STATS_ATOMIC_FETCH(OR,   64)
402 TEST_STATS_ATOMIC_FETCH(XOR,  32)
403 TEST_STATS_ATOMIC_FETCH(XOR,  64)
404 TEST_STATS_ATOMIC_FETCH(SWAP, 32)
405 TEST_STATS_ATOMIC_FETCH(SWAP, 64)
406 
407 #define TEST_STATS_ATOMIC_CSWAP(val) \
408 UCS_TEST_SKIP_COND_P(test_uct_stats, atomic_cswap##val, \
409                      !check_atomics(UCS_BIT(UCT_ATOMIC_OP_CSWAP), FOP ## val)) \
410 { \
411     ucs_status_t status; \
412     uint##val##_t result; \
413     \
414     init_bufs(sizeof(result), sizeof(result)); \
415     \
416     init_completion(); \
417     UCT_TEST_CALL_AND_TRY_AGAIN( \
418         uct_ep_atomic_cswap##val (sender_ep(), 1, 2, rbuf->addr(), \
419                                   rbuf->rkey(), &result, &m_comp), \
420         status); \
421     wait_for_completion(status); \
422     \
423     check_atomic_counters(); \
424 }
425 
426 TEST_STATS_ATOMIC_CSWAP(32)
427 TEST_STATS_ATOMIC_CSWAP(64)
428 
UCS_TEST_P(test_uct_stats,flush)429 UCS_TEST_P(test_uct_stats, flush)
430 {
431     ucs_status_t status;
432 
433     if (sender_ep()) {
434         status = uct_ep_flush(sender_ep(), 0, NULL);
435         EXPECT_UCS_OK(status);
436         EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_FLUSH, 1Ul);
437         EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_FLUSH_WAIT, 0UL);
438     }
439 
440     status = uct_iface_flush(sender().iface(), 0, NULL);
441     EXPECT_UCS_OK(status);
442     EXPECT_STAT(sender, uct_iface, UCT_IFACE_STAT_FLUSH, 1UL);
443     EXPECT_STAT(sender, uct_iface, UCT_IFACE_STAT_FLUSH_WAIT, 0UL);
444 }
445 
UCS_TEST_P(test_uct_stats,fence)446 UCS_TEST_P(test_uct_stats, fence)
447 {
448     ucs_status_t status;
449 
450     if (sender_ep()) {
451         status = uct_ep_fence(sender_ep(), 0);
452         EXPECT_UCS_OK(status);
453         EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_FENCE, 1UL);
454     }
455 
456     status = uct_iface_fence(sender().iface(), 0);
457     EXPECT_UCS_OK(status);
458     EXPECT_STAT(sender, uct_iface, UCT_IFACE_STAT_FENCE, 1UL);
459 }
460 
461 /* flush test only check stats on tls with am_bcopy
462  * TODO: full test matrix
463  */
464 UCS_TEST_SKIP_COND_P(test_uct_stats, flush_wait_iface,
465                      !check_caps(UCT_IFACE_FLAG_AM_BCOPY))
466 {
467     uint64_t count_wait;
468     ucs_status_t status;
469 
470     init_bufs(0, sender().iface_attr().cap.am.max_bcopy);
471 
472     status = uct_iface_set_am_handler(receiver().iface(), 0, am_handler, 0, UCT_CB_FLAG_ASYNC);
473     EXPECT_UCS_OK(status);
474 
475     fill_tx_q(0);
476     count_wait = 0;
477     do {
478         status = uct_iface_flush(sender().iface(), 0, NULL);
479         if (status == UCS_INPROGRESS) {
480             count_wait++;
481         }
482         progress();
483     } while (status != UCS_OK);
484 
485     EXPECT_STAT(sender, uct_iface, UCT_IFACE_STAT_FLUSH, 1UL);
486     EXPECT_STAT(sender, uct_iface, UCT_IFACE_STAT_FLUSH_WAIT, count_wait);
487 }
488 
489 UCS_TEST_SKIP_COND_P(test_uct_stats, flush_wait_ep,
490                      !check_caps(UCT_IFACE_FLAG_AM_BCOPY))
491 {
492     uint64_t count_wait;
493     ucs_status_t status;
494 
495     init_bufs(0, sender().iface_attr().cap.am.max_bcopy);
496 
497     status = uct_iface_set_am_handler(receiver().iface(), 0, am_handler, 0, UCT_CB_FLAG_ASYNC);
498     EXPECT_UCS_OK(status);
499 
500     fill_tx_q(0);
501     count_wait = 0;
502     do {
503         status = uct_ep_flush(sender_ep(), 0, NULL);
504         if (status == UCS_INPROGRESS) {
505             count_wait++;
506         }
507         progress();
508     } while (status != UCS_OK);
509 
510     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_FLUSH, 1UL);
511     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_FLUSH_WAIT, count_wait);
512 }
513 
514 /* fence test only check stats on tls with am_bcopy
515  * TODO: full test matrix
516  */
517 UCS_TEST_SKIP_COND_P(test_uct_stats, fence_iface,
518                      !check_caps(UCT_IFACE_FLAG_AM_BCOPY))
519 {
520     ucs_status_t status;
521 
522     init_bufs(0, sender().iface_attr().cap.am.max_bcopy);
523 
524     status = uct_iface_set_am_handler(receiver().iface(), 0, am_handler, 0, UCT_CB_FLAG_ASYNC);
525     EXPECT_UCS_OK(status);
526 
527     fill_tx_q(0);
528 
529     status = uct_iface_fence(sender().iface(), 0);
530     EXPECT_UCS_OK(status);
531 
532     fill_tx_q(0);
533 
534     EXPECT_STAT(sender, uct_iface, UCT_IFACE_STAT_FENCE, 1UL);
535 }
536 
537 UCS_TEST_SKIP_COND_P(test_uct_stats, fence_ep,
538                      !check_caps(UCT_IFACE_FLAG_AM_BCOPY))
539 {
540     ucs_status_t status;
541 
542     init_bufs(0, sender().iface_attr().cap.am.max_bcopy);
543 
544     status = uct_iface_set_am_handler(receiver().iface(), 0, am_handler, 0, UCT_CB_FLAG_ASYNC);
545     EXPECT_UCS_OK(status);
546 
547     fill_tx_q(0);
548 
549     status = uct_ep_fence(sender_ep(), 0);
550     EXPECT_UCS_OK(status);
551 
552     fill_tx_q(0);
553 
554     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_FENCE, 1UL);
555 }
556 
557 UCS_TEST_SKIP_COND_P(test_uct_stats, tx_no_res,
558                      !check_caps(UCT_IFACE_FLAG_AM_BCOPY))
559 {
560     uint64_t count;
561     ucs_status_t status;
562 
563     init_bufs(0, sender().iface_attr().cap.am.max_bcopy);
564 
565     status = uct_iface_set_am_handler(receiver().iface(), 0, am_handler, 0, UCT_CB_FLAG_ASYNC);
566     EXPECT_UCS_OK(status);
567     count = fill_tx_q(1024);
568 
569     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_NO_RES, count);
570     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_AM, 1024 - count);
571 }
572 
573 UCS_TEST_SKIP_COND_P(test_uct_stats, pending_add,
574                      !check_caps(UCT_IFACE_FLAG_AM_BCOPY |
575                                  UCT_IFACE_FLAG_PENDING))
576 {
577     const size_t num_reqs = 5;
578     uct_pending_req_t p_reqs[num_reqs];
579     ssize_t len;
580 
581     init_bufs(0, sender().iface_attr().cap.am.max_bcopy);
582 
583     EXPECT_UCS_OK(uct_iface_set_am_handler(receiver().iface(), 0, am_handler, 0,
584                                            UCT_CB_FLAG_ASYNC));
585 
586     // Check that counter is not increased if pending_add returns NOT_OK
587     EXPECT_EQ(uct_ep_pending_add(sender().ep(0), &p_reqs[0], 0),
588               UCS_ERR_BUSY);
589     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_PENDING, 0UL);
590 
591     // Check that counter gets increased on every successfull pending_add returns NOT_OK
592     fill_tx_q(0);
593 
594     UCT_TEST_CALL_AND_TRY_AGAIN(
595         uct_ep_am_bcopy(sender_ep(), 0, mapped_buffer::pack,
596                         lbuf, 0), len);
597     if (len == (ssize_t)lbuf->length()) {
598         UCS_TEST_SKIP_R("Can't add to pending");
599     }
600 
601     for (size_t i = 0; i < num_reqs; ++i) {
602         p_reqs[i].func = NULL;
603         EXPECT_UCS_OK(uct_ep_pending_add(sender().ep(0), &p_reqs[i], 0));
604     }
605     uct_ep_pending_purge(sender().ep(0), purge_cb, NULL);
606 
607     EXPECT_STAT(sender, uct_ep, UCT_EP_STAT_PENDING, num_reqs);
608 }
609 
610 UCT_INSTANTIATE_TEST_CASE(test_uct_stats);
611 #endif
612