1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <string.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <stdint.h> 38 #include <inttypes.h> 39 #include <stdarg.h> 40 #include <errno.h> 41 #include <sys/queue.h> 42 43 #include <rte_common.h> 44 #include <rte_log.h> 45 #include <rte_debug.h> 46 #include <rte_memory.h> 47 #include <rte_memzone.h> 48 #include <rte_launch.h> 49 #include <rte_cycles.h> 50 #include <rte_eal.h> 51 #include <rte_per_lcore.h> 52 #include <rte_lcore.h> 53 #include <rte_atomic.h> 54 #include <rte_branch_prediction.h> 55 #include <rte_ring.h> 56 #include <rte_mempool.h> 57 #include <rte_spinlock.h> 58 #include <rte_malloc.h> 59 60 #include "test.h" 61 62 /* 63 * Mempool 64 * ======= 65 * 66 * Basic tests: done on one core with and without cache: 67 * 68 * - Get one object, put one object 69 * - Get two objects, put two objects 70 * - Get all objects, test that their content is not modified and 71 * put them back in the pool. 72 */ 73 74 #define MEMPOOL_ELT_SIZE 2048 75 #define MAX_KEEP 16 76 #define MEMPOOL_SIZE ((rte_lcore_count()*(MAX_KEEP+RTE_MEMPOOL_CACHE_MAX_SIZE))-1) 77 78 #define LOG_ERR() printf("test failed at %s():%d\n", __func__, __LINE__) 79 #define RET_ERR() do { \ 80 LOG_ERR(); \ 81 return -1; \ 82 } while (0) 83 #define GOTO_ERR(var, label) do { \ 84 LOG_ERR(); \ 85 var = -1; \ 86 goto label; \ 87 } while (0) 88 89 static rte_atomic32_t synchro; 90 91 /* 92 * save the object number in the first 4 bytes of object data. All 93 * other bytes are set to 0. 94 */ 95 static void 96 my_obj_init(struct rte_mempool *mp, __attribute__((unused)) void *arg, 97 void *obj, unsigned i) 98 { 99 uint32_t *objnum = obj; 100 101 memset(obj, 0, mp->elt_size); 102 *objnum = i; 103 } 104 105 /* basic tests (done on one core) */ 106 static int 107 test_mempool_basic(struct rte_mempool *mp, int use_external_cache) 108 { 109 uint32_t *objnum; 110 void **objtable; 111 void *obj, *obj2; 112 char *obj_data; 113 int ret = 0; 114 unsigned i, j; 115 int offset; 116 struct rte_mempool_cache *cache; 117 118 if (use_external_cache) { 119 /* Create a user-owned mempool cache. */ 120 cache = rte_mempool_cache_create(RTE_MEMPOOL_CACHE_MAX_SIZE, 121 SOCKET_ID_ANY); 122 if (cache == NULL) 123 RET_ERR(); 124 } else { 125 /* May be NULL if cache is disabled. */ 126 cache = rte_mempool_default_cache(mp, rte_lcore_id()); 127 } 128 129 /* dump the mempool status */ 130 rte_mempool_dump(stdout, mp); 131 132 printf("get an object\n"); 133 if (rte_mempool_generic_get(mp, &obj, 1, cache, 0) < 0) 134 GOTO_ERR(ret, out); 135 rte_mempool_dump(stdout, mp); 136 137 /* tests that improve coverage */ 138 printf("get object count\n"); 139 /* We have to count the extra caches, one in this case. */ 140 offset = use_external_cache ? 1 * cache->len : 0; 141 if (rte_mempool_avail_count(mp) + offset != MEMPOOL_SIZE - 1) 142 GOTO_ERR(ret, out); 143 144 printf("get private data\n"); 145 if (rte_mempool_get_priv(mp) != (char *)mp + 146 MEMPOOL_HEADER_SIZE(mp, mp->cache_size)) 147 GOTO_ERR(ret, out); 148 149 #ifndef RTE_EXEC_ENV_BSDAPP /* rte_mem_virt2phy() not supported on bsd */ 150 printf("get physical address of an object\n"); 151 if (rte_mempool_virt2phy(mp, obj) != rte_mem_virt2phy(obj)) 152 GOTO_ERR(ret, out); 153 #endif 154 155 printf("put the object back\n"); 156 rte_mempool_generic_put(mp, &obj, 1, cache, 0); 157 rte_mempool_dump(stdout, mp); 158 159 printf("get 2 objects\n"); 160 if (rte_mempool_generic_get(mp, &obj, 1, cache, 0) < 0) 161 GOTO_ERR(ret, out); 162 if (rte_mempool_generic_get(mp, &obj2, 1, cache, 0) < 0) { 163 rte_mempool_generic_put(mp, &obj, 1, cache, 0); 164 GOTO_ERR(ret, out); 165 } 166 rte_mempool_dump(stdout, mp); 167 168 printf("put the objects back\n"); 169 rte_mempool_generic_put(mp, &obj, 1, cache, 0); 170 rte_mempool_generic_put(mp, &obj2, 1, cache, 0); 171 rte_mempool_dump(stdout, mp); 172 173 /* 174 * get many objects: we cannot get them all because the cache 175 * on other cores may not be empty. 176 */ 177 objtable = malloc(MEMPOOL_SIZE * sizeof(void *)); 178 if (objtable == NULL) 179 GOTO_ERR(ret, out); 180 181 for (i = 0; i < MEMPOOL_SIZE; i++) { 182 if (rte_mempool_generic_get(mp, &objtable[i], 1, cache, 0) < 0) 183 break; 184 } 185 186 /* 187 * for each object, check that its content was not modified, 188 * and put objects back in pool 189 */ 190 while (i--) { 191 obj = objtable[i]; 192 obj_data = obj; 193 objnum = obj; 194 if (*objnum > MEMPOOL_SIZE) { 195 printf("bad object number(%d)\n", *objnum); 196 ret = -1; 197 break; 198 } 199 for (j = sizeof(*objnum); j < mp->elt_size; j++) { 200 if (obj_data[j] != 0) 201 ret = -1; 202 } 203 204 rte_mempool_generic_put(mp, &objtable[i], 1, cache, 0); 205 } 206 207 free(objtable); 208 if (ret == -1) 209 printf("objects were modified!\n"); 210 211 out: 212 if (use_external_cache) { 213 rte_mempool_cache_flush(cache, mp); 214 rte_mempool_cache_free(cache); 215 } 216 217 return ret; 218 } 219 220 static int test_mempool_creation_with_exceeded_cache_size(void) 221 { 222 struct rte_mempool *mp_cov; 223 224 mp_cov = rte_mempool_create("test_mempool_cache_too_big", 225 MEMPOOL_SIZE, 226 MEMPOOL_ELT_SIZE, 227 RTE_MEMPOOL_CACHE_MAX_SIZE + 32, 0, 228 NULL, NULL, 229 my_obj_init, NULL, 230 SOCKET_ID_ANY, 0); 231 232 if (mp_cov != NULL) { 233 rte_mempool_free(mp_cov); 234 RET_ERR(); 235 } 236 237 return 0; 238 } 239 240 static struct rte_mempool *mp_spsc; 241 static rte_spinlock_t scsp_spinlock; 242 static void *scsp_obj_table[MAX_KEEP]; 243 244 /* 245 * single producer function 246 */ 247 static int test_mempool_single_producer(void) 248 { 249 unsigned int i; 250 void *obj = NULL; 251 uint64_t start_cycles, end_cycles; 252 uint64_t duration = rte_get_timer_hz() / 4; 253 254 start_cycles = rte_get_timer_cycles(); 255 while (1) { 256 end_cycles = rte_get_timer_cycles(); 257 /* duration uses up, stop producing */ 258 if (start_cycles + duration < end_cycles) 259 break; 260 rte_spinlock_lock(&scsp_spinlock); 261 for (i = 0; i < MAX_KEEP; i ++) { 262 if (NULL != scsp_obj_table[i]) { 263 obj = scsp_obj_table[i]; 264 break; 265 } 266 } 267 rte_spinlock_unlock(&scsp_spinlock); 268 if (i >= MAX_KEEP) { 269 continue; 270 } 271 if (rte_mempool_from_obj(obj) != mp_spsc) { 272 printf("obj not owned by this mempool\n"); 273 RET_ERR(); 274 } 275 rte_mempool_put(mp_spsc, obj); 276 rte_spinlock_lock(&scsp_spinlock); 277 scsp_obj_table[i] = NULL; 278 rte_spinlock_unlock(&scsp_spinlock); 279 } 280 281 return 0; 282 } 283 284 /* 285 * single consumer function 286 */ 287 static int test_mempool_single_consumer(void) 288 { 289 unsigned int i; 290 void * obj; 291 uint64_t start_cycles, end_cycles; 292 uint64_t duration = rte_get_timer_hz() / 8; 293 294 start_cycles = rte_get_timer_cycles(); 295 while (1) { 296 end_cycles = rte_get_timer_cycles(); 297 /* duration uses up, stop consuming */ 298 if (start_cycles + duration < end_cycles) 299 break; 300 rte_spinlock_lock(&scsp_spinlock); 301 for (i = 0; i < MAX_KEEP; i ++) { 302 if (NULL == scsp_obj_table[i]) 303 break; 304 } 305 rte_spinlock_unlock(&scsp_spinlock); 306 if (i >= MAX_KEEP) 307 continue; 308 if (rte_mempool_get(mp_spsc, &obj) < 0) 309 break; 310 rte_spinlock_lock(&scsp_spinlock); 311 scsp_obj_table[i] = obj; 312 rte_spinlock_unlock(&scsp_spinlock); 313 } 314 315 return 0; 316 } 317 318 /* 319 * test function for mempool test based on singple consumer and single producer, 320 * can run on one lcore only 321 */ 322 static int 323 test_mempool_launch_single_consumer(__attribute__((unused)) void *arg) 324 { 325 return test_mempool_single_consumer(); 326 } 327 328 static void 329 my_mp_init(struct rte_mempool *mp, __attribute__((unused)) void *arg) 330 { 331 printf("mempool name is %s\n", mp->name); 332 /* nothing to be implemented here*/ 333 return ; 334 } 335 336 /* 337 * it tests the mempool operations based on singple producer and single consumer 338 */ 339 static int 340 test_mempool_sp_sc(void) 341 { 342 int ret = 0; 343 unsigned lcore_id = rte_lcore_id(); 344 unsigned lcore_next; 345 346 /* create a mempool with single producer/consumer ring */ 347 if (mp_spsc == NULL) { 348 mp_spsc = rte_mempool_create("test_mempool_sp_sc", MEMPOOL_SIZE, 349 MEMPOOL_ELT_SIZE, 0, 0, 350 my_mp_init, NULL, 351 my_obj_init, NULL, 352 SOCKET_ID_ANY, 353 MEMPOOL_F_NO_CACHE_ALIGN | MEMPOOL_F_SP_PUT | 354 MEMPOOL_F_SC_GET); 355 if (mp_spsc == NULL) 356 RET_ERR(); 357 } 358 if (rte_mempool_lookup("test_mempool_sp_sc") != mp_spsc) { 359 printf("Cannot lookup mempool from its name\n"); 360 rte_mempool_free(mp_spsc); 361 RET_ERR(); 362 } 363 lcore_next = rte_get_next_lcore(lcore_id, 0, 1); 364 if (lcore_next >= RTE_MAX_LCORE) { 365 rte_mempool_free(mp_spsc); 366 RET_ERR(); 367 } 368 if (rte_eal_lcore_role(lcore_next) != ROLE_RTE) { 369 rte_mempool_free(mp_spsc); 370 RET_ERR(); 371 } 372 rte_spinlock_init(&scsp_spinlock); 373 memset(scsp_obj_table, 0, sizeof(scsp_obj_table)); 374 rte_eal_remote_launch(test_mempool_launch_single_consumer, NULL, 375 lcore_next); 376 if (test_mempool_single_producer() < 0) 377 ret = -1; 378 379 if (rte_eal_wait_lcore(lcore_next) < 0) 380 ret = -1; 381 rte_mempool_free(mp_spsc); 382 383 return ret; 384 } 385 386 /* 387 * it tests some more basic of mempool 388 */ 389 static int 390 test_mempool_basic_ex(struct rte_mempool *mp) 391 { 392 unsigned i; 393 void **obj; 394 void *err_obj; 395 int ret = -1; 396 397 if (mp == NULL) 398 return ret; 399 400 obj = rte_calloc("test_mempool_basic_ex", MEMPOOL_SIZE, 401 sizeof(void *), 0); 402 if (obj == NULL) { 403 printf("test_mempool_basic_ex fail to rte_malloc\n"); 404 return ret; 405 } 406 printf("test_mempool_basic_ex now mempool (%s) has %u free entries\n", 407 mp->name, rte_mempool_in_use_count(mp)); 408 if (rte_mempool_full(mp) != 1) { 409 printf("test_mempool_basic_ex the mempool should be full\n"); 410 goto fail_mp_basic_ex; 411 } 412 413 for (i = 0; i < MEMPOOL_SIZE; i ++) { 414 if (rte_mempool_get(mp, &obj[i]) < 0) { 415 printf("test_mp_basic_ex fail to get object for [%u]\n", 416 i); 417 goto fail_mp_basic_ex; 418 } 419 } 420 if (rte_mempool_get(mp, &err_obj) == 0) { 421 printf("test_mempool_basic_ex get an impossible obj\n"); 422 goto fail_mp_basic_ex; 423 } 424 printf("number: %u\n", i); 425 if (rte_mempool_empty(mp) != 1) { 426 printf("test_mempool_basic_ex the mempool should be empty\n"); 427 goto fail_mp_basic_ex; 428 } 429 430 for (i = 0; i < MEMPOOL_SIZE; i++) 431 rte_mempool_put(mp, obj[i]); 432 433 if (rte_mempool_full(mp) != 1) { 434 printf("test_mempool_basic_ex the mempool should be full\n"); 435 goto fail_mp_basic_ex; 436 } 437 438 ret = 0; 439 440 fail_mp_basic_ex: 441 if (obj != NULL) 442 rte_free((void *)obj); 443 444 return ret; 445 } 446 447 static int 448 test_mempool_same_name_twice_creation(void) 449 { 450 struct rte_mempool *mp_tc, *mp_tc2; 451 452 mp_tc = rte_mempool_create("test_mempool_same_name", MEMPOOL_SIZE, 453 MEMPOOL_ELT_SIZE, 0, 0, 454 NULL, NULL, 455 NULL, NULL, 456 SOCKET_ID_ANY, 0); 457 458 if (mp_tc == NULL) 459 RET_ERR(); 460 461 mp_tc2 = rte_mempool_create("test_mempool_same_name", MEMPOOL_SIZE, 462 MEMPOOL_ELT_SIZE, 0, 0, 463 NULL, NULL, 464 NULL, NULL, 465 SOCKET_ID_ANY, 0); 466 467 if (mp_tc2 != NULL) { 468 rte_mempool_free(mp_tc); 469 rte_mempool_free(mp_tc2); 470 RET_ERR(); 471 } 472 473 rte_mempool_free(mp_tc); 474 return 0; 475 } 476 477 /* 478 * BAsic test for mempool_xmem functions. 479 */ 480 static int 481 test_mempool_xmem_misc(void) 482 { 483 uint32_t elt_num, total_size; 484 size_t sz; 485 ssize_t usz; 486 487 elt_num = MAX_KEEP; 488 total_size = rte_mempool_calc_obj_size(MEMPOOL_ELT_SIZE, 0, NULL); 489 sz = rte_mempool_xmem_size(elt_num, total_size, MEMPOOL_PG_SHIFT_MAX); 490 491 usz = rte_mempool_xmem_usage(NULL, elt_num, total_size, 0, 1, 492 MEMPOOL_PG_SHIFT_MAX); 493 494 if (sz != (size_t)usz) { 495 printf("failure @ %s: rte_mempool_xmem_usage(%u, %u) " 496 "returns: %#zx, while expected: %#zx;\n", 497 __func__, elt_num, total_size, sz, (size_t)usz); 498 return -1; 499 } 500 501 return 0; 502 } 503 504 static int 505 test_mempool(void) 506 { 507 struct rte_mempool *mp_cache = NULL; 508 struct rte_mempool *mp_nocache = NULL; 509 struct rte_mempool *mp_ext = NULL; 510 struct rte_mempool *mp_stack = NULL; 511 512 rte_atomic32_init(&synchro); 513 514 /* create a mempool (without cache) */ 515 mp_nocache = rte_mempool_create("test_nocache", MEMPOOL_SIZE, 516 MEMPOOL_ELT_SIZE, 0, 0, 517 NULL, NULL, 518 my_obj_init, NULL, 519 SOCKET_ID_ANY, 0); 520 521 if (mp_nocache == NULL) { 522 printf("cannot allocate mp_nocache mempool\n"); 523 goto err; 524 } 525 526 /* create a mempool (with cache) */ 527 mp_cache = rte_mempool_create("test_cache", MEMPOOL_SIZE, 528 MEMPOOL_ELT_SIZE, 529 RTE_MEMPOOL_CACHE_MAX_SIZE, 0, 530 NULL, NULL, 531 my_obj_init, NULL, 532 SOCKET_ID_ANY, 0); 533 534 if (mp_cache == NULL) { 535 printf("cannot allocate mp_cache mempool\n"); 536 goto err; 537 } 538 539 /* create a mempool with an external handler */ 540 mp_stack = rte_mempool_create_empty("test_stack", 541 MEMPOOL_SIZE, 542 MEMPOOL_ELT_SIZE, 543 RTE_MEMPOOL_CACHE_MAX_SIZE, 0, 544 SOCKET_ID_ANY, 0); 545 546 if (mp_stack == NULL) { 547 printf("cannot allocate mp_stack mempool\n"); 548 goto err; 549 } 550 if (rte_mempool_set_ops_byname(mp_stack, "stack", NULL) < 0) { 551 printf("cannot set stack handler\n"); 552 goto err; 553 } 554 if (rte_mempool_populate_default(mp_stack) < 0) { 555 printf("cannot populate mp_stack mempool\n"); 556 goto err; 557 } 558 rte_mempool_obj_iter(mp_stack, my_obj_init, NULL); 559 560 /* retrieve the mempool from its name */ 561 if (rte_mempool_lookup("test_nocache") != mp_nocache) { 562 printf("Cannot lookup mempool from its name\n"); 563 goto err; 564 } 565 566 rte_mempool_list_dump(stdout); 567 568 /* basic tests without cache */ 569 if (test_mempool_basic(mp_nocache, 0) < 0) 570 goto err; 571 572 /* basic tests with cache */ 573 if (test_mempool_basic(mp_cache, 0) < 0) 574 goto err; 575 576 /* basic tests with user-owned cache */ 577 if (test_mempool_basic(mp_nocache, 1) < 0) 578 goto err; 579 580 /* more basic tests without cache */ 581 if (test_mempool_basic_ex(mp_nocache) < 0) 582 goto err; 583 584 /* mempool operation test based on single producer and single comsumer */ 585 if (test_mempool_sp_sc() < 0) 586 goto err; 587 588 if (test_mempool_creation_with_exceeded_cache_size() < 0) 589 goto err; 590 591 if (test_mempool_same_name_twice_creation() < 0) 592 goto err; 593 594 if (test_mempool_xmem_misc() < 0) 595 goto err; 596 597 /* test the stack handler */ 598 if (test_mempool_basic(mp_stack, 1) < 0) 599 goto err; 600 601 rte_mempool_list_dump(stdout); 602 603 return 0; 604 605 err: 606 rte_mempool_free(mp_nocache); 607 rte_mempool_free(mp_cache); 608 rte_mempool_free(mp_ext); 609 return -1; 610 } 611 612 static struct test_command mempool_cmd = { 613 .command = "mempool_autotest", 614 .callback = test_mempool, 615 }; 616 REGISTER_TEST_COMMAND(mempool_cmd); 617