From 3b1737f6da22251769fee475a6214fa2be9a954d Mon Sep 17 00:00:00 2001 From: Oleg Obleukhov Date: Wed, 12 Jun 2024 09:40:45 -0700 Subject: [PATCH] reduce heap allocations #12 Summary: * Make `corrToDuration` as a method of `Correction` * Migrate usages * Implement tests This should help to avoid allocations in logging, but definitely improve code readability Reviewed By: deathowl Differential Revision: D58468150 fbshipit-source-id: 76d91cbc317435729595a81e2ee0dd2193e4fb54 --- ptp/protocol/types.go | 9 +++++++++ ptp/protocol/types_test.go | 24 +++++++++++++++++++++++- ptp/simpleclient/client.go | 21 ++++++--------------- ptp/sptp/client/client.go | 17 ++++------------- 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/ptp/protocol/types.go b/ptp/protocol/types.go index 310c7e0a..723ac8b8 100644 --- a/ptp/protocol/types.go +++ b/ptp/protocol/types.go @@ -163,6 +163,15 @@ func (t Correction) Nanoseconds() float64 { return IntFloat(t).Value() } +// Duration converts PTP CorrectionField to time.Duration, ignoring +// case where correction is too big, and dropping fractions of nanoseconds +func (t Correction) Duration() time.Duration { + if !t.TooBig() { + return time.Duration(t.Nanoseconds()) + } + return 0 +} + func (t Correction) String() string { if t.TooBig() { return "Correction(Too big)" diff --git a/ptp/protocol/types_test.go b/ptp/protocol/types_test.go index 90fa6b35..2d0310a9 100644 --- a/ptp/protocol/types_test.go +++ b/ptp/protocol/types_test.go @@ -249,7 +249,7 @@ func TestTimestamp(t *testing.T) { } } -func TestCorrection(t *testing.T) { +func TestCorrectionFromDuration(t *testing.T) { tests := []struct { in time.Duration want Correction @@ -285,6 +285,28 @@ func TestCorrection(t *testing.T) { } } +func TestDurationFromCorrection(t *testing.T) { + tests := []struct { + in Correction + want time.Duration + }{ + { + in: Correction(65536000000), + want: time.Millisecond, + }, + { + in: Correction(0x7fffffffffffffff), + want: 0, + }, + } + for _, tt := range tests { + t.Run(fmt.Sprintf("Duration of %v", tt.in), func(t *testing.T) { + got := tt.in.Duration() + require.Equal(t, tt.want, got) + }) + } +} + func TestLogInterval(t *testing.T) { tests := []struct { in LogInterval diff --git a/ptp/simpleclient/client.go b/ptp/simpleclient/client.go index cbfc0a24..1b708b40 100644 --- a/ptp/simpleclient/client.go +++ b/ptp/simpleclient/client.go @@ -89,15 +89,6 @@ func (c *udpConnTS) WriteToWithTS(b []byte, addr net.Addr) (int, time.Time, erro return n, hwts, nil } -// corrToDuration converts PTP CorrectionField to time.Duration, ignoring -// case where correction is too big, and dropping fractions of nanoseconds -func corrToDuration(correction ptp.Correction) (corr time.Duration) { - if !correction.TooBig() { - corr = time.Duration(correction.Nanoseconds()) - } - return -} - // Config specifies Client run options type Config struct { // address of a server to talk to @@ -361,16 +352,16 @@ func (c *Client) handleAnnounce(b *ptp.Announce) error { // handleSync handles SYNC packet and adds send timestamp to measurements func (c *Client) handleSync(b *ptp.SyncDelayReq, ts time.Time) error { - c.logReceive(ptp.MessageSync, "seq=%d, our ReceiveTimestamp(T2)=%v, correctionField(C1)=%v", b.SequenceID, ts, corrToDuration(b.CorrectionField)) - c.m.addSync(b.SequenceID, ts, corrToDuration(b.CorrectionField)) + c.logReceive(ptp.MessageSync, "seq=%d, our ReceiveTimestamp(T2)=%v, correctionField(C1)=%v", b.SequenceID, ts, b.CorrectionField.Duration()) + c.m.addSync(b.SequenceID, ts, b.CorrectionField.Duration()) return nil } // handleDelay handles DELAY packet and adds ReceiveTimestamp to measurements func (c *Client) handleDelay(b *ptp.DelayResp) error { - c.logReceive(ptp.MessageDelayResp, "seq=%d, server ReceiveTimestamp(T4)=%v, correctionField(C3)=%v", b.SequenceID, b.ReceiveTimestamp.Time(), corrToDuration(b.CorrectionField)) + c.logReceive(ptp.MessageDelayResp, "seq=%d, server ReceiveTimestamp(T4)=%v, correctionField(C3)=%v", b.SequenceID, b.ReceiveTimestamp.Time(), b.CorrectionField.Duration()) // store data in measurements - c.m.addDelayResp(b.SequenceID, b.ReceiveTimestamp.Time(), corrToDuration(b.CorrectionField)) + c.m.addDelayResp(b.SequenceID, b.ReceiveTimestamp.Time(), b.CorrectionField.Duration()) // do whatever needs to be done with current measurements res, err := c.m.latest() @@ -384,8 +375,8 @@ func (c *Client) handleDelay(b *ptp.DelayResp) error { // handleFollowUp handles FOLLOW_UP packet and sends DELAY_REQ packet func (c *Client) handleFollowUp(b *ptp.FollowUp) error { - c.logReceive(ptp.MessageFollowUp, "seq=%d, server PreciseOriginTimestamp(T1)=%v, correctionField(C2)=%v", b.SequenceID, b.PreciseOriginTimestamp.Time(), corrToDuration(b.CorrectionField)) - c.m.addFollowUp(b.SequenceID, b.PreciseOriginTimestamp.Time(), corrToDuration(b.CorrectionField)) + c.logReceive(ptp.MessageFollowUp, "seq=%d, server PreciseOriginTimestamp(T1)=%v, correctionField(C2)=%v", b.SequenceID, b.PreciseOriginTimestamp.Time(), b.CorrectionField.Duration()) + c.m.addFollowUp(b.SequenceID, b.PreciseOriginTimestamp.Time(), b.CorrectionField.Duration()) // ask for delay seq, hwts, err := c.sendEventMsg(reqDelay(c.clockID)) if err != nil { diff --git a/ptp/sptp/client/client.go b/ptp/sptp/client/client.go index 5ab407e7..dd84169b 100644 --- a/ptp/sptp/client/client.go +++ b/ptp/sptp/client/client.go @@ -31,15 +31,6 @@ import ( ptp "github.com/facebook/time/ptp/protocol" ) -// corrToDuration converts PTP CorrectionField to time.Duration, ignoring -// case where correction is too big, and dropping fractions of nanoseconds -func corrToDuration(correction ptp.Correction) (corr time.Duration) { - if !correction.TooBig() { - corr = time.Duration(correction.Nanoseconds()) - } - return -} - // ReqDelay is a helper to build ptp.SyncDelayReq func ReqDelay(clockID ptp.ClockIdentity, portID uint16) *ptp.SyncDelayReq { return &ptp.SyncDelayReq{ @@ -194,14 +185,14 @@ func (c *Client) handleAnnounce(b *ptp.Announce) { ptp.MessageAnnounce, b.SequenceID, b.OriginTimestamp.Time(), - corrToDuration(b.CorrectionField), + b.CorrectionField.Duration(), b.GrandmasterIdentity, b.TimeSource, b.StepsRemoved) c.m.currentUTCoffset = time.Duration(b.CurrentUTCOffset) * time.Second // announce carries T1 and CF2 c.m.addT1(b.SequenceID, b.OriginTimestamp.Time()) - c.m.addCF2(b.SequenceID, corrToDuration(b.CorrectionField)) + c.m.addCF2(b.SequenceID, b.CorrectionField.Duration()) c.m.addAnnounce(*b) } @@ -213,9 +204,9 @@ func (c *Client) handleSync(b *ptp.SyncDelayReq, ts time.Time) { b.SequenceID, ts, b.OriginTimestamp.Time(), - corrToDuration(b.CorrectionField)) + b.CorrectionField.Duration()) // T2 and CF1 - c.m.addT2andCF1(b.SequenceID, ts, corrToDuration(b.CorrectionField)) + c.m.addT2andCF1(b.SequenceID, ts, b.CorrectionField.Duration()) // sync carries T4 as well c.m.addT4(b.SequenceID, b.OriginTimestamp.Time()) }