Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,31 @@ go build -o choice
./choice
```

### Testing

```bash
go test ./...
```

### Benchmarks

```bash
# 全ベンチマーク実行
go test -bench=. -benchmem ./pkg/buffer/...

# 特定のベンチマークのみ
go test -bench=BenchmarkBufferWrite -benchmem ./pkg/buffer/...

# 複数回実行して安定性を確認
go test -bench=. -benchmem -count=5 ./pkg/buffer/...

# CPUプロファイル付き
go test -bench=BenchmarkBufferWrite -benchmem -cpuprofile=cpu.prof ./pkg/buffer/...

# メモリプロファイル付き
go test -bench=BenchmarkBufferWrite -benchmem -memprofile=mem.prof ./pkg/buffer/...
```

## License

This project is licensed under the MIT License.
132 changes: 132 additions & 0 deletions pkg/buffer/bucket_benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package buffer

import (
"testing"

"github.com/pion/rtp"
)

func newTestBucket() *Bucket {
buf := make([]byte, minBufferSize)
return NewBucket(&buf)
}

func createTestRTPPacketForBucket(seqNo uint16, timestamp uint32) []byte {
pkt := &rtp.Packet{
Header: rtp.Header{
Version: 2,
Padding: false,
Extension: false,
Marker: false,
PayloadType: 96,
SequenceNumber: seqNo,
Timestamp: timestamp,
SSRC: 12345,
},
Payload: make([]byte, 100),
}
data, _ := pkt.Marshal()
return data
}

// ベンチマーク: Bucket.AddPacket (連続書き込み)
func BenchmarkBucketAddPacket(b *testing.B) {
bucket := newTestBucket()

b.ResetTimer()
for i := 0; b.Loop(); i++ {
pkt := createTestRTPPacketForBucket(uint16(i), uint32(i)*100)
_, _ = bucket.AddPacket(pkt, uint16(i), true)
}
}

// ベンチマーク: Bucket.AddPacket (並列)
func BenchmarkBucketAddPacketParallel(b *testing.B) {
bucket := newTestBucket()

b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
seqNo := uint16(0)
for pb.Next() {
pkt := createTestRTPPacketForBucket(seqNo, uint32(seqNo)*100)
_, _ = bucket.AddPacket(pkt, seqNo, true)
seqNo++
}
})
}

// ベンチマーク: Bucket.GetPacket
func BenchmarkBucketGetPacket(b *testing.B) {
bucket := newTestBucket()

// 事前にパケットを書き込む
for i := range 1000 {
pkt := createTestRTPPacketForBucket(uint16(i), uint32(i)*100)
_, _ = bucket.AddPacket(pkt, uint16(i), true)
}

buf := make([]byte, maxPktSize)

b.ResetTimer()
for i := 0; b.Loop(); i++ {
sn := uint16(i % 1000)
_, _ = bucket.GetPacket(buf, sn)
}
}

// ベンチマーク: Bucket.AddPacket (非連続シーケンス番号)
func BenchmarkBucketAddPacketWithGap(b *testing.B) {
bucket := newTestBucket()

b.ResetTimer()
for i := 0; b.Loop(); i++ {
// 2つおきにシーケンス番号を進める(パケットロスをシミュレート)
seqNo := uint16(i * 2)
pkt := createTestRTPPacketForBucket(seqNo, uint32(seqNo)*100)
_, _ = bucket.AddPacket(pkt, seqNo, true)
}
}

// ベンチマーク: Bucket.AddPacket (リオーダー)
func BenchmarkBucketAddPacketReorder(b *testing.B) {
bucket := newTestBucket()

// 事前に連続パケットを書き込む
for i := range 100 {
pkt := createTestRTPPacketForBucket(uint16(i), uint32(i)*100)
_, _ = bucket.AddPacket(pkt, uint16(i), true)
}

b.ResetTimer()
for i := 0; b.Loop(); i++ {
// 過去のシーケンス番号で再送パケットをシミュレート
seqNo := uint16(50 + (i % 30))
pkt := createTestRTPPacketForBucket(seqNo, uint32(seqNo)*100)
_, _ = bucket.AddPacket(pkt, seqNo, false)
}
}

// ベンチマーク: Bucket 作成
func BenchmarkBucketNew(b *testing.B) {
b.ResetTimer()
for b.Loop() {
buf := make([]byte, minBufferSize)
_ = NewBucket(&buf)
}
}

// ベンチマーク: AddPacket と GetPacket の組み合わせ
func BenchmarkBucketAddAndGet(b *testing.B) {
bucket := newTestBucket()
getBuf := make([]byte, maxPktSize)

b.ResetTimer()
for i := 0; b.Loop(); i++ {
seqNo := uint16(i)
pkt := createTestRTPPacketForBucket(seqNo, uint32(seqNo)*100)
_, _ = bucket.AddPacket(pkt, seqNo, true)

// 直前に追加したパケットを取得
_, _ = bucket.GetPacket(getBuf, seqNo)
}
}
12 changes: 6 additions & 6 deletions pkg/buffer/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ type Buffer struct {
twccExt uint8
audioExt uint8
bound bool
closed atomicBool
closed atomic.Bool
mime string

// パケット到着通知用
Expand Down Expand Up @@ -233,7 +233,7 @@ func (b *Buffer) Write(pkt []byte) (n int, err error) {
b.mu.Lock()
defer b.mu.Unlock()

if b.closed.get() {
if b.closed.Load() {
err = io.EOF
return
}
Expand All @@ -259,7 +259,7 @@ func (b *Buffer) Read(buff []byte) (int, error) {
defer b.mu.Unlock()

for {
if b.closed.get() {
if b.closed.Load() {
return 0, io.EOF
}

Expand All @@ -283,7 +283,7 @@ func (b *Buffer) ReadExtended() (*ExtPacket, error) {
defer b.mu.Unlock()

for {
if b.closed.get() {
if b.closed.Load() {
return nil, io.EOF
}

Expand All @@ -308,7 +308,7 @@ func (b *Buffer) Close() error {
b.audioPool.Put(&b.bucket.buf)
}

b.closed.set(true)
b.closed.Store(true)

// 待機中のgoroutineを起こす
b.extPacketNotifier.broadcast()
Expand Down Expand Up @@ -645,7 +645,7 @@ func (b *Buffer) GetPacket(buff []byte, sn uint16) (int, error) {
b.mu.Lock()
defer b.mu.Unlock()

if b.closed.get() {
if b.closed.Load() {
return 0, io.EOF
}

Expand Down
Loading