memefficiency.tcl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. proc test_memory_efficiency {range} {
  2. r flushall
  3. set rd [redis_deferring_client]
  4. set base_mem [s used_memory]
  5. set written 0
  6. for {set j 0} {$j < 10000} {incr j} {
  7. set key key:$j
  8. set val [string repeat A [expr {int(rand()*$range)}]]
  9. $rd set $key $val
  10. incr written [string length $key]
  11. incr written [string length $val]
  12. incr written 2 ;# A separator is the minimum to store key-value data.
  13. }
  14. for {set j 0} {$j < 10000} {incr j} {
  15. $rd read ; # Discard replies
  16. }
  17. set current_mem [s used_memory]
  18. set used [expr {$current_mem-$base_mem}]
  19. set efficiency [expr {double($written)/$used}]
  20. return $efficiency
  21. }
  22. start_server {tags {"memefficiency"}} {
  23. foreach {size_range expected_min_efficiency} {
  24. 32 0.15
  25. 64 0.25
  26. 128 0.35
  27. 1024 0.75
  28. 16384 0.82
  29. } {
  30. test "Memory efficiency with values in range $size_range" {
  31. set efficiency [test_memory_efficiency $size_range]
  32. assert {$efficiency >= $expected_min_efficiency}
  33. }
  34. }
  35. }
  36. start_server {tags {"defrag"}} {
  37. if {[string match {*jemalloc*} [s mem_allocator]]} {
  38. test "Active defrag" {
  39. r config set save "" ;# prevent bgsave from interfereing with save below
  40. r config set hz 100
  41. r config set activedefrag no
  42. r config set active-defrag-threshold-lower 5
  43. r config set active-defrag-cycle-min 65
  44. r config set active-defrag-cycle-max 75
  45. r config set active-defrag-ignore-bytes 2mb
  46. r config set maxmemory 100mb
  47. r config set maxmemory-policy allkeys-lru
  48. r debug populate 700000 asdf1 150
  49. r debug populate 170000 asdf2 300
  50. r ping ;# trigger eviction following the previous population
  51. after 120 ;# serverCron only updates the info once in 100ms
  52. set frag [s allocator_frag_ratio]
  53. if {$::verbose} {
  54. puts "frag $frag"
  55. }
  56. assert {$frag >= 1.4}
  57. r config set latency-monitor-threshold 5
  58. r latency reset
  59. r config set maxmemory 110mb ;# prevent further eviction (not to fail the digest test)
  60. set digest [r debug digest]
  61. catch {r config set activedefrag yes} e
  62. if {![string match {DISABLED*} $e]} {
  63. # Wait for the active defrag to start working (decision once a
  64. # second).
  65. wait_for_condition 50 100 {
  66. [s active_defrag_running] ne 0
  67. } else {
  68. fail "defrag not started."
  69. }
  70. # Wait for the active defrag to stop working.
  71. wait_for_condition 150 100 {
  72. [s active_defrag_running] eq 0
  73. } else {
  74. after 120 ;# serverCron only updates the info once in 100ms
  75. puts [r info memory]
  76. puts [r memory malloc-stats]
  77. fail "defrag didn't stop."
  78. }
  79. # Test the the fragmentation is lower.
  80. after 120 ;# serverCron only updates the info once in 100ms
  81. set frag [s allocator_frag_ratio]
  82. set max_latency 0
  83. foreach event [r latency latest] {
  84. lassign $event eventname time latency max
  85. if {$eventname == "active-defrag-cycle"} {
  86. set max_latency $max
  87. }
  88. }
  89. if {$::verbose} {
  90. puts "frag $frag"
  91. puts "max latency $max_latency"
  92. puts [r latency latest]
  93. puts [r latency history active-defrag-cycle]
  94. }
  95. assert {$frag < 1.1}
  96. # due to high fragmentation, 100hz, and active-defrag-cycle-max set to 75,
  97. # we expect max latency to be not much higher than 7.5ms but due to rare slowness threshold is set higher
  98. assert {$max_latency <= 30}
  99. } else {
  100. set _ ""
  101. }
  102. # verify the data isn't corrupted or changed
  103. set newdigest [r debug digest]
  104. assert {$digest eq $newdigest}
  105. r save ;# saving an rdb iterates over all the data / pointers
  106. } {OK}
  107. test "Active defrag big keys" {
  108. r flushdb
  109. r config resetstat
  110. r config set save "" ;# prevent bgsave from interfereing with save below
  111. r config set hz 100
  112. r config set activedefrag no
  113. r config set active-defrag-max-scan-fields 1000
  114. r config set active-defrag-threshold-lower 5
  115. r config set active-defrag-cycle-min 65
  116. r config set active-defrag-cycle-max 75
  117. r config set active-defrag-ignore-bytes 2mb
  118. r config set maxmemory 0
  119. r config set list-max-ziplist-size 5 ;# list of 10k items will have 2000 quicklist nodes
  120. r config set stream-node-max-entries 5
  121. r hmset hash h1 v1 h2 v2 h3 v3
  122. r lpush list a b c d
  123. r zadd zset 0 a 1 b 2 c 3 d
  124. r sadd set a b c d
  125. r xadd stream * item 1 value a
  126. r xadd stream * item 2 value b
  127. r xgroup create stream mygroup 0
  128. r xreadgroup GROUP mygroup Alice COUNT 1 STREAMS stream >
  129. # create big keys with 10k items
  130. set rd [redis_deferring_client]
  131. for {set j 0} {$j < 10000} {incr j} {
  132. $rd hset bighash $j [concat "asdfasdfasdf" $j]
  133. $rd lpush biglist [concat "asdfasdfasdf" $j]
  134. $rd zadd bigzset $j [concat "asdfasdfasdf" $j]
  135. $rd sadd bigset [concat "asdfasdfasdf" $j]
  136. $rd xadd bigstream * item 1 value a
  137. }
  138. for {set j 0} {$j < 50000} {incr j} {
  139. $rd read ; # Discard replies
  140. }
  141. set expected_frag 1.7
  142. if {$::accurate} {
  143. # scale the hash to 1m fields in order to have a measurable the latency
  144. for {set j 10000} {$j < 1000000} {incr j} {
  145. $rd hset bighash $j [concat "asdfasdfasdf" $j]
  146. }
  147. for {set j 10000} {$j < 1000000} {incr j} {
  148. $rd read ; # Discard replies
  149. }
  150. # creating that big hash, increased used_memory, so the relative frag goes down
  151. set expected_frag 1.3
  152. }
  153. # add a mass of string keys
  154. for {set j 0} {$j < 500000} {incr j} {
  155. $rd setrange $j 150 a
  156. }
  157. for {set j 0} {$j < 500000} {incr j} {
  158. $rd read ; # Discard replies
  159. }
  160. assert_equal [r dbsize] 500010
  161. # create some fragmentation
  162. for {set j 0} {$j < 500000} {incr j 2} {
  163. $rd del $j
  164. }
  165. for {set j 0} {$j < 500000} {incr j 2} {
  166. $rd read ; # Discard replies
  167. }
  168. assert_equal [r dbsize] 250010
  169. # start defrag
  170. after 120 ;# serverCron only updates the info once in 100ms
  171. set frag [s allocator_frag_ratio]
  172. if {$::verbose} {
  173. puts "frag $frag"
  174. }
  175. assert {$frag >= $expected_frag}
  176. r config set latency-monitor-threshold 5
  177. r latency reset
  178. set digest [r debug digest]
  179. catch {r config set activedefrag yes} e
  180. if {![string match {DISABLED*} $e]} {
  181. # wait for the active defrag to start working (decision once a second)
  182. wait_for_condition 50 100 {
  183. [s active_defrag_running] ne 0
  184. } else {
  185. fail "defrag not started."
  186. }
  187. # wait for the active defrag to stop working
  188. wait_for_condition 500 100 {
  189. [s active_defrag_running] eq 0
  190. } else {
  191. after 120 ;# serverCron only updates the info once in 100ms
  192. puts [r info memory]
  193. puts [r memory malloc-stats]
  194. fail "defrag didn't stop."
  195. }
  196. # test the the fragmentation is lower
  197. after 120 ;# serverCron only updates the info once in 100ms
  198. set frag [s allocator_frag_ratio]
  199. set max_latency 0
  200. foreach event [r latency latest] {
  201. lassign $event eventname time latency max
  202. if {$eventname == "active-defrag-cycle"} {
  203. set max_latency $max
  204. }
  205. }
  206. if {$::verbose} {
  207. puts "frag $frag"
  208. puts "max latency $max_latency"
  209. puts [r latency latest]
  210. puts [r latency history active-defrag-cycle]
  211. }
  212. assert {$frag < 1.1}
  213. # due to high fragmentation, 100hz, and active-defrag-cycle-max set to 75,
  214. # we expect max latency to be not much higher than 7.5ms but due to rare slowness threshold is set higher
  215. assert {$max_latency <= 30}
  216. }
  217. # verify the data isn't corrupted or changed
  218. set newdigest [r debug digest]
  219. assert {$digest eq $newdigest}
  220. r save ;# saving an rdb iterates over all the data / pointers
  221. } {OK}
  222. test "Active defrag big list" {
  223. r flushdb
  224. r config resetstat
  225. r config set save "" ;# prevent bgsave from interfereing with save below
  226. r config set hz 100
  227. r config set activedefrag no
  228. r config set active-defrag-max-scan-fields 1000
  229. r config set active-defrag-threshold-lower 5
  230. r config set active-defrag-cycle-min 65
  231. r config set active-defrag-cycle-max 75
  232. r config set active-defrag-ignore-bytes 2mb
  233. r config set maxmemory 0
  234. r config set list-max-ziplist-size 5 ;# list of 500k items will have 100k quicklist nodes
  235. # create big keys with 10k items
  236. set rd [redis_deferring_client]
  237. set expected_frag 1.7
  238. # add a mass of list nodes to two lists (allocations are interlaced)
  239. set val [string repeat A 100] ;# 5 items of 100 bytes puts us in the 640 bytes bin, which has 32 regs, so high potential for fragmentation
  240. for {set j 0} {$j < 500000} {incr j} {
  241. $rd lpush biglist1 $val
  242. $rd lpush biglist2 $val
  243. }
  244. for {set j 0} {$j < 500000} {incr j} {
  245. $rd read ; # Discard replies
  246. $rd read ; # Discard replies
  247. }
  248. # create some fragmentation
  249. r del biglist2
  250. # start defrag
  251. after 120 ;# serverCron only updates the info once in 100ms
  252. set frag [s allocator_frag_ratio]
  253. if {$::verbose} {
  254. puts "frag $frag"
  255. }
  256. assert {$frag >= $expected_frag}
  257. r config set latency-monitor-threshold 5
  258. r latency reset
  259. set digest [r debug digest]
  260. catch {r config set activedefrag yes} e
  261. if {![string match {DISABLED*} $e]} {
  262. # wait for the active defrag to start working (decision once a second)
  263. wait_for_condition 50 100 {
  264. [s active_defrag_running] ne 0
  265. } else {
  266. fail "defrag not started."
  267. }
  268. # wait for the active defrag to stop working
  269. wait_for_condition 500 100 {
  270. [s active_defrag_running] eq 0
  271. } else {
  272. after 120 ;# serverCron only updates the info once in 100ms
  273. puts [r info memory]
  274. puts [r info stats]
  275. puts [r memory malloc-stats]
  276. fail "defrag didn't stop."
  277. }
  278. # test the the fragmentation is lower
  279. after 120 ;# serverCron only updates the info once in 100ms
  280. set frag [s allocator_frag_ratio]
  281. set max_latency 0
  282. foreach event [r latency latest] {
  283. lassign $event eventname time latency max
  284. if {$eventname == "active-defrag-cycle"} {
  285. set max_latency $max
  286. }
  287. }
  288. if {$::verbose} {
  289. puts "frag $frag"
  290. puts "max latency $max_latency"
  291. puts [r latency latest]
  292. puts [r latency history active-defrag-cycle]
  293. }
  294. assert {$frag < 1.1}
  295. # due to high fragmentation, 100hz, and active-defrag-cycle-max set to 75,
  296. # we expect max latency to be not much higher than 7.5ms but due to rare slowness threshold is set higher
  297. assert {$max_latency <= 30}
  298. }
  299. # verify the data isn't corrupted or changed
  300. set newdigest [r debug digest]
  301. assert {$digest eq $newdigest}
  302. r save ;# saving an rdb iterates over all the data / pointers
  303. r del biglist1 ;# coverage for quicklistBookmarksClear
  304. } {1}
  305. }
  306. }