2
0

memefficiency.tcl 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  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. run_solo {defrag} {
  37. start_server {tags {"defrag"}} {
  38. if {[string match {*jemalloc*} [s mem_allocator]]} {
  39. test "Active defrag" {
  40. r config set save "" ;# prevent bgsave from interfereing with save below
  41. r config set hz 100
  42. r config set activedefrag no
  43. r config set active-defrag-threshold-lower 5
  44. r config set active-defrag-cycle-min 65
  45. r config set active-defrag-cycle-max 75
  46. r config set active-defrag-ignore-bytes 2mb
  47. r config set maxmemory 100mb
  48. r config set maxmemory-policy allkeys-lru
  49. r debug populate 700000 asdf1 150
  50. r debug populate 170000 asdf2 300
  51. r ping ;# trigger eviction following the previous population
  52. after 120 ;# serverCron only updates the info once in 100ms
  53. set frag [s allocator_frag_ratio]
  54. if {$::verbose} {
  55. puts "frag $frag"
  56. }
  57. assert {$frag >= 1.4}
  58. r config set latency-monitor-threshold 5
  59. r latency reset
  60. r config set maxmemory 110mb ;# prevent further eviction (not to fail the digest test)
  61. set digest [r debug digest]
  62. catch {r config set activedefrag yes} e
  63. if {![string match {DISABLED*} $e]} {
  64. # Wait for the active defrag to start working (decision once a
  65. # second).
  66. wait_for_condition 50 100 {
  67. [s active_defrag_running] ne 0
  68. } else {
  69. fail "defrag not started."
  70. }
  71. # Wait for the active defrag to stop working.
  72. wait_for_condition 150 100 {
  73. [s active_defrag_running] eq 0
  74. } else {
  75. after 120 ;# serverCron only updates the info once in 100ms
  76. puts [r info memory]
  77. puts [r memory malloc-stats]
  78. fail "defrag didn't stop."
  79. }
  80. # Test the the fragmentation is lower.
  81. after 120 ;# serverCron only updates the info once in 100ms
  82. set frag [s allocator_frag_ratio]
  83. set max_latency 0
  84. foreach event [r latency latest] {
  85. lassign $event eventname time latency max
  86. if {$eventname == "active-defrag-cycle"} {
  87. set max_latency $max
  88. }
  89. }
  90. if {$::verbose} {
  91. puts "frag $frag"
  92. set misses [s active_defrag_misses]
  93. set hits [s active_defrag_hits]
  94. puts "hits: $hits"
  95. puts "misses: $misses"
  96. puts "max latency $max_latency"
  97. puts [r latency latest]
  98. puts [r latency history active-defrag-cycle]
  99. }
  100. assert {$frag < 1.1}
  101. # due to high fragmentation, 100hz, and active-defrag-cycle-max set to 75,
  102. # we expect max latency to be not much higher than 7.5ms but due to rare slowness threshold is set higher
  103. assert {$max_latency <= 30}
  104. } else {
  105. set _ ""
  106. }
  107. # verify the data isn't corrupted or changed
  108. set newdigest [r debug digest]
  109. assert {$digest eq $newdigest}
  110. r save ;# saving an rdb iterates over all the data / pointers
  111. } {OK}
  112. test "Active defrag big keys" {
  113. r flushdb
  114. r config resetstat
  115. r config set save "" ;# prevent bgsave from interfereing with save below
  116. r config set hz 100
  117. r config set activedefrag no
  118. r config set active-defrag-max-scan-fields 1000
  119. r config set active-defrag-threshold-lower 5
  120. r config set active-defrag-cycle-min 65
  121. r config set active-defrag-cycle-max 75
  122. r config set active-defrag-ignore-bytes 2mb
  123. r config set maxmemory 0
  124. r config set list-max-ziplist-size 5 ;# list of 10k items will have 2000 quicklist nodes
  125. r config set stream-node-max-entries 5
  126. r hmset hash h1 v1 h2 v2 h3 v3
  127. r lpush list a b c d
  128. r zadd zset 0 a 1 b 2 c 3 d
  129. r sadd set a b c d
  130. r xadd stream * item 1 value a
  131. r xadd stream * item 2 value b
  132. r xgroup create stream mygroup 0
  133. r xreadgroup GROUP mygroup Alice COUNT 1 STREAMS stream >
  134. # create big keys with 10k items
  135. set rd [redis_deferring_client]
  136. for {set j 0} {$j < 10000} {incr j} {
  137. $rd hset bighash $j [concat "asdfasdfasdf" $j]
  138. $rd lpush biglist [concat "asdfasdfasdf" $j]
  139. $rd zadd bigzset $j [concat "asdfasdfasdf" $j]
  140. $rd sadd bigset [concat "asdfasdfasdf" $j]
  141. $rd xadd bigstream * item 1 value a
  142. }
  143. for {set j 0} {$j < 50000} {incr j} {
  144. $rd read ; # Discard replies
  145. }
  146. set expected_frag 1.7
  147. if {$::accurate} {
  148. # scale the hash to 1m fields in order to have a measurable the latency
  149. for {set j 10000} {$j < 1000000} {incr j} {
  150. $rd hset bighash $j [concat "asdfasdfasdf" $j]
  151. }
  152. for {set j 10000} {$j < 1000000} {incr j} {
  153. $rd read ; # Discard replies
  154. }
  155. # creating that big hash, increased used_memory, so the relative frag goes down
  156. set expected_frag 1.3
  157. }
  158. # add a mass of string keys
  159. for {set j 0} {$j < 500000} {incr j} {
  160. $rd setrange $j 150 a
  161. }
  162. for {set j 0} {$j < 500000} {incr j} {
  163. $rd read ; # Discard replies
  164. }
  165. assert_equal [r dbsize] 500010
  166. # create some fragmentation
  167. for {set j 0} {$j < 500000} {incr j 2} {
  168. $rd del $j
  169. }
  170. for {set j 0} {$j < 500000} {incr j 2} {
  171. $rd read ; # Discard replies
  172. }
  173. assert_equal [r dbsize] 250010
  174. # start defrag
  175. after 120 ;# serverCron only updates the info once in 100ms
  176. set frag [s allocator_frag_ratio]
  177. if {$::verbose} {
  178. puts "frag $frag"
  179. }
  180. assert {$frag >= $expected_frag}
  181. r config set latency-monitor-threshold 5
  182. r latency reset
  183. set digest [r debug digest]
  184. catch {r config set activedefrag yes} e
  185. if {![string match {DISABLED*} $e]} {
  186. # wait for the active defrag to start working (decision once a second)
  187. wait_for_condition 50 100 {
  188. [s active_defrag_running] ne 0
  189. } else {
  190. fail "defrag not started."
  191. }
  192. # wait for the active defrag to stop working
  193. wait_for_condition 500 100 {
  194. [s active_defrag_running] eq 0
  195. } else {
  196. after 120 ;# serverCron only updates the info once in 100ms
  197. puts [r info memory]
  198. puts [r memory malloc-stats]
  199. fail "defrag didn't stop."
  200. }
  201. # test the the fragmentation is lower
  202. after 120 ;# serverCron only updates the info once in 100ms
  203. set frag [s allocator_frag_ratio]
  204. set max_latency 0
  205. foreach event [r latency latest] {
  206. lassign $event eventname time latency max
  207. if {$eventname == "active-defrag-cycle"} {
  208. set max_latency $max
  209. }
  210. }
  211. if {$::verbose} {
  212. puts "frag $frag"
  213. set misses [s active_defrag_misses]
  214. set hits [s active_defrag_hits]
  215. puts "hits: $hits"
  216. puts "misses: $misses"
  217. puts "max latency $max_latency"
  218. puts [r latency latest]
  219. puts [r latency history active-defrag-cycle]
  220. }
  221. assert {$frag < 1.1}
  222. # due to high fragmentation, 100hz, and active-defrag-cycle-max set to 75,
  223. # we expect max latency to be not much higher than 7.5ms but due to rare slowness threshold is set higher
  224. assert {$max_latency <= 30}
  225. }
  226. # verify the data isn't corrupted or changed
  227. set newdigest [r debug digest]
  228. assert {$digest eq $newdigest}
  229. r save ;# saving an rdb iterates over all the data / pointers
  230. } {OK}
  231. test "Active defrag big list" {
  232. r flushdb
  233. r config resetstat
  234. r config set save "" ;# prevent bgsave from interfereing with save below
  235. r config set hz 100
  236. r config set activedefrag no
  237. r config set active-defrag-max-scan-fields 1000
  238. r config set active-defrag-threshold-lower 5
  239. r config set active-defrag-cycle-min 65
  240. r config set active-defrag-cycle-max 75
  241. r config set active-defrag-ignore-bytes 2mb
  242. r config set maxmemory 0
  243. r config set list-max-ziplist-size 5 ;# list of 500k items will have 100k quicklist nodes
  244. # create big keys with 10k items
  245. set rd [redis_deferring_client]
  246. set expected_frag 1.7
  247. # add a mass of list nodes to two lists (allocations are interlaced)
  248. 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
  249. set elements 500000
  250. for {set j 0} {$j < $elements} {incr j} {
  251. $rd lpush biglist1 $val
  252. $rd lpush biglist2 $val
  253. }
  254. for {set j 0} {$j < $elements} {incr j} {
  255. $rd read ; # Discard replies
  256. $rd read ; # Discard replies
  257. }
  258. # create some fragmentation
  259. r del biglist2
  260. # start defrag
  261. after 120 ;# serverCron only updates the info once in 100ms
  262. set frag [s allocator_frag_ratio]
  263. if {$::verbose} {
  264. puts "frag $frag"
  265. }
  266. assert {$frag >= $expected_frag}
  267. r config set latency-monitor-threshold 5
  268. r latency reset
  269. set digest [r debug digest]
  270. catch {r config set activedefrag yes} e
  271. if {![string match {DISABLED*} $e]} {
  272. # wait for the active defrag to start working (decision once a second)
  273. wait_for_condition 50 100 {
  274. [s active_defrag_running] ne 0
  275. } else {
  276. fail "defrag not started."
  277. }
  278. # wait for the active defrag to stop working
  279. wait_for_condition 500 100 {
  280. [s active_defrag_running] eq 0
  281. } else {
  282. after 120 ;# serverCron only updates the info once in 100ms
  283. puts [r info memory]
  284. puts [r info stats]
  285. puts [r memory malloc-stats]
  286. fail "defrag didn't stop."
  287. }
  288. # test the the fragmentation is lower
  289. after 120 ;# serverCron only updates the info once in 100ms
  290. set misses [s active_defrag_misses]
  291. set hits [s active_defrag_hits]
  292. set frag [s allocator_frag_ratio]
  293. set max_latency 0
  294. foreach event [r latency latest] {
  295. lassign $event eventname time latency max
  296. if {$eventname == "active-defrag-cycle"} {
  297. set max_latency $max
  298. }
  299. }
  300. if {$::verbose} {
  301. puts "frag $frag"
  302. puts "misses: $misses"
  303. puts "hits: $hits"
  304. puts "max latency $max_latency"
  305. puts [r latency latest]
  306. puts [r latency history active-defrag-cycle]
  307. }
  308. assert {$frag < 1.1}
  309. # due to high fragmentation, 100hz, and active-defrag-cycle-max set to 75,
  310. # we expect max latency to be not much higher than 7.5ms but due to rare slowness threshold is set higher
  311. assert {$max_latency <= 30}
  312. # in extreme cases of stagnation, we see over 20m misses before the tests aborts with "defrag didn't stop",
  313. # in normal cases we only see 100k misses out of 500k elements
  314. assert {$misses < $elements}
  315. }
  316. # verify the data isn't corrupted or changed
  317. set newdigest [r debug digest]
  318. assert {$digest eq $newdigest}
  319. r save ;# saving an rdb iterates over all the data / pointers
  320. r del biglist1 ;# coverage for quicklistBookmarksClear
  321. } {1}
  322. test "Active defrag edge case" {
  323. # there was an edge case in defrag where all the slabs of a certain bin are exact the same
  324. # % utilization, with the exception of the current slab from which new allocations are made
  325. # if the current slab is lower in utilization the defragger would have ended up in stagnation,
  326. # keept running and not move any allocation.
  327. # this test is more consistent on a fresh server with no history
  328. start_server {tags {"defrag"}} {
  329. r flushdb
  330. r config resetstat
  331. r config set save "" ;# prevent bgsave from interfereing with save below
  332. r config set hz 100
  333. r config set activedefrag no
  334. r config set active-defrag-max-scan-fields 1000
  335. r config set active-defrag-threshold-lower 5
  336. r config set active-defrag-cycle-min 65
  337. r config set active-defrag-cycle-max 75
  338. r config set active-defrag-ignore-bytes 1mb
  339. r config set maxmemory 0
  340. set expected_frag 1.3
  341. r debug mallctl-str thread.tcache.flush VOID
  342. # fill the first slab containin 32 regs of 640 bytes.
  343. for {set j 0} {$j < 32} {incr j} {
  344. r setrange "_$j" 600 x
  345. r debug mallctl-str thread.tcache.flush VOID
  346. }
  347. # add a mass of keys with 600 bytes values, fill the bin of 640 bytes which has 32 regs per slab.
  348. set rd [redis_deferring_client]
  349. set keys 640000
  350. for {set j 0} {$j < $keys} {incr j} {
  351. $rd setrange $j 600 x
  352. }
  353. for {set j 0} {$j < $keys} {incr j} {
  354. $rd read ; # Discard replies
  355. }
  356. # create some fragmentation of 50%
  357. set sent 0
  358. for {set j 0} {$j < $keys} {incr j 1} {
  359. $rd del $j
  360. incr sent
  361. incr j 1
  362. }
  363. for {set j 0} {$j < $sent} {incr j} {
  364. $rd read ; # Discard replies
  365. }
  366. # create higher fragmentation in the first slab
  367. for {set j 10} {$j < 32} {incr j} {
  368. r del "_$j"
  369. }
  370. # start defrag
  371. after 120 ;# serverCron only updates the info once in 100ms
  372. set frag [s allocator_frag_ratio]
  373. if {$::verbose} {
  374. puts "frag $frag"
  375. }
  376. assert {$frag >= $expected_frag}
  377. set digest [r debug digest]
  378. catch {r config set activedefrag yes} e
  379. if {![string match {DISABLED*} $e]} {
  380. # wait for the active defrag to start working (decision once a second)
  381. wait_for_condition 50 100 {
  382. [s active_defrag_running] ne 0
  383. } else {
  384. fail "defrag not started."
  385. }
  386. # wait for the active defrag to stop working
  387. wait_for_condition 500 100 {
  388. [s active_defrag_running] eq 0
  389. } else {
  390. after 120 ;# serverCron only updates the info once in 100ms
  391. puts [r info memory]
  392. puts [r info stats]
  393. puts [r memory malloc-stats]
  394. fail "defrag didn't stop."
  395. }
  396. # test the the fragmentation is lower
  397. after 120 ;# serverCron only updates the info once in 100ms
  398. set misses [s active_defrag_misses]
  399. set hits [s active_defrag_hits]
  400. set frag [s allocator_frag_ratio]
  401. if {$::verbose} {
  402. puts "frag $frag"
  403. puts "hits: $hits"
  404. puts "misses: $misses"
  405. }
  406. assert {$frag < 1.1}
  407. assert {$misses < 10000000} ;# when defrag doesn't stop, we have some 30m misses, when it does, we have 2m misses
  408. }
  409. # verify the data isn't corrupted or changed
  410. set newdigest [r debug digest]
  411. assert {$digest eq $newdigest}
  412. r save ;# saving an rdb iterates over all the data / pointers
  413. }
  414. }
  415. }
  416. }
  417. } ;# run_solo