bufs.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. // Copyright 2014 The bufs Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package bufs implements a simple buffer cache.
  5. //
  6. // The intended use scheme is like:
  7. //
  8. // type Foo struct {
  9. // buffers bufs.Buffers
  10. // ...
  11. // }
  12. //
  13. // // Bar can call Qux, but not the other way around (in this example).
  14. // const maxFooDepth = 2
  15. //
  16. // func NewFoo() *Foo {
  17. // return &Foo{buffers: bufs.New(maxFooDepth), ...}
  18. // }
  19. //
  20. // func (f *Foo) Bar(n int) {
  21. // buf := f.buffers.Alloc(n) // needed locally for computation and/or I/O
  22. // defer f.buffers.Free()
  23. // ...
  24. // f.Qux(whatever)
  25. // }
  26. //
  27. // func (f *Foo) Qux(n int) {
  28. // buf := f.buffers.Alloc(n) // needed locally for computation and/or I/O
  29. // defer f.buffers.Free()
  30. // ...
  31. // }
  32. //
  33. // The whole idea behind 'bufs' is that when calling e.g. Foo.Bar N times, then
  34. // normally, without using 'bufs', there will be 2*N (in this example) []byte
  35. // buffers allocated. While using 'bufs', only 2 buffers (in this example)
  36. // will ever be created. For large N it can be a substantial difference.
  37. //
  38. // It's not a good idea to use Buffers to cache too big buffers. The cost of
  39. // having a cached buffer is that the buffer is naturally not eligible for
  40. // garbage collection. Of course, that holds only while the Foo instance is
  41. // reachable, in the above example.
  42. //
  43. // The buffer count limit is intentionally "hard" (read panicking), although
  44. // configurable in New(). The rationale is to prevent recursive calls, using
  45. // Alloc, to cause excessive, "static" memory consumption. Tune the limit
  46. // carefully or do not use Buffers from within [mutually] recursive functions
  47. // where the nesting depth is not realistically bounded to some rather small
  48. // number.
  49. //
  50. // Buffers cannot guarantee improvements to you program performance. There may
  51. // be a gain in case where they fit well. Firm grasp on what your code is
  52. // actually doing, when and in what order is essential to proper use of
  53. // Buffers. It's _highly_ recommended to first do profiling and memory
  54. // profiling before even thinking about using 'bufs'. The real world example,
  55. // and cause for this package, was a first correct, yet no optimizations done
  56. // version of a program; producing few MB of useful data while allocating 20+GB
  57. // of memory. Of course the garbage collector properly kicked in, yet the
  58. // memory abuse caused ~80+% of run time to be spent memory management. The
  59. // program _was_ expected to be slow in its still development phase, but the
  60. // bottleneck was guessed to be in I/O. Actually the hard disk was waiting for
  61. // the billions bytes being allocated and zeroed. Garbage collect on low
  62. // memory, rinse and repeat.
  63. //
  64. // In the provided tests, TestFoo and TestFooBufs do the same simulated work,
  65. // except the later uses Buffers while the former does not. Suggested test runs
  66. // which show the differences:
  67. //
  68. // $ go test -bench . -benchmem
  69. //
  70. // or
  71. //
  72. // $ go test -c
  73. // $ ./bufs.test -test.v -test.run Foo -test.memprofile mem.out -test.memprofilerate 1
  74. // $ go tool pprof bufs.test mem.out --alloc_space --nodefraction 0.0001 --edgefraction 0 -web
  75. // $ # Note: Foo vs FooBufs allocated memory is in hundreds of MBs vs 8 kB.
  76. //
  77. // or
  78. //
  79. // $ make demo # same as all of the above
  80. //
  81. //
  82. // NOTE: Alloc/Free calls must be properly nested in the same way as in for
  83. // example BeginTransaction/EndTransaction pairs. If your code can panic then
  84. // the pairing should be enforced by deferred calls.
  85. //
  86. // NOTE: Buffers objects do not allocate any space until requested by Alloc,
  87. // the mechanism works on demand only.
  88. //
  89. // FAQ: Why the 'bufs' package name?
  90. //
  91. // Package name 'bufs' was intentionally chosen instead of the perhaps more
  92. // conventional 'buf'. There are already too many 'buf' named things in the
  93. // code out there and that'll be a source of a lot of trouble. It's a bit
  94. // similar situation as in the case of package "strings" (not "string").
  95. package bufs
  96. import (
  97. "errors"
  98. "sort"
  99. "sync"
  100. )
  101. // Buffers type represents a buffer ([]byte) cache.
  102. //
  103. // NOTE: Do not modify Buffers directly, use only its methods. Do not create
  104. // additional values (copies) of Buffers, that'll break its functionality. Use
  105. // a pointer instead to refer to a single instance from different
  106. // places/scopes.
  107. type Buffers [][]byte
  108. // New returns a newly created instance of Buffers with a maximum capacity of n
  109. // buffers.
  110. //
  111. // NOTE: 'bufs.New(n)' is the same as 'make(bufs.Buffers, n)'.
  112. func New(n int) Buffers {
  113. return make(Buffers, n)
  114. }
  115. // Alloc will return a buffer such that len(r) == n. It will firstly try to
  116. // find an existing and unused buffer of big enough size. Only when there is no
  117. // such, then one of the buffer slots is reallocated to a bigger size.
  118. //
  119. // It's okay to use append with buffers returned by Alloc. But it can cause
  120. // allocation in that case and will again be producing load for the garbage
  121. // collector. The best use of Alloc is for I/O buffers where the needed size of
  122. // the buffer is figured out at some point of the code path in a 'final size'
  123. // sense. Another real world example are compression/decompression buffers.
  124. //
  125. // NOTE: The buffer returned by Alloc _is not_ zeroed. That's okay for e.g.
  126. // passing a buffer to io.Reader. If you need a zeroed buffer use Calloc.
  127. //
  128. // NOTE: Buffers returned from Alloc _must not_ be exposed/returned to your
  129. // clients. Those buffers are intended to be used strictly internally, within
  130. // the methods of some "object".
  131. //
  132. // NOTE: Alloc will panic if there are no buffers (buffer slots) left.
  133. func (p *Buffers) Alloc(n int) (r []byte) {
  134. b := *p
  135. if len(b) == 0 {
  136. panic(errors.New("Buffers.Alloc: out of buffers"))
  137. }
  138. biggest, best, biggestI, bestI := -1, -1, -1, -1
  139. for i, v := range b {
  140. //ln := len(v)
  141. // The above was correct, buts it's just confusing. It worked
  142. // because not the buffers, but slices of them are returned in
  143. // the 'if best >= n' code path.
  144. ln := cap(v)
  145. if ln >= biggest {
  146. biggest, biggestI = ln, i
  147. }
  148. if ln >= n && (bestI < 0 || best > ln) {
  149. best, bestI = ln, i
  150. if ln == n {
  151. break
  152. }
  153. }
  154. }
  155. last := len(b) - 1
  156. if best >= n {
  157. r = b[bestI]
  158. b[last], b[bestI] = b[bestI], b[last]
  159. *p = b[:last]
  160. return r[:n]
  161. }
  162. r = make([]byte, n, overCommit(n))
  163. b[biggestI] = r
  164. b[last], b[biggestI] = b[biggestI], b[last]
  165. *p = b[:last]
  166. return
  167. }
  168. // Calloc will acquire a buffer using Alloc and then clears it to zeros. The
  169. // zeroing goes up to n, not cap(r).
  170. func (p *Buffers) Calloc(n int) (r []byte) {
  171. r = p.Alloc(n)
  172. for i := range r {
  173. r[i] = 0
  174. }
  175. return
  176. }
  177. // Free makes the lastly allocated by Alloc buffer free (available) again for
  178. // Alloc.
  179. //
  180. // NOTE: Improper Free invocations, like in the sequence {New, Alloc, Free,
  181. // Free}, will panic.
  182. func (p *Buffers) Free() {
  183. b := *p
  184. b = b[:len(b)+1]
  185. *p = b
  186. }
  187. // Stats reports memory consumed by Buffers, without accounting for some
  188. // (smallish) additional overhead.
  189. func (p *Buffers) Stats() (bytes int) {
  190. b := *p
  191. b = b[:cap(b)]
  192. for _, v := range b {
  193. bytes += cap(v)
  194. }
  195. return
  196. }
  197. // Cache caches buffers ([]byte). A zero value of Cache is ready for use.
  198. //
  199. // NOTE: Do not modify a Cache directly, use only its methods. Do not create
  200. // additional values (copies) of a Cache, that'll break its functionality. Use
  201. // a pointer instead to refer to a single instance from different
  202. // places/scopes.
  203. type Cache [][]byte
  204. // Get returns a buffer ([]byte) of length n. If no such buffer is cached then
  205. // a biggest cached buffer is resized to have length n and returned. If there
  206. // are no cached items at all, Get returns a newly allocated buffer.
  207. //
  208. // In other words the cache policy is:
  209. //
  210. // - If the cache is empty, the buffer must be newly created and returned.
  211. // Cache remains empty.
  212. //
  213. // - If a buffer of sufficient size is found in the cache, remove it from the
  214. // cache and return it.
  215. //
  216. // - Otherwise the cache is non empty, but no cached buffer is big enough.
  217. // Enlarge the biggest cached buffer, remove it from the cache and return it.
  218. // This provide cached buffers size adjustment based on demand.
  219. //
  220. // In short, if the cache is not empty, Get guarantees to make it always one
  221. // item less. This rules prevent uncontrolled cache grow in some scenarios.
  222. // The older policy was not preventing that. Another advantage is better cached
  223. // buffers sizes "auto tuning", although not in every possible use case.
  224. //
  225. // NOTE: The buffer returned by Get _is not guaranteed_ to be zeroed. That's
  226. // okay for e.g. passing a buffer to io.Reader. If you need a zeroed buffer
  227. // use Cget.
  228. func (c *Cache) Get(n int) []byte {
  229. r, _ := c.get(n)
  230. return r
  231. }
  232. func (c *Cache) get(n int) (r []byte, isZeroed bool) {
  233. s := *c
  234. lens := len(s)
  235. if lens == 0 {
  236. r, isZeroed = make([]byte, n, overCommit(n)), true
  237. return
  238. }
  239. i := sort.Search(lens, func(x int) bool { return len(s[x]) >= n })
  240. if i == lens {
  241. i--
  242. s[i] = make([]byte, n, overCommit(n))
  243. }
  244. r = s[i][:n]
  245. copy(s[i:], s[i+1:])
  246. s[lens-1] = nil
  247. s = s[:lens-1]
  248. *c = s
  249. return r, false
  250. }
  251. // Cget will acquire a buffer using Get and then clears it to zeros. The
  252. // zeroing goes up to n, not cap(r).
  253. func (c *Cache) Cget(n int) (r []byte) {
  254. r, ok := c.get(n)
  255. if ok {
  256. return
  257. }
  258. for i := range r {
  259. r[i] = 0
  260. }
  261. return
  262. }
  263. // Put caches b for possible later reuse (via Get). No other references to b's
  264. // backing array may exist. Otherwise a big mess is sooner or later inevitable.
  265. func (c *Cache) Put(b []byte) {
  266. b = b[:cap(b)]
  267. lenb := len(b)
  268. if lenb == 0 {
  269. return
  270. }
  271. s := *c
  272. lens := len(s)
  273. i := sort.Search(lens, func(x int) bool { return len(s[x]) >= lenb })
  274. s = append(s, nil)
  275. copy(s[i+1:], s[i:])
  276. s[i] = b
  277. *c = s
  278. return
  279. }
  280. // Stats reports memory consumed by a Cache, without accounting for some
  281. // (smallish) additional overhead. 'n' is the number of cached buffers, bytes
  282. // is their combined capacity.
  283. func (c Cache) Stats() (n, bytes int) {
  284. n = len(c)
  285. for _, v := range c {
  286. bytes += cap(v)
  287. }
  288. return
  289. }
  290. // CCache is a Cache which is safe for concurrent use by multiple goroutines.
  291. type CCache struct {
  292. c Cache
  293. mu sync.Mutex
  294. }
  295. // Get returns a buffer ([]byte) of length n. If no such buffer is cached then
  296. // a biggest cached buffer is resized to have length n and returned. If there
  297. // are no cached items at all, Get returns a newly allocated buffer.
  298. //
  299. // In other words the cache policy is:
  300. //
  301. // - If the cache is empty, the buffer must be newly created and returned.
  302. // Cache remains empty.
  303. //
  304. // - If a buffer of sufficient size is found in the cache, remove it from the
  305. // cache and return it.
  306. //
  307. // - Otherwise the cache is non empty, but no cached buffer is big enough.
  308. // Enlarge the biggest cached buffer, remove it from the cache and return it.
  309. // This provide cached buffers size adjustment based on demand.
  310. //
  311. // In short, if the cache is not empty, Get guarantees to make it always one
  312. // item less. This rules prevent uncontrolled cache grow in some scenarios.
  313. // The older policy was not preventing that. Another advantage is better cached
  314. // buffers sizes "auto tuning", although not in every possible use case.
  315. //
  316. // NOTE: The buffer returned by Get _is not guaranteed_ to be zeroed. That's
  317. // okay for e.g. passing a buffer to io.Reader. If you need a zeroed buffer
  318. // use Cget.
  319. func (c *CCache) Get(n int) []byte {
  320. c.mu.Lock()
  321. r, _ := c.c.get(n)
  322. c.mu.Unlock()
  323. return r
  324. }
  325. // Cget will acquire a buffer using Get and then clears it to zeros. The
  326. // zeroing goes up to n, not cap(r).
  327. func (c *CCache) Cget(n int) (r []byte) {
  328. c.mu.Lock()
  329. r = c.c.Cget(n)
  330. c.mu.Unlock()
  331. return
  332. }
  333. // Put caches b for possible later reuse (via Get). No other references to b's
  334. // backing array may exist. Otherwise a big mess is sooner or later inevitable.
  335. func (c *CCache) Put(b []byte) {
  336. c.mu.Lock()
  337. c.c.Put(b)
  338. c.mu.Unlock()
  339. }
  340. // Stats reports memory consumed by a Cache, without accounting for some
  341. // (smallish) additional overhead. 'n' is the number of cached buffers, bytes
  342. // is their combined capacity.
  343. func (c *CCache) Stats() (n, bytes int) {
  344. c.mu.Lock()
  345. n, bytes = c.c.Stats()
  346. c.mu.Unlock()
  347. return
  348. }
  349. // GCache is a ready to use global instance of a CCache.
  350. var GCache CCache
  351. func overCommit(n int) int {
  352. switch {
  353. case n < 8:
  354. return 8
  355. case n < 1e5:
  356. return 2 * n
  357. case n < 1e6:
  358. return 3 * n / 2
  359. default:
  360. return n
  361. }
  362. }