Skip to content

Commit

Permalink
make the sync.Pool allocation a little nicer (you need to opt in)
Browse files Browse the repository at this point in the history
  • Loading branch information
bluntelk committed Nov 11, 2023
1 parent dfc90a9 commit 25cd5da
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 23 deletions.
10 changes: 4 additions & 6 deletions lib/producer/beast.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@ const tokenBufLen = 50

func (p *Producer) beastScanner(scan *bufio.Scanner) error {
lastTimeStamp := time.Duration(0)
// make our best lib allocate out of a sync.Pool
beast.UsePoolAllocator = true
for scan.Scan() {
msg := bytes.Clone(scan.Bytes())
frame, err := beast.NewFrame(msg, false)
if nil != err {
continue
}
//frame := beast.NewFrame(msg, false)
//if nil == frame {
// continue
//}
if p.beastDelay {
currentTs := frame.BeastTicksNs()
if lastTimeStamp > 0 && lastTimeStamp < currentTs {
Expand All @@ -46,7 +44,7 @@ func ScanBeast(data []byte, atEOF bool) (int, []byte, error) {

// skip until we get our first 0x1A (message start)
i := bytes.IndexByte(data, 0x1A)
if -1 == i || len(data) < i+11 {
if i == -1 || len(data) < i+11 {
// we do not even have the smallest message, let's get some more data
return 0, nil, nil
}
Expand Down Expand Up @@ -78,7 +76,7 @@ func ScanBeast(data []byte, atEOF bool) (int, []byte, error) {
return i + 1, nil, nil
}
bufLen := len(data) - i
//println("type", data[i+1], "input len", bufLen, "msg len",msgLen)
// println("type", data[i+1], "input len", bufLen, "msg len",msgLen)
if bufLen >= tokenBufLen {
// we have enough in our buffer
// account for double escapes
Expand Down
36 changes: 27 additions & 9 deletions lib/tracker/beast/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
)

type (
// Frame represents our Beast frame and is used to decode into AVR
Frame struct {
raw []byte
mlatTimestamp []byte
Expand All @@ -20,11 +21,20 @@ type (

isRadarCape bool
hasDecoded bool
isPool bool
decodedModeS mode_s.Frame
}
)

var beastPool sync.Pool
var (
// UsePoolAllocator when set to true will allocate Frame objects out of a sync.Pool. you will need to free them
// by calling beast.Release()
UsePoolAllocator = false
beastPool sync.Pool

magicTimestampMLAT = []byte{0xFF, 0x00, 0x4D, 0x4C, 0x41, 0x54}
ErrBadBeastFrame = errors.New("bad beast frame")
)

func init() {
beastPool = sync.Pool{
Expand All @@ -45,16 +55,19 @@ func init() {
}

func Release(frame *Frame) {
beastPool.Put(frame)
if UsePoolAllocator {
beastPool.Put(frame)
}
}

//var msgLenLookup = map[byte]int{
// var msgLenLookup = map[byte]int{
// 0x31: 2,
// 0x32: 7,
// 0x33: 14,
// 0x34: 2,
//}
// }

// Icao returns the airframes ICAO code as an int
func (f *Frame) Icao() uint32 {
if nil == f {
return 0
Expand All @@ -65,6 +78,7 @@ func (f *Frame) Icao() uint32 {
return f.decodedModeS.Icao()
}

// IcaoStr returns the airframes ICAO code as a readable string
func (f *Frame) IcaoStr() string {
if nil == f {
return ""
Expand All @@ -75,6 +89,7 @@ func (f *Frame) IcaoStr() string {
return f.decodedModeS.IcaoStr()
}

// Decode is used to turn our beast msg into our mode_s.Frame representation
func (f *Frame) Decode() error {
if nil == f {
return errors.New("nil frame")
Expand All @@ -98,19 +113,22 @@ func (f *Frame) TimeStamp() time.Time {
return time.Now()
}

// Raw gives us back our raw beast message
func (f *Frame) Raw() []byte {
if nil == f {
return []byte{}
}
return f.raw
}

var magicTimestampMLAT = []byte{0xFF, 0x00, 0x4D, 0x4C, 0x41, 0x54}

var ErrBadBeastFrame = errors.New("bad beast frame")

func NewFrame(rawBytes []byte, isRadarCape bool) (*Frame, error) {
f := beastPool.Get().(*Frame)
if UsePoolAllocator {
return newFrameInto(beastPool.Get().(*Frame), rawBytes, isRadarCape)
} else {
return newFrameInto(&Frame{}, rawBytes, isRadarCape)
}
}
func newFrameInto(f *Frame, rawBytes []byte, isRadarCape bool) (*Frame, error) {
if len(rawBytes) <= 8 {
return f, ErrBadBeastFrame
}
Expand Down
37 changes: 29 additions & 8 deletions lib/tracker/beast/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,20 @@ func TestNewBeastMsgModeSShort(t *testing.T) {
)
}

if 0x32 != f.msgType {
if f.msgType != 0x32 {
t.Error("Incorrect msg type")
}

// check time stamp
if 6 != len(f.mlatTimestamp) {
if len(f.mlatTimestamp) != 6 {
t.Errorf("Incorrect timestamp len. expected 6, got %d", len(f.mlatTimestamp))
}
// check signal level - should be 0xBF
if 38 != f.signalLevel {
if f.signalLevel != 38 {
t.Errorf("Did not get the signal level correctly. expected 93: got %d", f.signalLevel)
}
// make sure we decode into a mode_s.Frame
if 7 != len(f.body) {
if len(f.body) != 7 {
t.Errorf("Incorrect body len. expected 7, got %d", len(f.body))
}
}
Expand All @@ -72,20 +72,20 @@ func TestNewBeastMsgModeSLong(t *testing.T) {
t.Error("Failed to copy the long beast message correctly")
}

if 0x33 != f.msgType {
if f.msgType != 0x33 {
t.Error("Incorrect msg type")
}

// check time stamp
if 6 != len(f.mlatTimestamp) {
if len(f.mlatTimestamp) != 6 {
t.Errorf("Incorrect timestamp len. expected 6, got %d", len(f.mlatTimestamp))
}
// check signal level - should be 0xBF
if 40 != f.signalLevel {
if f.signalLevel != 40 {
t.Errorf("Did not get the signal level correctly. expected 93: got %d", f.signalLevel)
}
// make sure we decode into a mode_s.Frame
if 14 != len(f.body) {
if len(f.body) != 14 {
t.Errorf("Incorrect body len. expected 7, got %d", len(f.body))
}
}
Expand Down Expand Up @@ -231,3 +231,24 @@ func BenchmarkNewFrameAndDecode(b *testing.B) {
})
}
}

func BenchmarkNewFrameAndDecodePool(b *testing.B) {
UsePoolAllocator = true
for _, name := range keys {
arg := messages[name]
b.Run(name, func(bb *testing.B) {
var frame *Frame
var err error
for n := 0; n < bb.N; n++ {
frame, err = NewFrame(arg, false)
if nil != err {
b.Error(err)
}
if err = frame.Decode(); nil != err {
bb.Error(err)
}
Release(frame)
}
})
}
}

0 comments on commit 25cd5da

Please sign in to comment.