test_bwmgt.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /* Copyright (c) 2018-2019, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file test_bwmgt.c
  5. * \brief tests for bandwidth management / token bucket functions
  6. */
  7. #define TOKEN_BUCKET_PRIVATE
  8. #include "core/or/or.h"
  9. #include "test/test.h"
  10. #include "lib/evloop/token_bucket.h"
  11. // an imaginary time, in timestamp units. Chosen so it will roll over.
  12. static const uint32_t START_TS = UINT32_MAX-10;
  13. static const int32_t KB = 1024;
  14. static const uint32_t GB = (UINT64_C(1) << 30);
  15. static void
  16. test_bwmgt_token_buf_init(void *arg)
  17. {
  18. (void)arg;
  19. token_bucket_rw_t b;
  20. token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
  21. // Burst is correct
  22. tt_uint_op(b.cfg.burst, OP_EQ, 64*KB);
  23. // Rate is correct, within 1 percent.
  24. {
  25. uint32_t ticks_per_sec =
  26. (uint32_t) monotime_msec_to_approx_coarse_stamp_units(1000);
  27. uint32_t rate_per_sec = (b.cfg.rate * ticks_per_sec / TICKS_PER_STEP);
  28. tt_uint_op(rate_per_sec, OP_GT, 16*KB-160);
  29. tt_uint_op(rate_per_sec, OP_LT, 16*KB+160);
  30. }
  31. // Bucket starts out full:
  32. tt_uint_op(b.last_refilled_at_timestamp, OP_EQ, START_TS);
  33. tt_int_op(b.read_bucket.bucket, OP_EQ, 64*KB);
  34. done:
  35. ;
  36. }
  37. static void
  38. test_bwmgt_token_buf_adjust(void *arg)
  39. {
  40. (void)arg;
  41. token_bucket_rw_t b;
  42. token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
  43. uint32_t rate_orig = b.cfg.rate;
  44. // Increasing burst
  45. token_bucket_rw_adjust(&b, 16*KB, 128*KB);
  46. tt_uint_op(b.cfg.rate, OP_EQ, rate_orig);
  47. tt_uint_op(b.read_bucket.bucket, OP_EQ, 64*KB);
  48. tt_uint_op(b.cfg.burst, OP_EQ, 128*KB);
  49. // Decreasing burst but staying above bucket
  50. token_bucket_rw_adjust(&b, 16*KB, 96*KB);
  51. tt_uint_op(b.cfg.rate, OP_EQ, rate_orig);
  52. tt_uint_op(b.read_bucket.bucket, OP_EQ, 64*KB);
  53. tt_uint_op(b.cfg.burst, OP_EQ, 96*KB);
  54. // Decreasing burst below bucket,
  55. token_bucket_rw_adjust(&b, 16*KB, 48*KB);
  56. tt_uint_op(b.cfg.rate, OP_EQ, rate_orig);
  57. tt_uint_op(b.read_bucket.bucket, OP_EQ, 48*KB);
  58. tt_uint_op(b.cfg.burst, OP_EQ, 48*KB);
  59. // Changing rate.
  60. token_bucket_rw_adjust(&b, 32*KB, 48*KB);
  61. tt_uint_op(b.cfg.rate, OP_GE, rate_orig*2 - 10);
  62. tt_uint_op(b.cfg.rate, OP_LE, rate_orig*2 + 10);
  63. tt_uint_op(b.read_bucket.bucket, OP_EQ, 48*KB);
  64. tt_uint_op(b.cfg.burst, OP_EQ, 48*KB);
  65. done:
  66. ;
  67. }
  68. static void
  69. test_bwmgt_token_buf_dec(void *arg)
  70. {
  71. (void)arg;
  72. token_bucket_rw_t b;
  73. token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
  74. // full-to-not-full.
  75. tt_int_op(0, OP_EQ, token_bucket_rw_dec_read(&b, KB));
  76. tt_int_op(b.read_bucket.bucket, OP_EQ, 63*KB);
  77. // Full to almost-not-full
  78. tt_int_op(0, OP_EQ, token_bucket_rw_dec_read(&b, 63*KB - 1));
  79. tt_int_op(b.read_bucket.bucket, OP_EQ, 1);
  80. // almost-not-full to empty.
  81. tt_int_op(1, OP_EQ, token_bucket_rw_dec_read(&b, 1));
  82. tt_int_op(b.read_bucket.bucket, OP_EQ, 0);
  83. // reset bucket, try full-to-empty
  84. token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
  85. tt_int_op(1, OP_EQ, token_bucket_rw_dec_read(&b, 64*KB));
  86. tt_int_op(b.read_bucket.bucket, OP_EQ, 0);
  87. // reset bucket, try underflow.
  88. token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
  89. tt_int_op(1, OP_EQ, token_bucket_rw_dec_read(&b, 64*KB + 1));
  90. tt_int_op(b.read_bucket.bucket, OP_EQ, -1);
  91. // A second underflow does not make the bucket empty.
  92. tt_int_op(0, OP_EQ, token_bucket_rw_dec_read(&b, 1000));
  93. tt_int_op(b.read_bucket.bucket, OP_EQ, -1001);
  94. done:
  95. ;
  96. }
  97. static void
  98. test_bwmgt_token_buf_refill(void *arg)
  99. {
  100. (void)arg;
  101. token_bucket_rw_t b;
  102. const uint32_t BW_SEC =
  103. (uint32_t)monotime_msec_to_approx_coarse_stamp_units(1000);
  104. token_bucket_rw_init(&b, 16*KB, 64*KB, START_TS);
  105. /* Make the buffer much emptier, then let one second elapse. */
  106. token_bucket_rw_dec_read(&b, 48*KB);
  107. tt_int_op(b.read_bucket.bucket, OP_EQ, 16*KB);
  108. tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + BW_SEC));
  109. tt_int_op(b.read_bucket.bucket, OP_GT, 32*KB - 300);
  110. tt_int_op(b.read_bucket.bucket, OP_LT, 32*KB + 300);
  111. /* Another half second. */
  112. tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + BW_SEC*3/2));
  113. tt_int_op(b.read_bucket.bucket, OP_GT, 40*KB - 400);
  114. tt_int_op(b.read_bucket.bucket, OP_LT, 40*KB + 400);
  115. tt_uint_op(b.last_refilled_at_timestamp, OP_EQ, START_TS + BW_SEC*3/2);
  116. /* No time: nothing happens. */
  117. {
  118. const uint32_t bucket_orig = b.read_bucket.bucket;
  119. tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + BW_SEC*3/2));
  120. tt_int_op(b.read_bucket.bucket, OP_EQ, bucket_orig);
  121. }
  122. /* Another 30 seconds: fill the bucket. */
  123. tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b,
  124. START_TS + BW_SEC*3/2 + BW_SEC*30));
  125. tt_int_op(b.read_bucket.bucket, OP_EQ, b.cfg.burst);
  126. tt_uint_op(b.last_refilled_at_timestamp, OP_EQ,
  127. START_TS + BW_SEC*3/2 + BW_SEC*30);
  128. /* Another 30 seconds: nothing happens. */
  129. tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b,
  130. START_TS + BW_SEC*3/2 + BW_SEC*60));
  131. tt_int_op(b.read_bucket.bucket, OP_EQ, b.cfg.burst);
  132. tt_uint_op(b.last_refilled_at_timestamp, OP_EQ,
  133. START_TS + BW_SEC*3/2 + BW_SEC*60);
  134. /* Empty the bucket, let two seconds pass, and make sure that a refill is
  135. * noticed. */
  136. tt_int_op(1, OP_EQ, token_bucket_rw_dec_read(&b, b.cfg.burst));
  137. tt_int_op(0, OP_EQ, b.read_bucket.bucket);
  138. tt_int_op(1, OP_EQ, token_bucket_rw_refill(&b,
  139. START_TS + BW_SEC*3/2 + BW_SEC*61));
  140. tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b,
  141. START_TS + BW_SEC*3/2 + BW_SEC*62));
  142. tt_int_op(b.read_bucket.bucket, OP_GT, 32*KB-400);
  143. tt_int_op(b.read_bucket.bucket, OP_LT, 32*KB+400);
  144. /* Underflow the bucket, make sure we detect when it has tokens again. */
  145. tt_int_op(1, OP_EQ,
  146. token_bucket_rw_dec_read(&b, b.read_bucket.bucket+16*KB));
  147. tt_int_op(-16*KB, OP_EQ, b.read_bucket.bucket);
  148. // half a second passes...
  149. tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + BW_SEC*64));
  150. tt_int_op(b.read_bucket.bucket, OP_GT, -8*KB-300);
  151. tt_int_op(b.read_bucket.bucket, OP_LT, -8*KB+300);
  152. // a second passes
  153. tt_int_op(1, OP_EQ, token_bucket_rw_refill(&b, START_TS + BW_SEC*65));
  154. tt_int_op(b.read_bucket.bucket, OP_GT, 8*KB-400);
  155. tt_int_op(b.read_bucket.bucket, OP_LT, 8*KB+400);
  156. // We step a second backwards, and nothing happens.
  157. tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, START_TS + BW_SEC*64));
  158. tt_int_op(b.read_bucket.bucket, OP_GT, 8*KB-400);
  159. tt_int_op(b.read_bucket.bucket, OP_LT, 8*KB+400);
  160. // A ridiculous amount of time passes.
  161. tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, INT32_MAX));
  162. tt_int_op(b.read_bucket.bucket, OP_EQ, b.cfg.burst);
  163. done:
  164. ;
  165. }
  166. /* Test some helper functions we use within the token bucket interface. */
  167. static void
  168. test_bwmgt_token_buf_helpers(void *arg)
  169. {
  170. uint32_t ret;
  171. (void) arg;
  172. /* The returned value will be OS specific but in any case, it should be
  173. * greater than 1 since we are passing 1GB/sec rate. */
  174. ret = rate_per_sec_to_rate_per_step(1 * GB);
  175. tt_u64_op(ret, OP_GT, 1);
  176. /* We default to 1 in case rate is 0. */
  177. ret = rate_per_sec_to_rate_per_step(0);
  178. tt_u64_op(ret, OP_EQ, 1);
  179. done:
  180. ;
  181. }
  182. #define BWMGT(name) \
  183. { #name, test_bwmgt_ ## name , 0, NULL, NULL }
  184. struct testcase_t bwmgt_tests[] = {
  185. BWMGT(token_buf_init),
  186. BWMGT(token_buf_adjust),
  187. BWMGT(token_buf_dec),
  188. BWMGT(token_buf_refill),
  189. BWMGT(token_buf_helpers),
  190. END_OF_TESTCASES
  191. };