1 /* 2 * 3 * Copyright 2016 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 #include "src/core/lib/iomgr/resource_quota.h" 20 21 #include <grpc/support/alloc.h> 22 #include <grpc/support/log.h> 23 24 #include "src/core/lib/iomgr/exec_ctx.h" 25 #include "src/core/lib/slice/slice_internal.h" 26 #include "test/core/util/test_config.h" 27 28 gpr_mu g_mu; 29 gpr_cv g_cv; 30 31 static void inc_int_cb(void* a, grpc_error* error) { 32 gpr_mu_lock(&g_mu); 33 ++*static_cast<int*>(a); 34 gpr_cv_signal(&g_cv); 35 gpr_mu_unlock(&g_mu); 36 } 37 38 static void assert_counter_becomes(int* ctr, int value) { 39 gpr_mu_lock(&g_mu); 40 gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5); 41 while (*ctr != value) { 42 GPR_ASSERT(!gpr_cv_wait(&g_cv, &g_mu, deadline)); 43 } 44 gpr_mu_unlock(&g_mu); 45 } 46 47 static void set_event_cb(void* a, grpc_error* error) { 48 gpr_event_set(static_cast<gpr_event*>(a), (void*)1); 49 } 50 grpc_closure* set_event(gpr_event* ev) { 51 return GRPC_CLOSURE_CREATE(set_event_cb, ev, grpc_schedule_on_exec_ctx); 52 } 53 54 typedef struct { 55 size_t size; 56 grpc_resource_user* resource_user; 57 grpc_closure* then; 58 } reclaimer_args; 59 60 static void reclaimer_cb(void* args, grpc_error* error) { 61 GPR_ASSERT(error == GRPC_ERROR_NONE); 62 reclaimer_args* a = static_cast<reclaimer_args*>(args); 63 grpc_resource_user_free(a->resource_user, a->size); 64 grpc_resource_user_finish_reclamation(a->resource_user); 65 GRPC_CLOSURE_RUN(a->then, GRPC_ERROR_NONE); 66 gpr_free(a); 67 } 68 69 grpc_closure* make_reclaimer(grpc_resource_user* resource_user, size_t size, 70 grpc_closure* then) { 71 reclaimer_args* a = static_cast<reclaimer_args*>(gpr_malloc(sizeof(*a))); 72 a->size = size; 73 a->resource_user = resource_user; 74 a->then = then; 75 return GRPC_CLOSURE_CREATE(reclaimer_cb, a, grpc_schedule_on_exec_ctx); 76 } 77 78 static void unused_reclaimer_cb(void* arg, grpc_error* error) { 79 GPR_ASSERT(error == GRPC_ERROR_CANCELLED); 80 GRPC_CLOSURE_RUN(static_cast<grpc_closure*>(arg), GRPC_ERROR_NONE); 81 } 82 grpc_closure* make_unused_reclaimer(grpc_closure* then) { 83 return GRPC_CLOSURE_CREATE(unused_reclaimer_cb, then, 84 grpc_schedule_on_exec_ctx); 85 } 86 87 static void destroy_user(grpc_resource_user* usr) { 88 grpc_core::ExecCtx exec_ctx; 89 grpc_resource_user_unref(usr); 90 } 91 92 static void test_no_op(void) { 93 gpr_log(GPR_INFO, "** test_no_op **"); 94 grpc_resource_quota_unref(grpc_resource_quota_create("test_no_op")); 95 } 96 97 static void test_resize_then_destroy(void) { 98 gpr_log(GPR_INFO, "** test_resize_then_destroy **"); 99 grpc_resource_quota* q = 100 grpc_resource_quota_create("test_resize_then_destroy"); 101 grpc_resource_quota_resize(q, 1024 * 1024); 102 grpc_resource_quota_unref(q); 103 } 104 105 static void test_resource_user_no_op(void) { 106 gpr_log(GPR_INFO, "** test_resource_user_no_op **"); 107 grpc_resource_quota* q = 108 grpc_resource_quota_create("test_resource_user_no_op"); 109 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 110 grpc_resource_quota_unref(q); 111 destroy_user(usr); 112 } 113 114 static void test_instant_alloc_then_free(void) { 115 gpr_log(GPR_INFO, "** test_instant_alloc_then_free **"); 116 grpc_resource_quota* q = 117 grpc_resource_quota_create("test_instant_alloc_then_free"); 118 grpc_resource_quota_resize(q, 1024 * 1024); 119 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 120 { 121 grpc_core::ExecCtx exec_ctx; 122 grpc_resource_user_alloc(usr, 1024, nullptr); 123 } 124 { 125 grpc_core::ExecCtx exec_ctx; 126 grpc_resource_user_free(usr, 1024); 127 } 128 grpc_resource_quota_unref(q); 129 destroy_user(usr); 130 } 131 132 static void test_instant_alloc_free_pair(void) { 133 gpr_log(GPR_INFO, "** test_instant_alloc_free_pair **"); 134 grpc_resource_quota* q = 135 grpc_resource_quota_create("test_instant_alloc_free_pair"); 136 grpc_resource_quota_resize(q, 1024 * 1024); 137 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 138 { 139 grpc_core::ExecCtx exec_ctx; 140 grpc_resource_user_alloc(usr, 1024, nullptr); 141 grpc_resource_user_free(usr, 1024); 142 } 143 grpc_resource_quota_unref(q); 144 destroy_user(usr); 145 } 146 147 static void test_simple_async_alloc(void) { 148 gpr_log(GPR_INFO, "** test_simple_async_alloc **"); 149 grpc_resource_quota* q = 150 grpc_resource_quota_create("test_simple_async_alloc"); 151 grpc_resource_quota_resize(q, 1024 * 1024); 152 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 153 { 154 gpr_event ev; 155 gpr_event_init(&ev); 156 grpc_core::ExecCtx exec_ctx; 157 grpc_resource_user_alloc(usr, 1024, set_event(&ev)); 158 grpc_core::ExecCtx::Get()->Flush(); 159 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 160 nullptr); 161 } 162 { 163 grpc_core::ExecCtx exec_ctx; 164 grpc_resource_user_free(usr, 1024); 165 } 166 grpc_resource_quota_unref(q); 167 destroy_user(usr); 168 } 169 170 static void test_async_alloc_blocked_by_size(void) { 171 gpr_log(GPR_INFO, "** test_async_alloc_blocked_by_size **"); 172 grpc_resource_quota* q = 173 grpc_resource_quota_create("test_async_alloc_blocked_by_size"); 174 grpc_resource_quota_resize(q, 1); 175 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 176 gpr_event ev; 177 gpr_event_init(&ev); 178 { 179 grpc_core::ExecCtx exec_ctx; 180 grpc_resource_user_alloc(usr, 1024, set_event(&ev)); 181 grpc_core::ExecCtx::Get()->Flush(); 182 GPR_ASSERT(gpr_event_wait( 183 &ev, grpc_timeout_milliseconds_to_deadline(100)) == nullptr); 184 } 185 grpc_resource_quota_resize(q, 1024); 186 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 187 nullptr); 188 ; 189 { 190 grpc_core::ExecCtx exec_ctx; 191 grpc_resource_user_free(usr, 1024); 192 } 193 grpc_resource_quota_unref(q); 194 destroy_user(usr); 195 } 196 197 static void test_scavenge(void) { 198 gpr_log(GPR_INFO, "** test_scavenge **"); 199 grpc_resource_quota* q = grpc_resource_quota_create("test_scavenge"); 200 grpc_resource_quota_resize(q, 1024); 201 grpc_resource_user* usr1 = grpc_resource_user_create(q, "usr1"); 202 grpc_resource_user* usr2 = grpc_resource_user_create(q, "usr2"); 203 { 204 gpr_event ev; 205 gpr_event_init(&ev); 206 grpc_core::ExecCtx exec_ctx; 207 grpc_resource_user_alloc(usr1, 1024, set_event(&ev)); 208 grpc_core::ExecCtx::Get()->Flush(); 209 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 210 nullptr); 211 ; 212 } 213 { 214 grpc_core::ExecCtx exec_ctx; 215 grpc_resource_user_free(usr1, 1024); 216 } 217 { 218 gpr_event ev; 219 gpr_event_init(&ev); 220 grpc_core::ExecCtx exec_ctx; 221 grpc_resource_user_alloc(usr2, 1024, set_event(&ev)); 222 grpc_core::ExecCtx::Get()->Flush(); 223 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 224 nullptr); 225 ; 226 } 227 { 228 grpc_core::ExecCtx exec_ctx; 229 grpc_resource_user_free(usr2, 1024); 230 } 231 grpc_resource_quota_unref(q); 232 destroy_user(usr1); 233 destroy_user(usr2); 234 } 235 236 static void test_scavenge_blocked(void) { 237 gpr_log(GPR_INFO, "** test_scavenge_blocked **"); 238 grpc_resource_quota* q = grpc_resource_quota_create("test_scavenge_blocked"); 239 grpc_resource_quota_resize(q, 1024); 240 grpc_resource_user* usr1 = grpc_resource_user_create(q, "usr1"); 241 grpc_resource_user* usr2 = grpc_resource_user_create(q, "usr2"); 242 gpr_event ev; 243 { 244 gpr_event_init(&ev); 245 grpc_core::ExecCtx exec_ctx; 246 grpc_resource_user_alloc(usr1, 1024, set_event(&ev)); 247 grpc_core::ExecCtx::Get()->Flush(); 248 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 249 nullptr); 250 ; 251 } 252 { 253 gpr_event_init(&ev); 254 grpc_core::ExecCtx exec_ctx; 255 grpc_resource_user_alloc(usr2, 1024, set_event(&ev)); 256 grpc_core::ExecCtx::Get()->Flush(); 257 GPR_ASSERT(gpr_event_wait( 258 &ev, grpc_timeout_milliseconds_to_deadline(100)) == nullptr); 259 } 260 { 261 grpc_core::ExecCtx exec_ctx; 262 grpc_resource_user_free(usr1, 1024); 263 grpc_core::ExecCtx::Get()->Flush(); 264 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 265 nullptr); 266 ; 267 } 268 { 269 grpc_core::ExecCtx exec_ctx; 270 grpc_resource_user_free(usr2, 1024); 271 } 272 grpc_resource_quota_unref(q); 273 destroy_user(usr1); 274 destroy_user(usr2); 275 } 276 277 static void test_blocked_until_scheduled_reclaim(void) { 278 gpr_log(GPR_INFO, "** test_blocked_until_scheduled_reclaim **"); 279 grpc_resource_quota* q = 280 grpc_resource_quota_create("test_blocked_until_scheduled_reclaim"); 281 grpc_resource_quota_resize(q, 1024); 282 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 283 { 284 gpr_event ev; 285 gpr_event_init(&ev); 286 grpc_core::ExecCtx exec_ctx; 287 grpc_resource_user_alloc(usr, 1024, set_event(&ev)); 288 grpc_core::ExecCtx::Get()->Flush(); 289 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 290 nullptr); 291 ; 292 } 293 gpr_event reclaim_done; 294 gpr_event_init(&reclaim_done); 295 { 296 grpc_core::ExecCtx exec_ctx; 297 grpc_resource_user_post_reclaimer( 298 usr, false, make_reclaimer(usr, 1024, set_event(&reclaim_done))); 299 } 300 { 301 gpr_event ev; 302 gpr_event_init(&ev); 303 grpc_core::ExecCtx exec_ctx; 304 grpc_resource_user_alloc(usr, 1024, set_event(&ev)); 305 grpc_core::ExecCtx::Get()->Flush(); 306 GPR_ASSERT(gpr_event_wait(&reclaim_done, 307 grpc_timeout_seconds_to_deadline(5)) != nullptr); 308 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 309 nullptr); 310 ; 311 } 312 { 313 grpc_core::ExecCtx exec_ctx; 314 grpc_resource_user_free(usr, 1024); 315 } 316 grpc_resource_quota_unref(q); 317 destroy_user(usr); 318 } 319 320 static void test_blocked_until_scheduled_reclaim_and_scavenge(void) { 321 gpr_log(GPR_INFO, "** test_blocked_until_scheduled_reclaim_and_scavenge **"); 322 grpc_resource_quota* q = grpc_resource_quota_create( 323 "test_blocked_until_scheduled_reclaim_and_scavenge"); 324 grpc_resource_quota_resize(q, 1024); 325 grpc_resource_user* usr1 = grpc_resource_user_create(q, "usr1"); 326 grpc_resource_user* usr2 = grpc_resource_user_create(q, "usr2"); 327 { 328 gpr_event ev; 329 gpr_event_init(&ev); 330 grpc_core::ExecCtx exec_ctx; 331 grpc_resource_user_alloc(usr1, 1024, set_event(&ev)); 332 grpc_core::ExecCtx::Get()->Flush(); 333 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 334 nullptr); 335 ; 336 } 337 gpr_event reclaim_done; 338 gpr_event_init(&reclaim_done); 339 { 340 grpc_core::ExecCtx exec_ctx; 341 grpc_resource_user_post_reclaimer( 342 usr1, false, make_reclaimer(usr1, 1024, set_event(&reclaim_done))); 343 } 344 { 345 gpr_event ev; 346 gpr_event_init(&ev); 347 grpc_core::ExecCtx exec_ctx; 348 grpc_resource_user_alloc(usr2, 1024, set_event(&ev)); 349 grpc_core::ExecCtx::Get()->Flush(); 350 GPR_ASSERT(gpr_event_wait(&reclaim_done, 351 grpc_timeout_seconds_to_deadline(5)) != nullptr); 352 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 353 nullptr); 354 ; 355 } 356 { 357 grpc_core::ExecCtx exec_ctx; 358 grpc_resource_user_free(usr2, 1024); 359 } 360 grpc_resource_quota_unref(q); 361 destroy_user(usr1); 362 destroy_user(usr2); 363 } 364 365 static void test_blocked_until_scheduled_destructive_reclaim(void) { 366 gpr_log(GPR_INFO, "** test_blocked_until_scheduled_destructive_reclaim **"); 367 grpc_resource_quota* q = grpc_resource_quota_create( 368 "test_blocked_until_scheduled_destructive_reclaim"); 369 grpc_resource_quota_resize(q, 1024); 370 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 371 { 372 gpr_event ev; 373 gpr_event_init(&ev); 374 grpc_core::ExecCtx exec_ctx; 375 grpc_resource_user_alloc(usr, 1024, set_event(&ev)); 376 grpc_core::ExecCtx::Get()->Flush(); 377 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 378 nullptr); 379 ; 380 } 381 gpr_event reclaim_done; 382 gpr_event_init(&reclaim_done); 383 { 384 grpc_core::ExecCtx exec_ctx; 385 grpc_resource_user_post_reclaimer( 386 usr, true, make_reclaimer(usr, 1024, set_event(&reclaim_done))); 387 } 388 { 389 gpr_event ev; 390 gpr_event_init(&ev); 391 grpc_core::ExecCtx exec_ctx; 392 grpc_resource_user_alloc(usr, 1024, set_event(&ev)); 393 grpc_core::ExecCtx::Get()->Flush(); 394 GPR_ASSERT(gpr_event_wait(&reclaim_done, 395 grpc_timeout_seconds_to_deadline(5)) != nullptr); 396 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 397 nullptr); 398 ; 399 } 400 { 401 grpc_core::ExecCtx exec_ctx; 402 grpc_resource_user_free(usr, 1024); 403 } 404 grpc_resource_quota_unref(q); 405 destroy_user(usr); 406 } 407 408 static void test_unused_reclaim_is_cancelled(void) { 409 gpr_log(GPR_INFO, "** test_unused_reclaim_is_cancelled **"); 410 grpc_resource_quota* q = 411 grpc_resource_quota_create("test_unused_reclaim_is_cancelled"); 412 grpc_resource_quota_resize(q, 1024); 413 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 414 gpr_event benign_done; 415 gpr_event_init(&benign_done); 416 gpr_event destructive_done; 417 gpr_event_init(&destructive_done); 418 { 419 grpc_core::ExecCtx exec_ctx; 420 grpc_resource_user_post_reclaimer( 421 usr, false, make_unused_reclaimer(set_event(&benign_done))); 422 grpc_resource_user_post_reclaimer( 423 usr, true, make_unused_reclaimer(set_event(&destructive_done))); 424 grpc_core::ExecCtx::Get()->Flush(); 425 GPR_ASSERT(gpr_event_wait(&benign_done, 426 grpc_timeout_milliseconds_to_deadline(100)) == 427 nullptr); 428 GPR_ASSERT(gpr_event_wait(&destructive_done, 429 grpc_timeout_milliseconds_to_deadline(100)) == 430 nullptr); 431 } 432 grpc_resource_quota_unref(q); 433 destroy_user(usr); 434 GPR_ASSERT(gpr_event_wait(&benign_done, 435 grpc_timeout_seconds_to_deadline(5)) != nullptr); 436 GPR_ASSERT(gpr_event_wait(&destructive_done, 437 grpc_timeout_seconds_to_deadline(5)) != nullptr); 438 } 439 440 static void test_benign_reclaim_is_preferred(void) { 441 gpr_log(GPR_INFO, "** test_benign_reclaim_is_preferred **"); 442 grpc_resource_quota* q = 443 grpc_resource_quota_create("test_benign_reclaim_is_preferred"); 444 grpc_resource_quota_resize(q, 1024); 445 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 446 gpr_event benign_done; 447 gpr_event_init(&benign_done); 448 gpr_event destructive_done; 449 gpr_event_init(&destructive_done); 450 { 451 gpr_event ev; 452 gpr_event_init(&ev); 453 grpc_core::ExecCtx exec_ctx; 454 grpc_resource_user_alloc(usr, 1024, set_event(&ev)); 455 grpc_core::ExecCtx::Get()->Flush(); 456 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 457 nullptr); 458 ; 459 } 460 { 461 grpc_core::ExecCtx exec_ctx; 462 grpc_resource_user_post_reclaimer( 463 usr, false, make_reclaimer(usr, 1024, set_event(&benign_done))); 464 grpc_resource_user_post_reclaimer( 465 usr, true, make_unused_reclaimer(set_event(&destructive_done))); 466 grpc_core::ExecCtx::Get()->Flush(); 467 GPR_ASSERT(gpr_event_wait(&benign_done, 468 grpc_timeout_milliseconds_to_deadline(100)) == 469 nullptr); 470 GPR_ASSERT(gpr_event_wait(&destructive_done, 471 grpc_timeout_milliseconds_to_deadline(100)) == 472 nullptr); 473 } 474 { 475 gpr_event ev; 476 gpr_event_init(&ev); 477 grpc_core::ExecCtx exec_ctx; 478 grpc_resource_user_alloc(usr, 1024, set_event(&ev)); 479 grpc_core::ExecCtx::Get()->Flush(); 480 GPR_ASSERT(gpr_event_wait(&benign_done, 481 grpc_timeout_seconds_to_deadline(5)) != nullptr); 482 GPR_ASSERT(gpr_event_wait(&destructive_done, 483 grpc_timeout_milliseconds_to_deadline(100)) == 484 nullptr); 485 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 486 nullptr); 487 } 488 { 489 grpc_core::ExecCtx exec_ctx; 490 grpc_resource_user_free(usr, 1024); 491 } 492 grpc_resource_quota_unref(q); 493 destroy_user(usr); 494 GPR_ASSERT(gpr_event_wait(&benign_done, 495 grpc_timeout_seconds_to_deadline(5)) != nullptr); 496 GPR_ASSERT(gpr_event_wait(&destructive_done, 497 grpc_timeout_seconds_to_deadline(5)) != nullptr); 498 } 499 500 static void test_multiple_reclaims_can_be_triggered(void) { 501 gpr_log(GPR_INFO, "** test_multiple_reclaims_can_be_triggered **"); 502 grpc_resource_quota* q = 503 grpc_resource_quota_create("test_multiple_reclaims_can_be_triggered"); 504 grpc_resource_quota_resize(q, 1024); 505 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 506 gpr_event benign_done; 507 gpr_event_init(&benign_done); 508 gpr_event destructive_done; 509 gpr_event_init(&destructive_done); 510 { 511 gpr_event ev; 512 gpr_event_init(&ev); 513 grpc_core::ExecCtx exec_ctx; 514 grpc_resource_user_alloc(usr, 1024, set_event(&ev)); 515 grpc_core::ExecCtx::Get()->Flush(); 516 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 517 nullptr); 518 ; 519 } 520 { 521 grpc_core::ExecCtx exec_ctx; 522 grpc_resource_user_post_reclaimer( 523 usr, false, make_reclaimer(usr, 512, set_event(&benign_done))); 524 grpc_resource_user_post_reclaimer( 525 usr, true, make_reclaimer(usr, 512, set_event(&destructive_done))); 526 grpc_core::ExecCtx::Get()->Flush(); 527 GPR_ASSERT(gpr_event_wait(&benign_done, 528 grpc_timeout_milliseconds_to_deadline(100)) == 529 nullptr); 530 GPR_ASSERT(gpr_event_wait(&destructive_done, 531 grpc_timeout_milliseconds_to_deadline(100)) == 532 nullptr); 533 } 534 { 535 gpr_event ev; 536 gpr_event_init(&ev); 537 grpc_core::ExecCtx exec_ctx; 538 grpc_resource_user_alloc(usr, 1024, set_event(&ev)); 539 grpc_core::ExecCtx::Get()->Flush(); 540 GPR_ASSERT(gpr_event_wait(&benign_done, 541 grpc_timeout_seconds_to_deadline(5)) != nullptr); 542 GPR_ASSERT(gpr_event_wait(&destructive_done, 543 grpc_timeout_seconds_to_deadline(5)) != nullptr); 544 GPR_ASSERT(gpr_event_wait(&ev, grpc_timeout_seconds_to_deadline(5)) != 545 nullptr); 546 ; 547 } 548 { 549 grpc_core::ExecCtx exec_ctx; 550 grpc_resource_user_free(usr, 1024); 551 } 552 grpc_resource_quota_unref(q); 553 destroy_user(usr); 554 GPR_ASSERT(gpr_event_wait(&benign_done, 555 grpc_timeout_seconds_to_deadline(5)) != nullptr); 556 GPR_ASSERT(gpr_event_wait(&destructive_done, 557 grpc_timeout_seconds_to_deadline(5)) != nullptr); 558 } 559 560 static void test_resource_user_stays_allocated_until_memory_released(void) { 561 gpr_log(GPR_INFO, 562 "** test_resource_user_stays_allocated_until_memory_released **"); 563 grpc_resource_quota* q = grpc_resource_quota_create( 564 "test_resource_user_stays_allocated_until_memory_released"); 565 grpc_resource_quota_resize(q, 1024 * 1024); 566 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 567 { 568 grpc_core::ExecCtx exec_ctx; 569 grpc_resource_user_alloc(usr, 1024, nullptr); 570 } 571 { 572 grpc_core::ExecCtx exec_ctx; 573 grpc_resource_quota_unref(q); 574 grpc_resource_user_unref(usr); 575 } 576 { 577 grpc_core::ExecCtx exec_ctx; 578 grpc_resource_user_free(usr, 1024); 579 } 580 } 581 582 static void 583 test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_released( 584 void) { 585 gpr_log(GPR_INFO, 586 "** " 587 "test_resource_user_stays_allocated_and_reclaimers_unrun_until_" 588 "memory_released **"); 589 grpc_resource_quota* q = grpc_resource_quota_create( 590 "test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_" 591 "released"); 592 grpc_resource_quota_resize(q, 1024); 593 for (int i = 0; i < 10; i++) { 594 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 595 gpr_event reclaimer_cancelled; 596 gpr_event_init(&reclaimer_cancelled); 597 { 598 grpc_core::ExecCtx exec_ctx; 599 grpc_resource_user_post_reclaimer( 600 usr, false, make_unused_reclaimer(set_event(&reclaimer_cancelled))); 601 grpc_core::ExecCtx::Get()->Flush(); 602 GPR_ASSERT(gpr_event_wait(&reclaimer_cancelled, 603 grpc_timeout_milliseconds_to_deadline(100)) == 604 nullptr); 605 } 606 { 607 gpr_event allocated; 608 gpr_event_init(&allocated); 609 grpc_core::ExecCtx exec_ctx; 610 grpc_resource_user_alloc(usr, 1024, set_event(&allocated)); 611 grpc_core::ExecCtx::Get()->Flush(); 612 GPR_ASSERT(gpr_event_wait(&allocated, grpc_timeout_seconds_to_deadline( 613 5)) != nullptr); 614 GPR_ASSERT(gpr_event_wait(&reclaimer_cancelled, 615 grpc_timeout_milliseconds_to_deadline(100)) == 616 nullptr); 617 } 618 { 619 grpc_core::ExecCtx exec_ctx; 620 grpc_resource_user_unref(usr); 621 grpc_core::ExecCtx::Get()->Flush(); 622 GPR_ASSERT(gpr_event_wait(&reclaimer_cancelled, 623 grpc_timeout_milliseconds_to_deadline(100)) == 624 nullptr); 625 } 626 { 627 grpc_core::ExecCtx exec_ctx; 628 grpc_resource_user_free(usr, 1024); 629 grpc_core::ExecCtx::Get()->Flush(); 630 GPR_ASSERT(gpr_event_wait(&reclaimer_cancelled, 631 grpc_timeout_seconds_to_deadline(5)) != 632 nullptr); 633 } 634 } 635 grpc_resource_quota_unref(q); 636 } 637 638 static void test_reclaimers_can_be_posted_repeatedly(void) { 639 gpr_log(GPR_INFO, "** test_reclaimers_can_be_posted_repeatedly **"); 640 grpc_resource_quota* q = 641 grpc_resource_quota_create("test_reclaimers_can_be_posted_repeatedly"); 642 grpc_resource_quota_resize(q, 1024); 643 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 644 { 645 gpr_event allocated; 646 gpr_event_init(&allocated); 647 grpc_core::ExecCtx exec_ctx; 648 grpc_resource_user_alloc(usr, 1024, set_event(&allocated)); 649 grpc_core::ExecCtx::Get()->Flush(); 650 GPR_ASSERT(gpr_event_wait(&allocated, 651 grpc_timeout_seconds_to_deadline(5)) != nullptr); 652 } 653 for (int i = 0; i < 10; i++) { 654 gpr_event reclaimer_done; 655 gpr_event_init(&reclaimer_done); 656 { 657 grpc_core::ExecCtx exec_ctx; 658 grpc_resource_user_post_reclaimer( 659 usr, false, make_reclaimer(usr, 1024, set_event(&reclaimer_done))); 660 grpc_core::ExecCtx::Get()->Flush(); 661 GPR_ASSERT(gpr_event_wait(&reclaimer_done, 662 grpc_timeout_milliseconds_to_deadline(100)) == 663 nullptr); 664 } 665 { 666 gpr_event allocated; 667 gpr_event_init(&allocated); 668 grpc_core::ExecCtx exec_ctx; 669 grpc_resource_user_alloc(usr, 1024, set_event(&allocated)); 670 grpc_core::ExecCtx::Get()->Flush(); 671 GPR_ASSERT(gpr_event_wait(&allocated, grpc_timeout_seconds_to_deadline( 672 5)) != nullptr); 673 GPR_ASSERT(gpr_event_wait(&reclaimer_done, 674 grpc_timeout_seconds_to_deadline(5)) != 675 nullptr); 676 } 677 } 678 { 679 grpc_core::ExecCtx exec_ctx; 680 grpc_resource_user_free(usr, 1024); 681 } 682 destroy_user(usr); 683 grpc_resource_quota_unref(q); 684 } 685 686 static void test_one_slice(void) { 687 gpr_log(GPR_INFO, "** test_one_slice **"); 688 689 grpc_resource_quota* q = grpc_resource_quota_create("test_one_slice"); 690 grpc_resource_quota_resize(q, 1024); 691 692 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 693 694 grpc_resource_user_slice_allocator alloc; 695 int num_allocs = 0; 696 grpc_resource_user_slice_allocator_init(&alloc, usr, inc_int_cb, &num_allocs); 697 698 grpc_slice_buffer buffer; 699 grpc_slice_buffer_init(&buffer); 700 701 { 702 const int start_allocs = num_allocs; 703 grpc_core::ExecCtx exec_ctx; 704 grpc_resource_user_alloc_slices(&alloc, 1024, 1, &buffer); 705 grpc_core::ExecCtx::Get()->Flush(); 706 assert_counter_becomes(&num_allocs, start_allocs + 1); 707 } 708 709 { 710 grpc_core::ExecCtx exec_ctx; 711 grpc_slice_buffer_destroy_internal(&buffer); 712 } 713 destroy_user(usr); 714 grpc_resource_quota_unref(q); 715 } 716 717 static void test_one_slice_deleted_late(void) { 718 gpr_log(GPR_INFO, "** test_one_slice_deleted_late **"); 719 720 grpc_resource_quota* q = 721 grpc_resource_quota_create("test_one_slice_deleted_late"); 722 grpc_resource_quota_resize(q, 1024); 723 724 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 725 726 grpc_resource_user_slice_allocator alloc; 727 int num_allocs = 0; 728 grpc_resource_user_slice_allocator_init(&alloc, usr, inc_int_cb, &num_allocs); 729 730 grpc_slice_buffer buffer; 731 grpc_slice_buffer_init(&buffer); 732 733 { 734 const int start_allocs = num_allocs; 735 grpc_core::ExecCtx exec_ctx; 736 grpc_resource_user_alloc_slices(&alloc, 1024, 1, &buffer); 737 grpc_core::ExecCtx::Get()->Flush(); 738 assert_counter_becomes(&num_allocs, start_allocs + 1); 739 } 740 741 { 742 grpc_core::ExecCtx exec_ctx; 743 grpc_resource_user_unref(usr); 744 } 745 746 grpc_resource_quota_unref(q); 747 { 748 grpc_core::ExecCtx exec_ctx; 749 grpc_slice_buffer_destroy_internal(&buffer); 750 } 751 } 752 753 static void test_resize_to_zero(void) { 754 gpr_log(GPR_INFO, "** test_resize_to_zero **"); 755 grpc_resource_quota* q = grpc_resource_quota_create("test_resize_to_zero"); 756 grpc_resource_quota_resize(q, 0); 757 grpc_resource_quota_unref(q); 758 } 759 760 static void test_negative_rq_free_pool(void) { 761 gpr_log(GPR_INFO, "** test_negative_rq_free_pool **"); 762 grpc_resource_quota* q = 763 grpc_resource_quota_create("test_negative_rq_free_pool"); 764 grpc_resource_quota_resize(q, 1024); 765 766 grpc_resource_user* usr = grpc_resource_user_create(q, "usr"); 767 768 grpc_resource_user_slice_allocator alloc; 769 int num_allocs = 0; 770 grpc_resource_user_slice_allocator_init(&alloc, usr, inc_int_cb, &num_allocs); 771 772 grpc_slice_buffer buffer; 773 grpc_slice_buffer_init(&buffer); 774 775 { 776 const int start_allocs = num_allocs; 777 grpc_core::ExecCtx exec_ctx; 778 grpc_resource_user_alloc_slices(&alloc, 1024, 1, &buffer); 779 grpc_core::ExecCtx::Get()->Flush(); 780 assert_counter_becomes(&num_allocs, start_allocs + 1); 781 } 782 783 grpc_resource_quota_resize(q, 512); 784 785 double eps = 0.0001; 786 GPR_ASSERT(grpc_resource_quota_get_memory_pressure(q) < 1 + eps); 787 GPR_ASSERT(grpc_resource_quota_get_memory_pressure(q) > 1 - eps); 788 789 { 790 grpc_core::ExecCtx exec_ctx; 791 grpc_resource_user_unref(usr); 792 } 793 794 grpc_resource_quota_unref(q); 795 { 796 grpc_core::ExecCtx exec_ctx; 797 grpc_slice_buffer_destroy_internal(&buffer); 798 } 799 } 800 801 // Simple test to check resource quota thread limits 802 static void test_thread_limit() { 803 grpc_core::ExecCtx exec_ctx; 804 805 grpc_resource_quota* rq = grpc_resource_quota_create("test_thread_limit"); 806 grpc_resource_user* ru1 = grpc_resource_user_create(rq, "ru1"); 807 grpc_resource_user* ru2 = grpc_resource_user_create(rq, "ru2"); 808 809 // Max threads = 100 810 grpc_resource_quota_set_max_threads(rq, 100); 811 812 // Request quota for 100 threads (50 for ru1, 50 for ru2) 813 GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 10)); 814 GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 10)); 815 GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 40)); 816 GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 40)); 817 818 // Threads exhausted. Next request must fail 819 GPR_ASSERT(!grpc_resource_user_allocate_threads(ru2, 20)); 820 821 // Free 20 threads from two different users 822 grpc_resource_user_free_threads(ru1, 10); 823 grpc_resource_user_free_threads(ru2, 10); 824 825 // Next request to 20 threads must succeed 826 GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 20)); 827 828 // No more thread quota again 829 GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 20)); 830 831 // Free 10 more 832 grpc_resource_user_free_threads(ru1, 10); 833 834 GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 5)); 835 GPR_ASSERT( 836 !grpc_resource_user_allocate_threads(ru2, 10)); // Only 5 available 837 GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 5)); 838 839 // Teardown (ru1 and ru2 release all the quota back to rq) 840 grpc_resource_user_unref(ru1); 841 grpc_resource_user_unref(ru2); 842 grpc_resource_quota_unref(rq); 843 } 844 845 // Change max quota in either direction dynamically 846 static void test_thread_maxquota_change() { 847 grpc_core::ExecCtx exec_ctx; 848 849 grpc_resource_quota* rq = 850 grpc_resource_quota_create("test_thread_maxquota_change"); 851 grpc_resource_user* ru1 = grpc_resource_user_create(rq, "ru1"); 852 grpc_resource_user* ru2 = grpc_resource_user_create(rq, "ru2"); 853 854 // Max threads = 100 855 grpc_resource_quota_set_max_threads(rq, 100); 856 857 // Request quota for 100 threads (50 for ru1, 50 for ru2) 858 GPR_ASSERT(grpc_resource_user_allocate_threads(ru1, 50)); 859 GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 50)); 860 861 // Threads exhausted. Next request must fail 862 GPR_ASSERT(!grpc_resource_user_allocate_threads(ru2, 20)); 863 864 // Increase maxquota and retry 865 // Max threads = 150; 866 grpc_resource_quota_set_max_threads(rq, 150); 867 GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 20)); // ru2=70, ru1=50 868 869 // Decrease maxquota (Note: Quota already given to ru1 and ru2 is unaffected) 870 // Max threads = 10; 871 grpc_resource_quota_set_max_threads(rq, 10); 872 873 // New requests will fail until quota is available 874 GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 10)); 875 876 // Make quota available 877 grpc_resource_user_free_threads(ru1, 50); // ru1 now has 0 878 GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 10)); // not enough 879 880 grpc_resource_user_free_threads(ru2, 70); // ru2 now has 0 881 882 // Now we can get quota up-to 10, the current max 883 GPR_ASSERT(grpc_resource_user_allocate_threads(ru2, 10)); 884 // No more thread quota again 885 GPR_ASSERT(!grpc_resource_user_allocate_threads(ru1, 10)); 886 887 // Teardown (ru1 and ru2 release all the quota back to rq) 888 grpc_resource_user_unref(ru1); 889 grpc_resource_user_unref(ru2); 890 grpc_resource_quota_unref(rq); 891 } 892 893 int main(int argc, char** argv) { 894 grpc_test_init(argc, argv); 895 grpc_init(); 896 gpr_mu_init(&g_mu); 897 gpr_cv_init(&g_cv); 898 test_no_op(); 899 test_resize_then_destroy(); 900 test_resource_user_no_op(); 901 test_instant_alloc_then_free(); 902 test_instant_alloc_free_pair(); 903 test_simple_async_alloc(); 904 test_async_alloc_blocked_by_size(); 905 test_scavenge(); 906 test_scavenge_blocked(); 907 test_blocked_until_scheduled_reclaim(); 908 test_blocked_until_scheduled_reclaim_and_scavenge(); 909 test_blocked_until_scheduled_destructive_reclaim(); 910 test_unused_reclaim_is_cancelled(); 911 test_benign_reclaim_is_preferred(); 912 test_multiple_reclaims_can_be_triggered(); 913 test_resource_user_stays_allocated_until_memory_released(); 914 test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_released(); 915 test_reclaimers_can_be_posted_repeatedly(); 916 test_one_slice(); 917 test_one_slice_deleted_late(); 918 test_resize_to_zero(); 919 test_negative_rq_free_pool(); 920 gpr_mu_destroy(&g_mu); 921 gpr_cv_destroy(&g_cv); 922 923 // Resource quota thread related 924 test_thread_limit(); 925 test_thread_maxquota_change(); 926 927 grpc_shutdown(); 928 return 0; 929 } 930