Skip to content

Commit

Permalink
Merge pull request #11 from mazrean/dev/http-benchmark
Browse files Browse the repository at this point in the history
ベンチマーク、テストの強化
  • Loading branch information
mazrean authored Mar 5, 2024
2 parents 1c81c61 + 6a335f5 commit 3216ba1
Show file tree
Hide file tree
Showing 16 changed files with 510 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/benchmark.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
mkdir -p ./profile
{
echo "stdout<<EOF"
go test -benchmem -bench . -cpuprofile ./profile/cpu.out -memprofile ./profile/mem.out
go test -short -benchmem -bench . -cpuprofile ./profile/cpu.out -memprofile ./profile/mem.out
echo "EOF"
} >> $GITHUB_OUTPUT
id: bench
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: go test ./... -v -coverprofile=./coverage.txt -race -vet=off
- run: go test ./... -short -v -coverprofile=./coverage.txt -race -vet=off
- name: Upload coverage data
uses: codecov/[email protected]
with:
Expand Down
3 changes: 0 additions & 3 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ linters:
- staticcheck
- unused
- gosimple
- structcheck
- varcheck
- ineffassign
- typecheck
- revive
Expand All @@ -32,7 +30,6 @@ linters:
- nilerr
- nosprintfhostport
- sqlclosecheck
- testpackage
- unconvert
- unparam
- whitespace
Binary file modified docs/images/memory.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/time.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion formstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type parserConfig struct {

type ParserOption func(*parserConfig)

type DataSize uint64
type DataSize int64

const (
_ DataSize = 1 << (iota * 10)
Expand Down
123 changes: 99 additions & 24 deletions formstream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"testing"

"github.com/mazrean/formstream"
"github.com/mazrean/formstream/internal/myio"
)

func ExampleNewParser() {
Expand Down Expand Up @@ -69,44 +70,69 @@ large file contents

const boundary = "boundary"

func sampleForm(fileSize formstream.DataSize, boundary string, reverse bool) (io.Reader, error) {
b := bytes.NewBuffer(nil)
func sampleForm(fileSize formstream.DataSize, boundary string, reverse bool) (io.ReadSeekCloser, error) {
if fileSize > 1*formstream.GB {
f, err := os.CreateTemp("", "formstream-test-form-")
if err != nil {
return nil, fmt.Errorf("failed to create temp file: %w", err)
}

err = createSampleForm(f, fileSize, boundary, reverse)
if err != nil {
return nil, fmt.Errorf("failed to create sample form: %w", err)
}

return f, nil
}

buf := bytes.NewBuffer(nil)

err := createSampleForm(buf, fileSize, boundary, reverse)
if err != nil {
return nil, fmt.Errorf("failed to create sample form: %w", err)
}

mw := multipart.NewWriter(b)
return myio.NopSeekCloser(bytes.NewReader(buf.Bytes())), nil
}

func createSampleForm(w io.Writer, fileSize formstream.DataSize, boundary string, reverse bool) error {
mw := multipart.NewWriter(w)
defer mw.Close()

err := mw.SetBoundary(boundary)
if err != nil {
return nil, fmt.Errorf("failed to set boundary: %w", err)
return fmt.Errorf("failed to set boundary: %w", err)
}

if !reverse {
err := mw.WriteField("field", "value")
if err != nil {
return nil, fmt.Errorf("failed to write field: %w", err)
return fmt.Errorf("failed to write field: %w", err)
}
}

mh := make(textproto.MIMEHeader)
mh.Set("Content-Disposition", `form-data; name="stream"; filename="file.txt"`)
mh.Set("Content-Type", "text/plain")
w, err := mw.CreatePart(mh)
pw, err := mw.CreatePart(mh)
if err != nil {
return nil, fmt.Errorf("failed to create part: %w", err)
return fmt.Errorf("failed to create part: %w", err)
}
_, err = io.CopyN(w, strings.NewReader(strings.Repeat("a", int(fileSize))), int64(fileSize))
if err != nil {
return nil, fmt.Errorf("failed to copy: %w", err)
for i := 0; i < int(fileSize/formstream.MB); i++ {
_, err := pw.Write([]byte(strings.Repeat("a", int(formstream.MB))))
if err != nil {
return fmt.Errorf("failed to write: %w", err)
}
}

if reverse {
err := mw.WriteField("field", "value")
if err != nil {
return nil, fmt.Errorf("failed to write field: %w", err)
return fmt.Errorf("failed to write field: %w", err)
}
}

return b, nil
return nil
}

func BenchmarkFormStreamFastPath(b *testing.B) {
Expand All @@ -122,6 +148,18 @@ func BenchmarkFormStreamFastPath(b *testing.B) {
b.Run("1GB", func(b *testing.B) {
benchmarkFormStream(b, 1*formstream.GB, false)
})
b.Run("5GB", func(b *testing.B) {
if testing.Short() {
b.Skip("skipping test in short mode.")
}
benchmarkFormStream(b, 5*formstream.GB, false)
})
b.Run("10GB", func(b *testing.B) {
if testing.Short() {
b.Skip("skipping test in short mode.")
}
benchmarkFormStream(b, 10*formstream.GB, false)
})
}

func BenchmarkFormStreamSlowPath(b *testing.B) {
Expand All @@ -137,12 +175,31 @@ func BenchmarkFormStreamSlowPath(b *testing.B) {
b.Run("1GB", func(b *testing.B) {
benchmarkFormStream(b, 1*formstream.GB, true)
})
b.Run("5GB", func(b *testing.B) {
if testing.Short() {
b.Skip("skipping test in short mode.")
}
benchmarkFormStream(b, 5*formstream.GB, true)
})
b.Run("10GB", func(b *testing.B) {
if testing.Short() {
b.Skip("skipping test in short mode.")
}
benchmarkFormStream(b, 10*formstream.GB, true)
})
}

func benchmarkFormStream(b *testing.B, fileSize formstream.DataSize, reverse bool) {
r, err := sampleForm(fileSize, boundary, reverse)
if err != nil {
b.Fatal(err)
}
defer r.Close()

b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StopTimer()
r, err := sampleForm(fileSize, boundary, reverse)
_, err := r.Seek(0, io.SeekStart)
if err != nil {
b.Fatal(err)
}
Expand All @@ -169,32 +226,50 @@ func benchmarkFormStream(b *testing.B, fileSize formstream.DataSize, reverse boo
if err != nil {
b.Fatal(err)
}

}
}

func BenchmarkStdMultipart_ReadForm(b *testing.B) {
// default value in http package
const maxMemory = 32 * formstream.MB

func BenchmarkStdMultipartReadForm(b *testing.B) {
b.Run("1MB", func(b *testing.B) {
benchmarkStdMultipart_ReadForm(b, 1*formstream.MB, maxMemory)
benchmarkStdMultipartReadForm(b, 1*formstream.MB)
})
b.Run("10MB", func(b *testing.B) {
benchmarkStdMultipart_ReadForm(b, 10*formstream.MB, maxMemory)
benchmarkStdMultipartReadForm(b, 10*formstream.MB)
})
b.Run("100MB", func(b *testing.B) {
benchmarkStdMultipart_ReadForm(b, 100*formstream.MB, maxMemory)
benchmarkStdMultipartReadForm(b, 100*formstream.MB)
})
b.Run("1GB", func(b *testing.B) {
benchmarkStdMultipart_ReadForm(b, 1*formstream.GB, maxMemory)
benchmarkStdMultipartReadForm(b, 1*formstream.GB)
})
b.Run("5GB", func(b *testing.B) {
if testing.Short() {
b.Skip("skipping test in short mode.")
}
benchmarkStdMultipartReadForm(b, 5*formstream.GB)
})
b.Run("10GB", func(b *testing.B) {
if testing.Short() {
b.Skip("skipping test in short mode.")
}
benchmarkStdMultipartReadForm(b, 10*formstream.GB)
})
}

func benchmarkStdMultipart_ReadForm(b *testing.B, fileSize formstream.DataSize, maxMemory formstream.DataSize) {
func benchmarkStdMultipartReadForm(b *testing.B, fileSize formstream.DataSize) {
// default value in http package
const maxMemory = 32 * formstream.MB

r, err := sampleForm(fileSize, boundary, false)
if err != nil {
b.Fatal(err)
}
defer r.Close()

b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StopTimer()
r, err := sampleForm(fileSize, boundary, false)
_, err := r.Seek(0, io.SeekStart)
if err != nil {
b.Fatal(err)
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ require (
github.com/gin-gonic/gin v1.9.1
github.com/labstack/echo/v4 v4.11.4
golang.org/x/mod v0.11.0 // indirect
golang.org/x/sync v0.6.0
golang.org/x/sys v0.15.0 // indirect
golang.org/x/tools v0.6.0 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
Expand Down
Loading

0 comments on commit 3216ba1

Please sign in to comment.