oppbench_test.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package main
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "os"
  9. "path/filepath"
  10. "runtime"
  11. "sync/atomic"
  12. "testing"
  13. "time"
  14. "github.com/ollama/ollama/server/internal/chunks"
  15. "golang.org/x/sync/errgroup"
  16. )
  17. func BenchmarkDownload(b *testing.B) {
  18. run := func(fileSize, chunkSize int64) {
  19. name := fmt.Sprintf("size=%d/chunksize=%d", fileSize, chunkSize)
  20. b.Run(name, func(b *testing.B) { benchmarkDownload(b, fileSize, chunkSize) })
  21. }
  22. run(100<<20, 8<<20)
  23. run(100<<20, 16<<20)
  24. run(100<<20, 32<<20)
  25. run(100<<20, 64<<20)
  26. run(100<<20, 128<<20) // 1 chunk
  27. }
  28. func run(ctx context.Context, c *http.Client, chunk chunks.Chunk) error {
  29. const blobURL = "https://ollama.com/v2/x/x/blobs/sha256-4824460d29f2058aaf6e1118a63a7a197a09bed509f0e7d4e2efb1ee273b447d"
  30. req, err := http.NewRequestWithContext(ctx, "GET", blobURL, nil)
  31. if err != nil {
  32. return err
  33. }
  34. req.Header.Set("Range", fmt.Sprintf("bytes=%s", chunk))
  35. res, err := c.Do(req)
  36. if err != nil {
  37. return err
  38. }
  39. defer res.Body.Close()
  40. _, err = io.CopyN(io.Discard, res.Body, chunk.Size()) // will io.EOF on short read
  41. return err
  42. }
  43. var sleepTime atomic.Int64
  44. func benchmarkDownload(b *testing.B, fileSize, chunkSize int64) {
  45. client := &http.Client{
  46. Transport: func() http.RoundTripper {
  47. tr := http.DefaultTransport.(*http.Transport).Clone()
  48. tr.DisableKeepAlives = true
  49. return tr
  50. }(),
  51. }
  52. defer client.CloseIdleConnections()
  53. // warm up the client
  54. run(context.Background(), client, chunks.New(0, 1<<20))
  55. b.SetBytes(fileSize)
  56. b.ReportAllocs()
  57. // Give our CDN a min to breathe between benchmarks.
  58. time.Sleep(time.Duration(sleepTime.Swap(3)))
  59. for b.Loop() {
  60. g, ctx := errgroup.WithContext(b.Context())
  61. g.SetLimit(runtime.GOMAXPROCS(0))
  62. for chunk := range chunks.Of(fileSize, chunkSize) {
  63. g.Go(func() error { return run(ctx, client, chunk) })
  64. }
  65. if err := g.Wait(); err != nil {
  66. b.Fatal(err)
  67. }
  68. }
  69. }
  70. func BenchmarkWrite(b *testing.B) {
  71. b.Run("chunksize=1MiB", func(b *testing.B) { benchmarkWrite(b, 1<<20) })
  72. }
  73. func benchmarkWrite(b *testing.B, chunkSize int) {
  74. b.ReportAllocs()
  75. dir := b.TempDir()
  76. f, err := os.Create(filepath.Join(dir, "write-single"))
  77. if err != nil {
  78. b.Fatal(err)
  79. }
  80. defer f.Close()
  81. data := make([]byte, chunkSize)
  82. b.SetBytes(int64(chunkSize))
  83. r := bytes.NewReader(data)
  84. for b.Loop() {
  85. r.Reset(data)
  86. _, err := io.Copy(f, r)
  87. if err != nil {
  88. b.Fatal(err)
  89. }
  90. }
  91. }