cache_test.go 6.3 KB

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