1 /**
2 * Copyright (C) Mellanox Technologies Ltd. 2001-2015. ALL RIGHTS RESERVED.
3 *
4 * See file LICENSE for terms.
5 */
6
7 #include "ud_base.h"
8
9 #include <uct/uct_test.h>
10
11 extern "C" {
12 #include <ucs/time/time.h>
13 #include <ucs/datastruct/queue.h>
14 #include <ucs/datastruct/ptr_array.h>
15 #include <uct/ib/ud/base/ud_ep.h>
16 #include <uct/ib/ud/base/ud_iface.h>
17 }
18
19
20 class test_ud_timer : public ud_base_test {
21 public:
22 /* ack while doing retransmit */
23 static int packet_count, rx_limit;
rx_npackets(uct_ud_ep_t * ep,uct_ud_neth_t * neth)24 static ucs_status_t rx_npackets(uct_ud_ep_t *ep, uct_ud_neth_t *neth)
25 {
26 if (packet_count++ < rx_limit) {
27 return UCS_OK;
28 }
29 else {
30 return UCS_ERR_INVALID_PARAM;
31 }
32 }
33 /* test slow timer and restransmit */
34 static int tick_count;
35
tick_counter(uct_ud_ep_t * ep,uct_ud_neth_t * neth)36 static ucs_status_t tick_counter(uct_ud_ep_t *ep, uct_ud_neth_t *neth)
37 {
38 uct_ud_iface_t *iface = ucs_derived_of(ep->super.super.iface,
39 uct_ud_iface_t);
40
41 /* hack to disable retransmit */
42 ep->tx.send_time = ucs_twheel_get_time(&iface->tx.timer);
43 tick_count++;
44 return UCS_OK;
45 }
46
drop_packet(uct_ud_ep_t * ep,uct_ud_neth_t * neth)47 static ucs_status_t drop_packet(uct_ud_ep_t *ep, uct_ud_neth_t *neth)
48 {
49 return UCS_ERR_INVALID_PARAM;
50 }
51
wait_for_rx_sn(unsigned sn)52 void wait_for_rx_sn(unsigned sn)
53 {
54 ucs_time_t deadline = ucs_get_time() +
55 ucs_time_from_sec(10) * ucs::test_time_multiplier();
56 while ((ucs_get_time() < deadline) && (ucs_frag_list_sn(&ep(m_e2)->rx.ooo_pkts) < sn)) {
57 usleep(1000);
58 }
59 }
60
wait_for_ep_destroyed(uct_ud_iface_t * iface,uint32_t ep_idx)61 void wait_for_ep_destroyed(uct_ud_iface_t *iface, uint32_t ep_idx)
62 {
63 ucs_time_t deadline = ucs_get_time() +
64 ucs_time_from_sec(60) * ucs::test_time_multiplier();
65 void *ud_ep_tmp GTEST_ATTRIBUTE_UNUSED_;
66
67 while ((ucs_get_time() < deadline) &&
68 ucs_ptr_array_lookup(&iface->eps, ep_idx, ud_ep_tmp)) {
69 usleep(1000);
70 }
71 }
72 };
73
74 int test_ud_timer::rx_limit = 10;
75 int test_ud_timer::packet_count = 0;
76 int test_ud_timer::tick_count = 0;
77
78
79 /* single packet received without progress */
80 UCS_TEST_SKIP_COND_P(test_ud_timer, tx1,
81 !check_caps(UCT_IFACE_FLAG_PUT_SHORT)) {
82 connect();
83 EXPECT_UCS_OK(tx(m_e1));
84 wait_for_rx_sn(1);
85 EXPECT_EQ(2, ep(m_e1)->tx.psn);
86 EXPECT_EQ(1, ucs_frag_list_sn(&ep(m_e2)->rx.ooo_pkts));
87 }
88
89 /* multiple packets received without progress */
90 UCS_TEST_SKIP_COND_P(test_ud_timer, txn,
91 !check_caps(UCT_IFACE_FLAG_PUT_SHORT)) {
92 unsigned i, N = 42;
93
94 connect();
95 set_tx_win(m_e1, 1024);
96 for (i = 0; i < N; i++) {
97 EXPECT_UCS_OK(tx(m_e1));
98 }
99 wait_for_rx_sn(N);
100 EXPECT_EQ(N+1, ep(m_e1)->tx.psn);
101 EXPECT_EQ(N, ucs_frag_list_sn(&ep(m_e2)->rx.ooo_pkts));
102 }
103
104 UCS_TEST_P(test_ud_timer, ep_destroy, "UD_TIMEOUT=1s") {
105 void *ud_ep_tmp GTEST_ATTRIBUTE_UNUSED_;
106 connect();
107
108 uct_ud_ep_t *ud_ep = ep(m_e1);
109 uct_ud_iface_t *iface = ucs_derived_of(ud_ep->super.super.iface,
110 uct_ud_iface_t);
111 uint32_t ep_idx = ud_ep->ep_id;
112 EXPECT_TRUE(ucs_ptr_array_lookup(&iface->eps, ep_idx, ud_ep_tmp));
113
114 m_e1->destroy_eps();
115 wait_for_ep_destroyed(iface, ep_idx);
116 EXPECT_FALSE(ucs_ptr_array_lookup(&iface->eps, ep_idx, ud_ep_tmp));
117 }
118
UCS_TEST_P(test_ud_timer,backoff_config)119 UCS_TEST_P(test_ud_timer, backoff_config) {
120 /* check minimum allowed value */
121 ASSERT_UCS_OK(uct_config_modify(m_iface_config,
122 "UD_TIMER_BACKOFF",
123 ucs::to_string(UCT_UD_MIN_TIMER_TIMER_BACKOFF).c_str()));
124 entity *e = uct_test::create_entity(0);
125 m_entities.push_back(e);
126
127 {
128 /* iface creation should fail with back off value less than
129 * UCT_UD_MIN_TIMER_TIMER_BACKOFF */
130 ASSERT_UCS_OK(uct_config_modify(m_iface_config,
131 "UD_TIMER_BACKOFF",
132 ucs::to_string(UCT_UD_MIN_TIMER_TIMER_BACKOFF - 0.1).c_str()));
133 scoped_log_handler wrap_err(wrap_errors_logger);
134 uct_iface_h iface;
135 ucs_status_t status = uct_iface_open(e->md(), e->worker(),
136 &e->iface_params(),
137 m_iface_config, &iface);
138 EXPECT_EQ(UCS_ERR_INVALID_PARAM, status);
139 EXPECT_EQ(NULL, iface);
140 }
141 }
142
143 #if UCT_UD_EP_DEBUG_HOOKS
144 /* no traffic - no ticks */
UCS_TEST_P(test_ud_timer,tick1)145 UCS_TEST_P(test_ud_timer, tick1) {
146 connect();
147 tick_count = 0;
148 ep(m_e1)->timer_hook = tick_counter;
149 twait(500);
150 EXPECT_EQ(0, tick_count);
151 }
152
153 /* ticks while tx window is not empty */
154 UCS_TEST_SKIP_COND_P(test_ud_timer, tick2,
155 !check_caps(UCT_IFACE_FLAG_PUT_SHORT)) {
156 connect();
157 tick_count = 0;
158 ep(m_e1)->timer_hook = tick_counter;
159 EXPECT_UCS_OK(tx(m_e1));
160 twait(500);
161 EXPECT_LT(0, tick_count);
162 }
163
164 /* retransmit one packet */
165
166 UCS_TEST_SKIP_COND_P(test_ud_timer, retransmit1,
167 !check_caps(UCT_IFACE_FLAG_PUT_SHORT)) {
168 connect();
169 ep(m_e2)->rx.rx_hook = drop_packet;
170 EXPECT_UCS_OK(tx(m_e1));
171 short_progress_loop();
172 EXPECT_EQ(0, ucs_frag_list_sn(&ep(m_e2)->rx.ooo_pkts));
173 ep(m_e2)->rx.rx_hook = uct_ud_ep_null_hook;
174 EXPECT_EQ(2, ep(m_e1)->tx.psn);
175 wait_for_rx_sn(1);
176 EXPECT_EQ(2, ep(m_e1)->tx.psn);
177 EXPECT_EQ(1, ucs_frag_list_sn(&ep(m_e2)->rx.ooo_pkts));
178 }
179
180 /* retransmit many packets */
181 UCS_TEST_SKIP_COND_P(test_ud_timer, retransmitn,
182 !check_caps(UCT_IFACE_FLAG_PUT_SHORT)) {
183
184 unsigned i, N = 42;
185
186 connect();
187 set_tx_win(m_e1, 1024);
188 ep(m_e2)->rx.rx_hook = drop_packet;
189 for (i = 0; i < N; i++) {
190 EXPECT_UCS_OK(tx(m_e1));
191 }
192 short_progress_loop();
193 EXPECT_EQ(0, ucs_frag_list_sn(&ep(m_e2)->rx.ooo_pkts));
194 ep(m_e2)->rx.rx_hook = uct_ud_ep_null_hook;
195 EXPECT_EQ(N+1, ep(m_e1)->tx.psn);
196 wait_for_rx_sn(N);
197 EXPECT_EQ(N+1, ep(m_e1)->tx.psn);
198 EXPECT_EQ(N, ucs_frag_list_sn(&ep(m_e2)->rx.ooo_pkts));
199 }
200
201
202 UCS_TEST_SKIP_COND_P(test_ud_timer, partial_drop,
203 !check_caps(UCT_IFACE_FLAG_PUT_SHORT)) {
204
205 unsigned i, N = 24;
206 int orig_avail;
207
208 connect();
209 set_tx_win(m_e1, 1024);
210 packet_count = 0;
211 rx_limit = 10;
212 ep(m_e2)->rx.rx_hook = rx_npackets;
213 for (i = 0; i < N; i++) {
214 EXPECT_UCS_OK(tx(m_e1));
215 }
216 short_progress_loop();
217 EXPECT_EQ(rx_limit, ucs_frag_list_sn(&ep(m_e2)->rx.ooo_pkts));
218 ep(m_e2)->rx.rx_hook = uct_ud_ep_null_hook;
219 EXPECT_EQ(N+1, ep(m_e1)->tx.psn);
220 orig_avail = iface(m_e1)->tx.available;
221 /* allow only 6 outgoing packets. It will allow to get ack
222 * from receiver
223 */
224 iface(m_e1)->tx.available = 6;
225 twait(500);
226 iface(m_e1)->tx.available = orig_avail-6;
227 short_progress_loop();
228
229 EXPECT_EQ(N+1, ep(m_e1)->tx.psn);
230 wait_for_rx_sn(N);
231 EXPECT_EQ(N, ucs_frag_list_sn(&ep(m_e2)->rx.ooo_pkts));
232 }
233 #endif
234
235 UCT_INSTANTIATE_UD_TEST_CASE(test_ud_timer)
236