cache_test.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. package llamarunner
  2. import (
  3. "testing"
  4. "time"
  5. )
  6. func TestCountCommon(t *testing.T) {
  7. tests := []struct {
  8. name string
  9. t1 []input
  10. t2 []input
  11. expected int
  12. }{
  13. {
  14. name: "Equal",
  15. t1: []input{{token: 1}, {token: 2}, {token: 3}},
  16. t2: []input{{token: 1}, {token: 2}, {token: 3}},
  17. expected: 3,
  18. },
  19. {
  20. name: "Prefix",
  21. t1: []input{{token: 1}},
  22. t2: []input{{token: 1}, {token: 2}, {token: 3}},
  23. expected: 1,
  24. },
  25. {
  26. name: "Embeddings Prefix",
  27. t1: []input{{embed: []float32{0.1, 0.2, 0.3}}},
  28. t2: []input{{embed: []float32{0.1, 0.2, 0.3}}, {embed: []float32{0.4, 0.5, 0.6}}, {embed: []float32{0.7}}},
  29. expected: 1,
  30. },
  31. {
  32. name: "Embeddings Prefix Partial",
  33. t1: []input{{embed: []float32{0.1, 0.2, 0.3}}},
  34. t2: []input{{embed: []float32{0.1, 0.2}}, {embed: []float32{0.4, 0.5, 0.6}}, {embed: []float32{0.7}}},
  35. expected: 0,
  36. },
  37. {
  38. name: "Mixed",
  39. t1: []input{{token: 1}, {embed: []float32{0.2, 0.3, 0.4}}},
  40. t2: []input{{token: 1}, {embed: []float32{0.2, 0.3, 0.4}}, {token: 5}},
  41. expected: 2,
  42. },
  43. {
  44. name: "Empty",
  45. t1: []input{},
  46. t2: []input{{token: 1}, {token: 2}, {token: 3}},
  47. expected: 0,
  48. },
  49. {
  50. name: "Both Empty",
  51. t1: []input{},
  52. t2: []input{},
  53. expected: 0,
  54. },
  55. }
  56. for _, tt := range tests {
  57. t.Run(tt.name, func(t *testing.T) {
  58. result := countCommonPrefix(tt.t1, tt.t2)
  59. if result != tt.expected {
  60. t.Errorf("countCommonPrefix(%v, %v): have %v; want %v", tt.t1, tt.t2, result, tt.expected)
  61. }
  62. })
  63. }
  64. }
  65. func TestFindCacheSlot(t *testing.T) {
  66. type expected struct {
  67. result int
  68. len int
  69. }
  70. tests := []struct {
  71. name string
  72. cache InputCache
  73. prompt []input
  74. longest expected
  75. best expected
  76. }{
  77. {
  78. name: "Empty",
  79. cache: InputCache{slots: []InputCacheSlot{
  80. {
  81. Id: 0,
  82. Inputs: []input{},
  83. InUse: false,
  84. lastUsed: time.Time{},
  85. },
  86. {
  87. Id: 1,
  88. Inputs: []input{},
  89. InUse: false,
  90. lastUsed: time.Time{},
  91. },
  92. }},
  93. prompt: []input{{token: 1}},
  94. longest: expected{result: 0, len: 0},
  95. best: expected{result: 0, len: 0},
  96. },
  97. {
  98. name: "Extend",
  99. cache: InputCache{slots: []InputCacheSlot{
  100. {
  101. Id: 0,
  102. Inputs: []input{{token: 1}},
  103. InUse: false,
  104. lastUsed: time.Now().Add(-time.Second),
  105. },
  106. {
  107. Id: 1,
  108. Inputs: []input{{token: 1}, {token: 2}},
  109. InUse: false,
  110. lastUsed: time.Now().Add(-2 * time.Second),
  111. },
  112. }},
  113. prompt: []input{{token: 1}, {token: 2}},
  114. longest: expected{result: 1, len: 2},
  115. best: expected{result: 1, len: 2},
  116. },
  117. {
  118. name: "New",
  119. cache: InputCache{slots: []InputCacheSlot{
  120. {
  121. Id: 0,
  122. Inputs: []input{{token: 1}, {token: 2}},
  123. InUse: false,
  124. lastUsed: time.Now().Add(-time.Second),
  125. },
  126. {
  127. Id: 1,
  128. Inputs: []input{},
  129. InUse: false,
  130. lastUsed: time.Time{},
  131. },
  132. }},
  133. prompt: []input{{token: 2}},
  134. longest: expected{result: 0, len: 0},
  135. best: expected{result: 1, len: 0},
  136. },
  137. {
  138. name: "Fork",
  139. cache: InputCache{
  140. slots: []InputCacheSlot{
  141. {
  142. Id: 0,
  143. Inputs: []input{{token: 1}, {token: 2}},
  144. InUse: false,
  145. lastUsed: time.Now().Add(-time.Second),
  146. },
  147. {
  148. Id: 1,
  149. Inputs: []input{},
  150. InUse: false,
  151. lastUsed: time.Time{},
  152. },
  153. },
  154. },
  155. prompt: []input{{token: 1}},
  156. longest: expected{result: 0, len: 1},
  157. best: expected{result: 1, len: 1},
  158. },
  159. {
  160. name: "Evict",
  161. cache: InputCache{slots: []InputCacheSlot{
  162. {
  163. Id: 0,
  164. Inputs: []input{{token: 1}},
  165. InUse: false,
  166. lastUsed: time.Now().Add(-time.Second),
  167. },
  168. {
  169. Id: 1,
  170. Inputs: []input{{token: 1}, {token: 2}},
  171. InUse: false,
  172. lastUsed: time.Now().Add(-2 * time.Second),
  173. },
  174. }},
  175. prompt: []input{{token: 2}, {token: 3}},
  176. longest: expected{result: 0, len: 0},
  177. best: expected{result: 1, len: 0},
  178. },
  179. {
  180. name: "In use",
  181. cache: InputCache{slots: []InputCacheSlot{
  182. {
  183. Id: 0,
  184. Inputs: []input{{token: 1}, {token: 2}},
  185. InUse: true,
  186. lastUsed: time.Now().Add(-time.Second),
  187. },
  188. {
  189. Id: 1,
  190. Inputs: []input{{token: 1}},
  191. InUse: false,
  192. lastUsed: time.Now().Add(-2 * time.Second),
  193. },
  194. }},
  195. prompt: []input{{token: 1}, {token: 2}},
  196. longest: expected{result: 1, len: 1},
  197. best: expected{result: 1, len: 2},
  198. },
  199. }
  200. for _, tt := range tests {
  201. t.Run("Longest-"+tt.name, func(t *testing.T) {
  202. result, resultLen, err := tt.cache.findLongestCacheSlot(tt.prompt)
  203. if err != nil {
  204. t.Errorf("findLongestCacheSlot: err %v", err)
  205. } else if result.Id != tt.longest.result || resultLen != tt.longest.len {
  206. t.Errorf("findLongestCacheSlot: slot have %v, want %v len have %v, want %v",
  207. result.Id, tt.longest.result, resultLen, tt.longest.len)
  208. }
  209. })
  210. }
  211. for _, tt := range tests {
  212. t.Run("Best-"+tt.name, func(t *testing.T) {
  213. result, resultLen, err := tt.cache.findBestCacheSlot(tt.prompt)
  214. if err != nil {
  215. t.Errorf("findBestCacheSlot: err %v", err)
  216. } else if result.Id != tt.best.result || resultLen != tt.best.len {
  217. t.Errorf("findBestCacheSlot: slot have %v, want %v len have %v, want %v",
  218. result.Id, tt.best.result, resultLen, tt.best.len)
  219. }
  220. })
  221. }
  222. }
  223. func TestShiftDiscard(t *testing.T) {
  224. tests := []struct {
  225. name string
  226. numCtx int
  227. numKeep int
  228. inputLen int
  229. expected int
  230. }{
  231. {
  232. name: "Shift",
  233. numCtx: 2048,
  234. numKeep: 5,
  235. inputLen: 2048,
  236. expected: 1021,
  237. },
  238. {
  239. name: "Max Keep",
  240. numCtx: 2048,
  241. numKeep: 2047,
  242. inputLen: 2048,
  243. expected: 1,
  244. },
  245. {
  246. name: "No Keep",
  247. numCtx: 2048,
  248. numKeep: 0,
  249. inputLen: 2048,
  250. expected: 1024,
  251. },
  252. {
  253. name: "Truncate",
  254. numCtx: 2048,
  255. numKeep: 5,
  256. inputLen: 5000,
  257. expected: 3973,
  258. },
  259. {
  260. name: "Truncate Keep",
  261. numCtx: 2048,
  262. numKeep: 2047,
  263. inputLen: 5000,
  264. expected: 2953,
  265. },
  266. {
  267. name: "No Op",
  268. numCtx: 2048,
  269. numKeep: 5,
  270. inputLen: 512,
  271. expected: 0,
  272. },
  273. }
  274. for _, tt := range tests {
  275. t.Run(tt.name, func(t *testing.T) {
  276. c := InputCache{numCtx: tt.numCtx}
  277. result := c.ShiftDiscard(tt.inputLen, tt.numKeep)
  278. if result != tt.expected {
  279. t.Errorf("shiftDiscard(ctx: %v, keep: %v input: %v): have %v; want %v", tt.numCtx, tt.numKeep, tt.inputLen, result, tt.expected)
  280. }
  281. })
  282. }
  283. }