2 * Copyright (c) 2016 Intel Corporation.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
24 #include <rte_common.h>
26 #include <rte_errno.h>
27 #include <rte_launch.h>
28 #include <rte_cycles.h>
30 #include <rte_per_lcore.h>
31 #include <rte_lcore.h>
33 #include <tle_dring.h>
34 #include <rte_random.h>
36 #define OBJ_NUM UINT16_MAX
37 #define ITER_NUM (4 * OBJ_NUM)
56 * free memory allocated for drbs and for the ring itself.
59 fini_drb_ring(struct rte_ring *r)
64 while (rte_ring_dequeue(r, (void **)&drb) == 0)
72 * allocate drbs for specified number of objects, put them into the ring.
74 static struct rte_ring *
75 init_drb_ring(uint32_t num)
82 /* allocate and initialise rte_ring. */
84 n = rte_align32pow2(num);
85 sz = rte_ring_get_memsize(n);
89 printf("%s:%d(%u) failed to allocate %zu bytes;\n",
90 __func__, __LINE__, num, sz);
94 rte_ring_init(r, __func__, n, 0);
96 /* allocate drbs and put them into the ring. */
99 for (i = 0; i != num; i += k) {
100 k = rte_rand() % (UINT8_MAX + 1) + 1;
101 k = RTE_MIN(k, num - i);
102 sz = tle_drb_calc_size(k);
105 printf("%s:%d(%u) %u-th iteration: "
106 "failed to allocate %zu bytes;\n",
107 __func__, __LINE__, num, i, sz);
112 rte_ring_enqueue(r, drb);
116 printf("%s(%u) total %zu bytes allocated, number of drbs: %u;\n",
117 __func__, num, tsz, rte_ring_count(r));
122 * Each enqueued object will contain:
123 * [2-3]B: it's own sequence number.
124 * [0-1]B: next object sequence number, or UINT16_MAX.
127 test_fill_obj(uintptr_t obj[], uint32_t num)
131 for (i = 0; i != num - 1; i++)
132 obj[i] = i << 16 | (i + 1);
134 obj[i] = i << 16 | UINT16_MAX;
138 test_check_obj(uintptr_t obj[], uint32_t num)
140 uint32_t i, h, l, oh, ol;
143 l = obj[0] & UINT16_MAX;
145 if (h + 1 != l && l != UINT16_MAX)
151 for (i = 1; i != num; i++) {
154 ol = obj[i] & UINT16_MAX;
156 if (l != oh || (oh + 1 != ol && ol != UINT16_MAX))
168 test_dring_dequeue(struct tle_dring *dr, struct rte_ring *r, uint32_t num,
171 uint32_t i, k, lc, n, t;
172 struct tle_drb *drb[num];
178 /* dequeue objects. */
180 n = tle_dring_sc_dequeue(dr, (const void **)obj, num, drb, &k);
181 else if (type == MULTI)
182 n = tle_dring_mc_dequeue(dr, (const void **)obj, num, drb, &k);
189 /* check the data returned. */
190 t = test_check_obj(obj, n);
192 printf("%s:%d(%p, %u) at lcore %u: invalid dequeued object, "
193 "n=%u, idx=%u, obj=%#x, prev obj=%#x;\n",
194 __func__, __LINE__, dr, num, lc, n, t,
195 (uint32_t)obj[t], (t == 0) ? 0 : (uint32_t)obj[t - 1]);
199 /* check and free drbs. */
200 for (i = 0; i != k; i++) {
201 /* udata value for drb in use shouldn't be zero. */
202 if (drb[i]->udata == NULL) {
203 printf("error @ %s:%d(%p, %u) at lcore %u: "
204 "erroneous drb@%p={udata=%p, size=%u,};\n",
205 __func__, __LINE__, dr, num, lc, drb[i],
206 drb[i]->udata, drb[i]->size);
209 drb[i]->udata = NULL;
210 rte_ring_enqueue(r, drb[i]);
217 test_dring_enqueue(struct tle_dring *dr, struct rte_ring *r, uint32_t num,
220 uint32_t i, j, k, lc, nb;
221 struct tle_drb *drb[num];
226 /* prepare drbs to enqueue up to *num* objects. */
227 for (i = 0, j = 0; i != num; i += k, j++) {
229 if (rte_ring_dequeue(r, (void **)&drb[j]) != 0)
232 /* udata value for unused drb should be zero. */
233 if (drb[j]->udata != NULL) {
234 printf("error @ %s:%d(%p, %u) at lcore %u: "
235 "erroneous drb@%p={udata=%p, size=%u,};\n",
236 __func__, __LINE__, dr, num, lc, drb[j],
237 drb[j]->udata, drb[j]->size);
241 /* update udata value with current lcore id. */
242 drb[j]->udata = (void *)(uintptr_t)(lc + 1);
244 k = RTE_MIN(k, num - i);
247 /* no free drbs left. */
251 /* fill objects to enqueue. */
252 test_fill_obj(obj, i);
254 /* enqueue into the dring. */
257 k = tle_dring_sp_enqueue(dr, (const void **)obj, i, drb, &nb);
258 else if (type == MULTI)
259 k = tle_dring_mp_enqueue(dr, (const void **)obj, i, drb, &nb);
264 printf("%s:%d(%p, %p, %u): failed to enqueue %u objects;\n",
265 __func__, __LINE__, dr, r, num, i);
268 /* free unused drbs */
269 for (i = j - nb; i != j; i++) {
270 if ((uintptr_t)drb[i]->udata != lc + 1) {
271 printf("error @ %s:%d(%p, %u) at lcore %u: "
272 "erroneous drb@%p={udata=%p, size=%u,};\n",
273 __func__, __LINE__, dr, num, lc, drb[i],
274 drb[i]->udata, drb[i]->size);
277 drb[i]->udata = NULL;
278 rte_ring_enqueue(r, drb[i]);
285 test_dring_enq_deq(struct dring_arg *arg)
295 for (i = 0; i != arg->iter; i++) {
297 /* try to enqueue random number of objects. */
298 if (arg->enq_type != NONE) {
299 n = rte_rand() % (UINT8_MAX + 1);
300 rc = test_dring_enqueue(arg->dr, arg->r, n,
307 /* try to dequeue random number of objects. */
308 if (arg->deq_type != NONE) {
309 n = rte_rand() % (UINT8_MAX + 1);
310 rc = test_dring_dequeue(arg->dr, arg->r, n,
321 /* dequeue remaining objects. */
322 while (arg->deq_type != NONE && arg->enq != arg->deq) {
324 /* try to dequeue random number of objects. */
325 n = rte_rand() % (UINT8_MAX + 1) + 1;
326 rc = test_dring_dequeue(arg->dr, arg->r, n, arg->deq_type);
332 printf("%s:%d(lcore=%u, enq_type=%d, deq_type=%d): "
333 "%u objects enqueued, %u objects dequeued\n",
334 __func__, __LINE__, lc, arg->enq_type, arg->deq_type,
340 * enqueue/dequeue by single thread.
348 struct dring_arg arg;
350 printf("%s started;\n", __func__);
352 tle_dring_reset(&dr);
353 r = init_drb_ring(OBJ_NUM);
357 tle_dring_dump(stdout, 1, &dr);
359 memset(&arg, 0, sizeof(arg));
363 arg.enq_type = SINGLE;
364 arg.deq_type = SINGLE;
365 rc = test_dring_enq_deq(&arg);
367 rc = (rc != 0) ? rc : (arg.enq != arg.deq);
368 printf("%s finished with status: %s(%d);\n",
369 __func__, strerror(-rc), rc);
371 tle_dring_dump(stdout, rc != 0, &dr);
378 test_dring_worker(void *arg)
382 p = (struct dring_arg *)arg;
383 return test_dring_enq_deq(p);
387 * enqueue/dequeue by multiple threads.
390 test_dring_mt(int32_t master_enq_type, int32_t master_deq_type,
391 int32_t slave_enq_type, int32_t slave_deq_type)
398 struct dring_arg arg[RTE_MAX_LCORE];
400 tle_dring_reset(&dr);
401 r = init_drb_ring(OBJ_NUM);
405 memset(arg, 0, sizeof(arg));
407 /* launch on all slaves */
408 RTE_LCORE_FOREACH_SLAVE(lc) {
411 arg[lc].iter = ITER_NUM;
412 arg[lc].enq_type = slave_enq_type;
413 arg[lc].deq_type = slave_deq_type;
414 rte_eal_remote_launch(test_dring_worker, &arg[lc], lc);
417 /* launch on master */
421 arg[lc].iter = ITER_NUM;
422 arg[lc].enq_type = master_enq_type;
423 arg[lc].deq_type = master_deq_type;
424 rc = test_dring_worker(&arg[lc]);
428 /* wait for slaves. */
429 RTE_LCORE_FOREACH_SLAVE(lc) {
430 rc |= rte_eal_wait_lcore(lc);
435 printf("%s:%d: total %" PRIu64 " objects enqueued, %"
436 PRIu64 " objects dequeued\n",
437 __func__, __LINE__, enq, deq);
439 rc = (rc != 0) ? rc : (enq != deq);
441 tle_dring_dump(stdout, 1, &dr);
448 test_dring_mp_mc(void)
452 printf("%s started;\n", __func__);
453 rc = test_dring_mt(MULTI, MULTI, MULTI, MULTI);
454 printf("%s finished with status: %s(%d);\n",
455 __func__, strerror(-rc), rc);
460 test_dring_mp_sc(void)
464 printf("%s started;\n", __func__);
465 rc = test_dring_mt(MULTI, SINGLE, MULTI, NONE);
466 printf("%s finished with status: %s(%d);\n",
467 __func__, strerror(-rc), rc);
472 test_dring_sp_mc(void)
476 printf("%s started;\n", __func__);
477 rc = test_dring_mt(SINGLE, MULTI, NONE, MULTI);
478 printf("%s finished with status: %s(%d);\n",
479 __func__, strerror(-rc), rc);
488 rc = test_dring_st();
492 rc = test_dring_mp_mc();
496 rc = test_dring_mp_sc();
500 rc = test_dring_sp_mc();
508 main(int argc, char *argv[])
512 rc = rte_eal_init(argc, argv);
514 rte_exit(EXIT_FAILURE,
515 "%s: rte_eal_init failed with error code: %d\n",
520 printf("TEST FAILED\n");