1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2018 Arm Limited 3 */ 4 5 #include <stdio.h> 6 #include <rte_pause.h> 7 #include <rte_rcu_qsbr.h> 8 #include <rte_hash.h> 9 #include <rte_hash_crc.h> 10 #include <rte_malloc.h> 11 #include <rte_cycles.h> 12 #include <unistd.h> 13 14 #include "test.h" 15 16 /* Check condition and return an error if true. */ 17 #define TEST_RCU_QSBR_RETURN_IF_ERROR(cond, str, ...) do { \ 18 if (cond) { \ 19 printf("ERROR file %s, line %d: " str "\n", __FILE__, \ 20 __LINE__, ##__VA_ARGS__); \ 21 return -1; \ 22 } \ 23 } while (0) 24 25 /* Make sure that this has the same value as __RTE_QSBR_CNT_INIT */ 26 #define TEST_RCU_QSBR_CNT_INIT 1 27 28 uint16_t enabled_core_ids[RTE_MAX_LCORE]; 29 unsigned int num_cores; 30 31 static uint32_t *keys; 32 #define TOTAL_ENTRY (1024 * 8) 33 #define COUNTER_VALUE 4096 34 static uint32_t *hash_data[RTE_MAX_LCORE][TOTAL_ENTRY]; 35 static uint8_t writer_done; 36 37 static struct rte_rcu_qsbr *t[RTE_MAX_LCORE]; 38 struct rte_hash *h[RTE_MAX_LCORE]; 39 char hash_name[RTE_MAX_LCORE][8]; 40 41 struct test_rcu_thread_info { 42 /* Index in RCU array */ 43 int ir; 44 /* Index in hash array */ 45 int ih; 46 /* lcore IDs registered on the RCU variable */ 47 uint16_t r_core_ids[2]; 48 }; 49 struct test_rcu_thread_info thread_info[RTE_MAX_LCORE/4]; 50 51 static int 52 alloc_rcu(void) 53 { 54 int i; 55 uint32_t sz; 56 57 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE); 58 59 for (i = 0; i < RTE_MAX_LCORE; i++) 60 t[i] = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz, 61 RTE_CACHE_LINE_SIZE); 62 63 return 0; 64 } 65 66 static int 67 free_rcu(void) 68 { 69 int i; 70 71 for (i = 0; i < RTE_MAX_LCORE; i++) 72 rte_free(t[i]); 73 74 return 0; 75 } 76 77 /* 78 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads 79 * reporting their quiescent state on a QS variable. 80 */ 81 static int 82 test_rcu_qsbr_get_memsize(void) 83 { 84 uint32_t sz; 85 86 printf("\nTest rte_rcu_qsbr_thread_register()\n"); 87 88 sz = rte_rcu_qsbr_get_memsize(0); 89 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 1), "Get Memsize for 0 threads"); 90 91 sz = rte_rcu_qsbr_get_memsize(128); 92 /* For 128 threads, 93 * for machines with cache line size of 64B - 8384 94 * for machines with cache line size of 128 - 16768 95 */ 96 if (RTE_CACHE_LINE_SIZE == 64) 97 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 8384), 98 "Get Memsize for 128 threads"); 99 else if (RTE_CACHE_LINE_SIZE == 128) 100 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 16768), 101 "Get Memsize for 128 threads"); 102 103 return 0; 104 } 105 106 /* 107 * rte_rcu_qsbr_init: Initialize a QSBR variable. 108 */ 109 static int 110 test_rcu_qsbr_init(void) 111 { 112 int r; 113 114 printf("\nTest rte_rcu_qsbr_init()\n"); 115 116 r = rte_rcu_qsbr_init(NULL, RTE_MAX_LCORE); 117 TEST_RCU_QSBR_RETURN_IF_ERROR((r != 1), "NULL variable"); 118 119 return 0; 120 } 121 122 /* 123 * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads 124 * reporting their quiescent state on a QS variable. 125 */ 126 static int 127 test_rcu_qsbr_thread_register(void) 128 { 129 int ret; 130 131 printf("\nTest rte_rcu_qsbr_thread_register()\n"); 132 133 ret = rte_rcu_qsbr_thread_register(NULL, enabled_core_ids[0]); 134 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check"); 135 136 ret = rte_rcu_qsbr_thread_register(NULL, 100000); 137 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), 138 "NULL variable, invalid thread id"); 139 140 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 141 142 /* Register valid thread id */ 143 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]); 144 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Valid thread id"); 145 146 /* Re-registering should not return error */ 147 ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]); 148 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), 149 "Already registered thread id"); 150 151 /* Register valid thread id - max allowed thread id */ 152 ret = rte_rcu_qsbr_thread_register(t[0], RTE_MAX_LCORE - 1); 153 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Max thread id"); 154 155 ret = rte_rcu_qsbr_thread_register(t[0], 100000); 156 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), 157 "NULL variable, invalid thread id"); 158 159 return 0; 160 } 161 162 /* 163 * rte_rcu_qsbr_thread_unregister: Remove a reader thread, from the list of 164 * threads reporting their quiescent state on a QS variable. 165 */ 166 static int 167 test_rcu_qsbr_thread_unregister(void) 168 { 169 unsigned int num_threads[3] = {1, RTE_MAX_LCORE, 1}; 170 unsigned int i, j; 171 uint64_t token; 172 int ret; 173 174 printf("\nTest rte_rcu_qsbr_thread_unregister()\n"); 175 176 ret = rte_rcu_qsbr_thread_unregister(NULL, enabled_core_ids[0]); 177 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check"); 178 179 ret = rte_rcu_qsbr_thread_unregister(NULL, 100000); 180 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), 181 "NULL variable, invalid thread id"); 182 183 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 184 185 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]); 186 187 ret = rte_rcu_qsbr_thread_unregister(t[0], 100000); 188 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), 189 "NULL variable, invalid thread id"); 190 191 /* Find first disabled core */ 192 for (i = 0; i < RTE_MAX_LCORE; i++) { 193 if (enabled_core_ids[i] == 0) 194 break; 195 } 196 /* Test with disabled lcore */ 197 ret = rte_rcu_qsbr_thread_unregister(t[0], i); 198 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), 199 "disabled thread id"); 200 /* Unregister already unregistered core */ 201 ret = rte_rcu_qsbr_thread_unregister(t[0], i); 202 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), 203 "Already unregistered core"); 204 205 /* Test with enabled lcore */ 206 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]); 207 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), 208 "enabled thread id"); 209 /* Unregister already unregistered core */ 210 ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]); 211 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), 212 "Already unregistered core"); 213 214 /* 215 * Test with different thread_ids: 216 * 1 - thread_id = 0 217 * 2 - All possible thread_ids, from 0 to RTE_MAX_LCORE 218 * 3 - thread_id = RTE_MAX_LCORE - 1 219 */ 220 for (j = 0; j < 3; j++) { 221 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 222 223 for (i = 0; i < num_threads[j]; i++) 224 rte_rcu_qsbr_thread_register(t[0], 225 (j == 2) ? (RTE_MAX_LCORE - 1) : i); 226 227 token = rte_rcu_qsbr_start(t[0]); 228 TEST_RCU_QSBR_RETURN_IF_ERROR( 229 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start"); 230 /* Update quiescent state counter */ 231 for (i = 0; i < num_threads[j]; i++) { 232 /* Skip one update */ 233 if (i == (RTE_MAX_LCORE - 10)) 234 continue; 235 rte_rcu_qsbr_quiescent(t[0], 236 (j == 2) ? (RTE_MAX_LCORE - 1) : i); 237 } 238 239 if (j == 1) { 240 /* Validate the updates */ 241 ret = rte_rcu_qsbr_check(t[0], token, false); 242 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), 243 "Non-blocking QSBR check"); 244 /* Update the previously skipped thread */ 245 rte_rcu_qsbr_quiescent(t[0], RTE_MAX_LCORE - 10); 246 } 247 248 /* Validate the updates */ 249 ret = rte_rcu_qsbr_check(t[0], token, false); 250 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), 251 "Non-blocking QSBR check"); 252 253 for (i = 0; i < num_threads[j]; i++) 254 rte_rcu_qsbr_thread_unregister(t[0], 255 (j == 2) ? (RTE_MAX_LCORE - 1) : i); 256 257 /* Check with no thread registered */ 258 ret = rte_rcu_qsbr_check(t[0], token, true); 259 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), 260 "Blocking QSBR check"); 261 } 262 return 0; 263 } 264 265 /* 266 * rte_rcu_qsbr_start: Ask the worker threads to report the quiescent state 267 * status. 268 */ 269 static int 270 test_rcu_qsbr_start(void) 271 { 272 uint64_t token; 273 int i; 274 275 printf("\nTest rte_rcu_qsbr_start()\n"); 276 277 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 278 279 for (i = 0; i < 3; i++) 280 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]); 281 282 token = rte_rcu_qsbr_start(t[0]); 283 TEST_RCU_QSBR_RETURN_IF_ERROR( 284 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start"); 285 return 0; 286 } 287 288 static int 289 test_rcu_qsbr_check_reader(void *arg) 290 { 291 struct rte_rcu_qsbr *temp; 292 uint8_t read_type = (uint8_t)((uintptr_t)arg); 293 294 temp = t[read_type]; 295 296 /* Update quiescent state counter */ 297 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[0]); 298 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[1]); 299 rte_rcu_qsbr_thread_unregister(temp, enabled_core_ids[2]); 300 rte_rcu_qsbr_quiescent(temp, enabled_core_ids[3]); 301 return 0; 302 } 303 304 /* 305 * rte_rcu_qsbr_check: Checks if all the worker threads have entered the queis- 306 * cent state 'n' number of times. 'n' is provided in rte_rcu_qsbr_start API. 307 */ 308 static int 309 test_rcu_qsbr_check(void) 310 { 311 int i, ret; 312 uint64_t token; 313 314 printf("\nTest rte_rcu_qsbr_check()\n"); 315 316 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 317 318 token = rte_rcu_qsbr_start(t[0]); 319 TEST_RCU_QSBR_RETURN_IF_ERROR( 320 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start"); 321 322 323 ret = rte_rcu_qsbr_check(t[0], 0, false); 324 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Token = 0"); 325 326 ret = rte_rcu_qsbr_check(t[0], token, true); 327 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check"); 328 329 for (i = 0; i < 3; i++) 330 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]); 331 332 ret = rte_rcu_qsbr_check(t[0], token, false); 333 /* Threads are offline, hence this should pass */ 334 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check"); 335 336 token = rte_rcu_qsbr_start(t[0]); 337 TEST_RCU_QSBR_RETURN_IF_ERROR( 338 (token != (TEST_RCU_QSBR_CNT_INIT + 2)), "QSBR Start"); 339 340 ret = rte_rcu_qsbr_check(t[0], token, false); 341 /* Threads are offline, hence this should pass */ 342 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check"); 343 344 for (i = 0; i < 3; i++) 345 rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[i]); 346 347 ret = rte_rcu_qsbr_check(t[0], token, true); 348 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check"); 349 350 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 351 352 for (i = 0; i < 4; i++) 353 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]); 354 355 token = rte_rcu_qsbr_start(t[0]); 356 TEST_RCU_QSBR_RETURN_IF_ERROR( 357 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start"); 358 359 rte_eal_remote_launch(test_rcu_qsbr_check_reader, NULL, 360 enabled_core_ids[0]); 361 362 rte_eal_mp_wait_lcore(); 363 ret = rte_rcu_qsbr_check(t[0], token, true); 364 TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 1), "Blocking QSBR check"); 365 366 return 0; 367 } 368 369 static int 370 test_rcu_qsbr_synchronize_reader(void *arg) 371 { 372 uint32_t lcore_id = rte_lcore_id(); 373 (void)arg; 374 375 /* Register and become online */ 376 rte_rcu_qsbr_thread_register(t[0], lcore_id); 377 rte_rcu_qsbr_thread_online(t[0], lcore_id); 378 379 while (!writer_done) 380 rte_rcu_qsbr_quiescent(t[0], lcore_id); 381 382 rte_rcu_qsbr_thread_offline(t[0], lcore_id); 383 rte_rcu_qsbr_thread_unregister(t[0], lcore_id); 384 385 return 0; 386 } 387 388 /* 389 * rte_rcu_qsbr_synchronize: Wait till all the reader threads have entered 390 * the queiscent state. 391 */ 392 static int 393 test_rcu_qsbr_synchronize(void) 394 { 395 unsigned int i; 396 397 printf("\nTest rte_rcu_qsbr_synchronize()\n"); 398 399 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 400 401 /* Test if the API returns when there are no threads reporting 402 * QS on the variable. 403 */ 404 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID); 405 406 /* Test if the API returns when there are threads registered 407 * but not online. 408 */ 409 for (i = 0; i < RTE_MAX_LCORE; i++) 410 rte_rcu_qsbr_thread_register(t[0], i); 411 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID); 412 413 /* Test if the API returns when the caller is also 414 * reporting the QS status. 415 */ 416 rte_rcu_qsbr_thread_online(t[0], 0); 417 rte_rcu_qsbr_synchronize(t[0], 0); 418 rte_rcu_qsbr_thread_offline(t[0], 0); 419 420 /* Check the other boundary */ 421 rte_rcu_qsbr_thread_online(t[0], RTE_MAX_LCORE - 1); 422 rte_rcu_qsbr_synchronize(t[0], RTE_MAX_LCORE - 1); 423 rte_rcu_qsbr_thread_offline(t[0], RTE_MAX_LCORE - 1); 424 425 /* Test if the API returns after unregisterng all the threads */ 426 for (i = 0; i < RTE_MAX_LCORE; i++) 427 rte_rcu_qsbr_thread_unregister(t[0], i); 428 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID); 429 430 /* Test if the API returns with the live threads */ 431 writer_done = 0; 432 for (i = 0; i < num_cores; i++) 433 rte_eal_remote_launch(test_rcu_qsbr_synchronize_reader, 434 NULL, enabled_core_ids[i]); 435 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID); 436 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID); 437 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID); 438 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID); 439 rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID); 440 441 writer_done = 1; 442 rte_eal_mp_wait_lcore(); 443 444 return 0; 445 } 446 447 /* 448 * rte_rcu_qsbr_thread_online: Add a registered reader thread, to 449 * the list of threads reporting their quiescent state on a QS variable. 450 */ 451 static int 452 test_rcu_qsbr_thread_online(void) 453 { 454 int i, ret; 455 uint64_t token; 456 457 printf("Test rte_rcu_qsbr_thread_online()\n"); 458 459 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 460 461 /* Register 2 threads to validate that only the 462 * online thread is waited upon. 463 */ 464 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]); 465 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[1]); 466 467 /* Use qsbr_start to verify that the thread_online API 468 * succeeded. 469 */ 470 token = rte_rcu_qsbr_start(t[0]); 471 472 /* Make the thread online */ 473 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]); 474 475 /* Check if the thread is online */ 476 ret = rte_rcu_qsbr_check(t[0], token, true); 477 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online"); 478 479 /* Check if the online thread, can report QS */ 480 token = rte_rcu_qsbr_start(t[0]); 481 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]); 482 ret = rte_rcu_qsbr_check(t[0], token, true); 483 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update"); 484 485 /* Make all the threads online */ 486 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 487 token = rte_rcu_qsbr_start(t[0]); 488 for (i = 0; i < RTE_MAX_LCORE; i++) { 489 rte_rcu_qsbr_thread_register(t[0], i); 490 rte_rcu_qsbr_thread_online(t[0], i); 491 } 492 /* Check if all the threads are online */ 493 ret = rte_rcu_qsbr_check(t[0], token, true); 494 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online"); 495 /* Check if all the online threads can report QS */ 496 token = rte_rcu_qsbr_start(t[0]); 497 for (i = 0; i < RTE_MAX_LCORE; i++) 498 rte_rcu_qsbr_quiescent(t[0], i); 499 ret = rte_rcu_qsbr_check(t[0], token, true); 500 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update"); 501 502 return 0; 503 } 504 505 /* 506 * rte_rcu_qsbr_thread_offline: Remove a registered reader thread, from 507 * the list of threads reporting their quiescent state on a QS variable. 508 */ 509 static int 510 test_rcu_qsbr_thread_offline(void) 511 { 512 int i, ret; 513 uint64_t token; 514 515 printf("\nTest rte_rcu_qsbr_thread_offline()\n"); 516 517 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 518 519 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]); 520 521 /* Make the thread offline */ 522 rte_rcu_qsbr_thread_offline(t[0], enabled_core_ids[0]); 523 524 /* Use qsbr_start to verify that the thread_offline API 525 * succeeded. 526 */ 527 token = rte_rcu_qsbr_start(t[0]); 528 /* Check if the thread is offline */ 529 ret = rte_rcu_qsbr_check(t[0], token, true); 530 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread offline"); 531 532 /* Bring an offline thread online and check if it can 533 * report QS. 534 */ 535 rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]); 536 /* Check if the online thread, can report QS */ 537 token = rte_rcu_qsbr_start(t[0]); 538 rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]); 539 ret = rte_rcu_qsbr_check(t[0], token, true); 540 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline to online"); 541 542 /* 543 * Check a sequence of online/status/offline/status/online/status 544 */ 545 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 546 token = rte_rcu_qsbr_start(t[0]); 547 /* Make the threads online */ 548 for (i = 0; i < RTE_MAX_LCORE; i++) { 549 rte_rcu_qsbr_thread_register(t[0], i); 550 rte_rcu_qsbr_thread_online(t[0], i); 551 } 552 553 /* Check if all the threads are online */ 554 ret = rte_rcu_qsbr_check(t[0], token, true); 555 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online"); 556 557 /* Check if all the online threads can report QS */ 558 token = rte_rcu_qsbr_start(t[0]); 559 for (i = 0; i < RTE_MAX_LCORE; i++) 560 rte_rcu_qsbr_quiescent(t[0], i); 561 ret = rte_rcu_qsbr_check(t[0], token, true); 562 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "report QS"); 563 564 /* Make all the threads offline */ 565 for (i = 0; i < RTE_MAX_LCORE; i++) 566 rte_rcu_qsbr_thread_offline(t[0], i); 567 /* Make sure these threads are not being waited on */ 568 token = rte_rcu_qsbr_start(t[0]); 569 ret = rte_rcu_qsbr_check(t[0], token, true); 570 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline QS"); 571 572 /* Make the threads online */ 573 for (i = 0; i < RTE_MAX_LCORE; i++) 574 rte_rcu_qsbr_thread_online(t[0], i); 575 /* Check if all the online threads can report QS */ 576 token = rte_rcu_qsbr_start(t[0]); 577 for (i = 0; i < RTE_MAX_LCORE; i++) 578 rte_rcu_qsbr_quiescent(t[0], i); 579 ret = rte_rcu_qsbr_check(t[0], token, true); 580 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "online again"); 581 582 return 0; 583 } 584 585 /* 586 * rte_rcu_qsbr_dump: Dump status of a single QS variable to a file 587 */ 588 static int 589 test_rcu_qsbr_dump(void) 590 { 591 int i; 592 593 printf("\nTest rte_rcu_qsbr_dump()\n"); 594 595 /* Negative tests */ 596 rte_rcu_qsbr_dump(NULL, t[0]); 597 rte_rcu_qsbr_dump(stdout, NULL); 598 rte_rcu_qsbr_dump(NULL, NULL); 599 600 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 601 rte_rcu_qsbr_init(t[1], RTE_MAX_LCORE); 602 603 /* QS variable with 0 core mask */ 604 rte_rcu_qsbr_dump(stdout, t[0]); 605 606 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]); 607 608 for (i = 1; i < 3; i++) 609 rte_rcu_qsbr_thread_register(t[1], enabled_core_ids[i]); 610 611 rte_rcu_qsbr_dump(stdout, t[0]); 612 rte_rcu_qsbr_dump(stdout, t[1]); 613 printf("\n"); 614 return 0; 615 } 616 617 static int 618 test_rcu_qsbr_reader(void *arg) 619 { 620 struct rte_rcu_qsbr *temp; 621 struct rte_hash *hash = NULL; 622 int i; 623 uint32_t lcore_id = rte_lcore_id(); 624 struct test_rcu_thread_info *ti; 625 uint32_t *pdata; 626 627 ti = (struct test_rcu_thread_info *)arg; 628 temp = t[ti->ir]; 629 hash = h[ti->ih]; 630 631 do { 632 rte_rcu_qsbr_thread_register(temp, lcore_id); 633 rte_rcu_qsbr_thread_online(temp, lcore_id); 634 for (i = 0; i < TOTAL_ENTRY; i++) { 635 rte_rcu_qsbr_lock(temp, lcore_id); 636 if (rte_hash_lookup_data(hash, keys+i, 637 (void **)&pdata) != -ENOENT) { 638 pdata[lcore_id] = 0; 639 while (pdata[lcore_id] < COUNTER_VALUE) 640 pdata[lcore_id]++; 641 } 642 rte_rcu_qsbr_unlock(temp, lcore_id); 643 } 644 /* Update quiescent state counter */ 645 rte_rcu_qsbr_quiescent(temp, lcore_id); 646 rte_rcu_qsbr_thread_offline(temp, lcore_id); 647 rte_rcu_qsbr_thread_unregister(temp, lcore_id); 648 } while (!writer_done); 649 650 return 0; 651 } 652 653 static int 654 test_rcu_qsbr_writer(void *arg) 655 { 656 uint64_t token; 657 int32_t i, pos, del; 658 uint32_t c; 659 struct rte_rcu_qsbr *temp; 660 struct rte_hash *hash = NULL; 661 struct test_rcu_thread_info *ti; 662 663 ti = (struct test_rcu_thread_info *)arg; 664 temp = t[ti->ir]; 665 hash = h[ti->ih]; 666 667 /* Delete element from the shared data structure */ 668 del = rte_lcore_id() % TOTAL_ENTRY; 669 pos = rte_hash_del_key(hash, keys + del); 670 if (pos < 0) { 671 printf("Delete key failed #%d\n", keys[del]); 672 return -1; 673 } 674 /* Start the quiescent state query process */ 675 token = rte_rcu_qsbr_start(temp); 676 /* Check the quiescent state status */ 677 rte_rcu_qsbr_check(temp, token, true); 678 for (i = 0; i < 2; i++) { 679 c = hash_data[ti->ih][del][ti->r_core_ids[i]]; 680 if (c != COUNTER_VALUE && c != 0) { 681 printf("Reader lcore id %u did not complete = %u\t", 682 rte_lcore_id(), c); 683 return -1; 684 } 685 } 686 687 if (rte_hash_free_key_with_position(hash, pos) < 0) { 688 printf("Failed to free the key #%d\n", keys[del]); 689 return -1; 690 } 691 rte_free(hash_data[ti->ih][del]); 692 hash_data[ti->ih][del] = NULL; 693 694 return 0; 695 } 696 697 static struct rte_hash * 698 init_hash(int hash_id) 699 { 700 int i; 701 struct rte_hash *h = NULL; 702 703 sprintf(hash_name[hash_id], "hash%d", hash_id); 704 struct rte_hash_parameters hash_params = { 705 .entries = TOTAL_ENTRY, 706 .key_len = sizeof(uint32_t), 707 .hash_func_init_val = 0, 708 .socket_id = rte_socket_id(), 709 .hash_func = rte_hash_crc, 710 .extra_flag = 711 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF, 712 .name = hash_name[hash_id], 713 }; 714 715 h = rte_hash_create(&hash_params); 716 if (h == NULL) { 717 printf("Hash create Failed\n"); 718 return NULL; 719 } 720 721 for (i = 0; i < TOTAL_ENTRY; i++) { 722 hash_data[hash_id][i] = 723 rte_zmalloc(NULL, sizeof(uint32_t) * RTE_MAX_LCORE, 0); 724 if (hash_data[hash_id][i] == NULL) { 725 printf("No memory\n"); 726 return NULL; 727 } 728 } 729 keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0); 730 if (keys == NULL) { 731 printf("No memory\n"); 732 return NULL; 733 } 734 735 for (i = 0; i < TOTAL_ENTRY; i++) 736 keys[i] = i; 737 738 for (i = 0; i < TOTAL_ENTRY; i++) { 739 if (rte_hash_add_key_data(h, keys + i, 740 (void *)((uintptr_t)hash_data[hash_id][i])) 741 < 0) { 742 printf("Hash key add Failed #%d\n", i); 743 return NULL; 744 } 745 } 746 return h; 747 } 748 749 /* 750 * Functional test: 751 * Single writer, Single QS variable, simultaneous QSBR Queries 752 */ 753 static int 754 test_rcu_qsbr_sw_sv_3qs(void) 755 { 756 uint64_t token[3]; 757 uint32_t c; 758 int i; 759 int32_t pos[3]; 760 761 writer_done = 0; 762 763 printf("Test: 1 writer, 1 QSBR variable, simultaneous QSBR queries\n"); 764 765 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE); 766 767 /* Shared data structure created */ 768 h[0] = init_hash(0); 769 if (h[0] == NULL) { 770 printf("Hash init failed\n"); 771 goto error; 772 } 773 774 /* No need to fill the registered core IDs as the writer 775 * thread is not launched. 776 */ 777 thread_info[0].ir = 0; 778 thread_info[0].ih = 0; 779 780 /* Reader threads are launched */ 781 for (i = 0; i < 4; i++) 782 rte_eal_remote_launch(test_rcu_qsbr_reader, &thread_info[0], 783 enabled_core_ids[i]); 784 785 /* Delete element from the shared data structure */ 786 pos[0] = rte_hash_del_key(h[0], keys + 0); 787 if (pos[0] < 0) { 788 printf("Delete key failed #%d\n", keys[0]); 789 goto error; 790 } 791 /* Start the quiescent state query process */ 792 token[0] = rte_rcu_qsbr_start(t[0]); 793 794 /* Delete element from the shared data structure */ 795 pos[1] = rte_hash_del_key(h[0], keys + 3); 796 if (pos[1] < 0) { 797 printf("Delete key failed #%d\n", keys[3]); 798 goto error; 799 } 800 /* Start the quiescent state query process */ 801 token[1] = rte_rcu_qsbr_start(t[0]); 802 803 /* Delete element from the shared data structure */ 804 pos[2] = rte_hash_del_key(h[0], keys + 6); 805 if (pos[2] < 0) { 806 printf("Delete key failed #%d\n", keys[6]); 807 goto error; 808 } 809 /* Start the quiescent state query process */ 810 token[2] = rte_rcu_qsbr_start(t[0]); 811 812 /* Check the quiescent state status */ 813 rte_rcu_qsbr_check(t[0], token[0], true); 814 for (i = 0; i < 4; i++) { 815 c = hash_data[0][0][enabled_core_ids[i]]; 816 if (c != COUNTER_VALUE && c != 0) { 817 printf("Reader lcore %d did not complete #0 = %d\n", 818 enabled_core_ids[i], c); 819 goto error; 820 } 821 } 822 823 if (rte_hash_free_key_with_position(h[0], pos[0]) < 0) { 824 printf("Failed to free the key #%d\n", keys[0]); 825 goto error; 826 } 827 rte_free(hash_data[0][0]); 828 hash_data[0][0] = NULL; 829 830 /* Check the quiescent state status */ 831 rte_rcu_qsbr_check(t[0], token[1], true); 832 for (i = 0; i < 4; i++) { 833 c = hash_data[0][3][enabled_core_ids[i]]; 834 if (c != COUNTER_VALUE && c != 0) { 835 printf("Reader lcore %d did not complete #3 = %d\n", 836 enabled_core_ids[i], c); 837 goto error; 838 } 839 } 840 841 if (rte_hash_free_key_with_position(h[0], pos[1]) < 0) { 842 printf("Failed to free the key #%d\n", keys[3]); 843 goto error; 844 } 845 rte_free(hash_data[0][3]); 846 hash_data[0][3] = NULL; 847 848 /* Check the quiescent state status */ 849 rte_rcu_qsbr_check(t[0], token[2], true); 850 for (i = 0; i < 4; i++) { 851 c = hash_data[0][6][enabled_core_ids[i]]; 852 if (c != COUNTER_VALUE && c != 0) { 853 printf("Reader lcore %d did not complete #6 = %d\n", 854 enabled_core_ids[i], c); 855 goto error; 856 } 857 } 858 859 if (rte_hash_free_key_with_position(h[0], pos[2]) < 0) { 860 printf("Failed to free the key #%d\n", keys[6]); 861 goto error; 862 } 863 rte_free(hash_data[0][6]); 864 hash_data[0][6] = NULL; 865 866 writer_done = 1; 867 868 /* Wait and check return value from reader threads */ 869 for (i = 0; i < 4; i++) 870 if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0) 871 goto error; 872 rte_hash_free(h[0]); 873 rte_free(keys); 874 875 return 0; 876 877 error: 878 writer_done = 1; 879 /* Wait until all readers have exited */ 880 rte_eal_mp_wait_lcore(); 881 882 rte_hash_free(h[0]); 883 rte_free(keys); 884 for (i = 0; i < TOTAL_ENTRY; i++) 885 rte_free(hash_data[0][i]); 886 887 return -1; 888 } 889 890 /* 891 * Multi writer, Multiple QS variable, simultaneous QSBR queries 892 */ 893 static int 894 test_rcu_qsbr_mw_mv_mqs(void) 895 { 896 unsigned int i, j; 897 unsigned int test_cores; 898 899 writer_done = 0; 900 test_cores = num_cores / 4; 901 test_cores = test_cores * 4; 902 903 printf("Test: %d writers, %d QSBR variable, simultaneous QSBR queries\n", 904 test_cores / 2, test_cores / 4); 905 906 for (i = 0; i < test_cores / 4; i++) { 907 j = i * 4; 908 rte_rcu_qsbr_init(t[i], RTE_MAX_LCORE); 909 h[i] = init_hash(i); 910 if (h[i] == NULL) { 911 printf("Hash init failed\n"); 912 goto error; 913 } 914 thread_info[i].ir = i; 915 thread_info[i].ih = i; 916 thread_info[i].r_core_ids[0] = enabled_core_ids[j]; 917 thread_info[i].r_core_ids[1] = enabled_core_ids[j + 1]; 918 919 /* Reader threads are launched */ 920 rte_eal_remote_launch(test_rcu_qsbr_reader, 921 (void *)&thread_info[i], 922 enabled_core_ids[j]); 923 rte_eal_remote_launch(test_rcu_qsbr_reader, 924 (void *)&thread_info[i], 925 enabled_core_ids[j + 1]); 926 927 /* Writer threads are launched */ 928 rte_eal_remote_launch(test_rcu_qsbr_writer, 929 (void *)&thread_info[i], 930 enabled_core_ids[j + 2]); 931 rte_eal_remote_launch(test_rcu_qsbr_writer, 932 (void *)&thread_info[i], 933 enabled_core_ids[j + 3]); 934 } 935 936 /* Wait and check return value from writer threads */ 937 for (i = 0; i < test_cores / 4; i++) { 938 j = i * 4; 939 if (rte_eal_wait_lcore(enabled_core_ids[j + 2]) < 0) 940 goto error; 941 942 if (rte_eal_wait_lcore(enabled_core_ids[j + 3]) < 0) 943 goto error; 944 } 945 writer_done = 1; 946 947 /* Wait and check return value from reader threads */ 948 for (i = 0; i < test_cores / 4; i++) { 949 j = i * 4; 950 if (rte_eal_wait_lcore(enabled_core_ids[j]) < 0) 951 goto error; 952 953 if (rte_eal_wait_lcore(enabled_core_ids[j + 1]) < 0) 954 goto error; 955 } 956 957 for (i = 0; i < test_cores / 4; i++) 958 rte_hash_free(h[i]); 959 960 rte_free(keys); 961 962 return 0; 963 964 error: 965 writer_done = 1; 966 /* Wait until all readers and writers have exited */ 967 rte_eal_mp_wait_lcore(); 968 969 for (i = 0; i < test_cores / 4; i++) 970 rte_hash_free(h[i]); 971 rte_free(keys); 972 for (j = 0; j < test_cores / 4; j++) 973 for (i = 0; i < TOTAL_ENTRY; i++) 974 rte_free(hash_data[j][i]); 975 976 return -1; 977 } 978 979 static int 980 test_rcu_qsbr_main(void) 981 { 982 uint16_t core_id; 983 984 if (rte_lcore_count() < 5) { 985 printf("Not enough cores for rcu_qsbr_autotest, expecting at least 5\n"); 986 return TEST_SKIPPED; 987 } 988 989 num_cores = 0; 990 RTE_LCORE_FOREACH_SLAVE(core_id) { 991 enabled_core_ids[num_cores] = core_id; 992 num_cores++; 993 } 994 995 /* Error-checking test cases */ 996 if (test_rcu_qsbr_get_memsize() < 0) 997 goto test_fail; 998 999 if (test_rcu_qsbr_init() < 0) 1000 goto test_fail; 1001 1002 alloc_rcu(); 1003 1004 if (test_rcu_qsbr_thread_register() < 0) 1005 goto test_fail; 1006 1007 if (test_rcu_qsbr_thread_unregister() < 0) 1008 goto test_fail; 1009 1010 if (test_rcu_qsbr_start() < 0) 1011 goto test_fail; 1012 1013 if (test_rcu_qsbr_check() < 0) 1014 goto test_fail; 1015 1016 if (test_rcu_qsbr_synchronize() < 0) 1017 goto test_fail; 1018 1019 if (test_rcu_qsbr_dump() < 0) 1020 goto test_fail; 1021 1022 if (test_rcu_qsbr_thread_online() < 0) 1023 goto test_fail; 1024 1025 if (test_rcu_qsbr_thread_offline() < 0) 1026 goto test_fail; 1027 1028 printf("\nFunctional tests\n"); 1029 1030 if (test_rcu_qsbr_sw_sv_3qs() < 0) 1031 goto test_fail; 1032 1033 if (test_rcu_qsbr_mw_mv_mqs() < 0) 1034 goto test_fail; 1035 1036 free_rcu(); 1037 1038 printf("\n"); 1039 return 0; 1040 1041 test_fail: 1042 free_rcu(); 1043 1044 return -1; 1045 } 1046 1047 REGISTER_TEST_COMMAND(rcu_qsbr_autotest, test_rcu_qsbr_main); 1048