go-amqp/conn.go

1148 строки
32 KiB
Go
Исходник Обычный вид История

2017-04-01 23:00:36 +03:00
package amqp
import (
"bytes"
"context"
2017-04-23 04:32:50 +03:00
"crypto/tls"
"errors"
"fmt"
2017-04-30 02:38:15 +03:00
"math"
2017-04-01 23:00:36 +03:00
"net"
"net/url"
2017-04-27 06:35:29 +03:00
"sync"
2017-04-17 06:39:31 +03:00
"time"
2021-09-16 20:32:22 +03:00
"github.com/Azure/go-amqp/internal/bitmap"
"github.com/Azure/go-amqp/internal/buffer"
"github.com/Azure/go-amqp/internal/debug"
"github.com/Azure/go-amqp/internal/encoding"
"github.com/Azure/go-amqp/internal/frames"
"github.com/Azure/go-amqp/internal/shared"
2017-04-01 23:00:36 +03:00
)
2017-05-07 04:24:06 +03:00
// Default connection options
2017-04-01 23:00:36 +03:00
const (
defaultIdleTimeout = 1 * time.Minute
defaultMaxFrameSize = 65536
defaultMaxSessions = 65536
defaultWriteTimeout = 30 * time.Second
2017-04-30 02:38:15 +03:00
)
// ConnOptions contains the optional settings for configuring an AMQP connection.
type ConnOptions struct {
// ContainerID sets the container-id to use when opening the connection.
//
// A container ID will be randomly generated if this option is not used.
ContainerID string
// HostName sets the hostname sent in the AMQP
// Open frame and TLS ServerName (if not otherwise set).
HostName string
// IdleTimeout specifies the maximum period between
// receiving frames from the peer.
//
// Specify a value less than zero to disable idle timeout.
//
// Default: 1 minute (60000000000).
IdleTimeout time.Duration
// MaxFrameSize sets the maximum frame size that
// the connection will accept.
//
// Must be 512 or greater.
//
// Default: 65536.
MaxFrameSize uint32
// MaxSessions sets the maximum number of channels.
// The value must be greater than zero.
//
// Default: 65536.
MaxSessions uint16
// Properties sets an entry in the connection properties map sent to the server.
Properties map[string]any
// SASLType contains the specified SASL authentication mechanism.
SASLType SASLType
// TLSConfig sets the tls.Config to be used during
// TLS negotiation.
//
// This option is for advanced usage, in most scenarios
// providing a URL scheme of "amqps://" is sufficient.
TLSConfig *tls.Config
// WriteTimeout controls the write deadline when writing AMQP frames to the
// underlying net.Conn and no caller provided context.Context is available or
// the context contains no deadline (e.g. context.Background()).
// The timeout is set per write.
//
// Setting to a value less than zero means no timeout is set, so writes
// defer to the underlying behavior of net.Conn with no write deadline.
//
// Default: 30s
WriteTimeout time.Duration
// test hook
dialer dialer
}
// Dial connects to an AMQP broker.
//
// If the addr includes a scheme, it must be "amqp", "amqps", or "amqp+ssl".
// If no port is provided, 5672 will be used for "amqp" and 5671 for "amqps" or "amqp+ssl".
//
// If username and password information is not empty it's used as SASL PLAIN
// credentials, equal to passing ConnSASLPlain option.
//
// opts: pass nil to accept the default values.
func Dial(ctx context.Context, addr string, opts *ConnOptions) (*Conn, error) {
c, err := dialConn(ctx, addr, opts)
if err != nil {
return nil, err
}
err = c.start(ctx)
if err != nil {
return nil, err
}
return c, nil
}
// NewConn establishes a new AMQP client connection over conn.
// NOTE: [Conn] takes ownership of the provided [net.Conn] and will close it as required.
// opts: pass nil to accept the default values.
func NewConn(ctx context.Context, conn net.Conn, opts *ConnOptions) (*Conn, error) {
c, err := newConn(conn, opts)
if err != nil {
return nil, err
}
err = c.start(ctx)
if err != nil {
return nil, err
}
return c, nil
}
// Conn is an AMQP connection.
type Conn struct {
net net.Conn // underlying connection
dialer dialer // used for testing purposes, it allows faking dialing TCP/TLS endpoints
writeTimeout time.Duration // controls write deadline in absense of a context
// TLS
2017-04-30 02:38:15 +03:00
tlsNegotiation bool // negotiate TLS
tlsComplete bool // TLS negotiation complete
tlsConfig *tls.Config // TLS config, default used if nil (ServerName set to Client.hostname)
2017-04-01 23:00:36 +03:00
2017-04-30 02:38:15 +03:00
// SASL
saslHandlers map[encoding.Symbol]stateFunc // map of supported handlers keyed by SASL mechanism, SASL not negotiated if nil
saslComplete bool // SASL negotiation complete; internal *except* for SASL auth methods
2017-04-01 23:00:36 +03:00
2017-04-30 02:38:15 +03:00
// local settings
maxFrameSize uint32 // max frame size to accept
channelMax uint16 // maximum number of channels to allow
hostname string // hostname of remote server (set explicitly or parsed from URL)
idleTimeout time.Duration // maximum period between receiving frames
properties map[encoding.Symbol]any // additional properties sent upon connection open
containerID string // set explicitly or randomly generated
2017-04-27 06:35:29 +03:00
2017-04-30 02:38:15 +03:00
// peer settings
peerIdleTimeout time.Duration // maximum period between sending frames
peerMaxFrameSize uint32 // maximum frame size peer will accept
2017-04-01 23:00:36 +03:00
2017-04-30 02:38:15 +03:00
// conn state
done chan struct{} // indicates the connection has terminated
doneErr error // contains the error state returned from Close(); DO NOT TOUCH outside of conn.go until done has been closed!
2017-04-01 23:00:36 +03:00
// connReader and connWriter management
rxtxExit chan struct{} // signals connReader and connWriter to exit
closeOnce sync.Once // ensures that close() is only called once
// session tracking
channels *bitmap.Bitmap
sessionsByChannel map[uint16]*Session
sessionsByChannelMu sync.RWMutex
abandonedSessionsMu sync.Mutex
abandonedSessions []*Session
// connReader
rxBuf buffer.Buffer // incoming bytes buffer
rxDone chan struct{} // closed when connReader exits
rxErr error // contains last error reading from c.net; DO NOT TOUCH outside of connReader until rxDone has been closed!
// connWriter
txFrame chan frameEnvelope // AMQP frames to be sent by connWriter
txBuf buffer.Buffer // buffer for marshaling frames before transmitting
txDone chan struct{} // closed when connWriter exits
txErr error // contains last error writing to c.net; DO NOT TOUCH outside of connWriter until txDone has been closed!
}
// used to abstract the underlying dialer for testing purposes
type dialer interface {
NetDialerDial(ctx context.Context, c *Conn, host, port string) error
TLSDialWithDialer(ctx context.Context, c *Conn, host, port string) error
}
// implements the dialer interface
type defaultDialer struct{}
func (defaultDialer) NetDialerDial(ctx context.Context, c *Conn, host, port string) (err error) {
dialer := &net.Dialer{}
c.net, err = dialer.DialContext(ctx, "tcp", net.JoinHostPort(host, port))
return
}
func (defaultDialer) TLSDialWithDialer(ctx context.Context, c *Conn, host, port string) (err error) {
dialer := &tls.Dialer{Config: c.tlsConfig}
c.net, err = dialer.DialContext(ctx, "tcp", net.JoinHostPort(host, port))
return
}
func dialConn(ctx context.Context, addr string, opts *ConnOptions) (*Conn, error) {
u, err := url.Parse(addr)
if err != nil {
return nil, err
}
host, port := u.Hostname(), u.Port()
if port == "" {
port = "5672"
if u.Scheme == "amqps" || u.Scheme == "amqp+ssl" {
port = "5671"
}
}
var cp ConnOptions
if opts != nil {
cp = *opts
}
// prepend SASL credentials when the user/pass segment is not empty
if u.User != nil {
pass, _ := u.User.Password()
cp.SASLType = SASLTypePlain(u.User.Username(), pass)
}
if cp.HostName == "" {
cp.HostName = host
}
c, err := newConn(nil, &cp)
if err != nil {
return nil, err
}
switch u.Scheme {
case "amqp", "":
err = c.dialer.NetDialerDial(ctx, c, host, port)
case "amqps", "amqp+ssl":
c.initTLSConfig()
c.tlsNegotiation = false
err = c.dialer.TLSDialWithDialer(ctx, c, host, port)
default:
err = fmt.Errorf("unsupported scheme %q", u.Scheme)
}
if err != nil {
return nil, err
}
return c, nil
}
func newConn(netConn net.Conn, opts *ConnOptions) (*Conn, error) {
c := &Conn{
dialer: defaultDialer{},
net: netConn,
maxFrameSize: defaultMaxFrameSize,
peerMaxFrameSize: defaultMaxFrameSize,
channelMax: defaultMaxSessions - 1, // -1 because channel-max starts at zero
idleTimeout: defaultIdleTimeout,
containerID: shared.RandString(40),
done: make(chan struct{}),
rxtxExit: make(chan struct{}),
rxDone: make(chan struct{}),
txFrame: make(chan frameEnvelope),
txDone: make(chan struct{}),
sessionsByChannel: map[uint16]*Session{},
writeTimeout: defaultWriteTimeout,
}
// apply options
if opts == nil {
opts = &ConnOptions{}
}
if opts.WriteTimeout > 0 {
c.writeTimeout = opts.WriteTimeout
} else if opts.WriteTimeout < 0 {
c.writeTimeout = 0
}
if opts.ContainerID != "" {
c.containerID = opts.ContainerID
}
if opts.HostName != "" {
c.hostname = opts.HostName
}
if opts.IdleTimeout > 0 {
c.idleTimeout = opts.IdleTimeout
} else if opts.IdleTimeout < 0 {
c.idleTimeout = 0
}
if opts.MaxFrameSize > 0 && opts.MaxFrameSize < 512 {
return nil, fmt.Errorf("invalid MaxFrameSize value %d", opts.MaxFrameSize)
} else if opts.MaxFrameSize > 512 {
c.maxFrameSize = opts.MaxFrameSize
}
if opts.MaxSessions > 0 {
c.channelMax = opts.MaxSessions
}
if opts.SASLType != nil {
if err := opts.SASLType(c); err != nil {
return nil, err
}
}
if opts.Properties != nil {
c.properties = make(map[encoding.Symbol]any)
for key, val := range opts.Properties {
c.properties[encoding.Symbol(key)] = val
}
}
if opts.TLSConfig != nil {
c.tlsConfig = opts.TLSConfig.Clone()
}
if opts.dialer != nil {
c.dialer = opts.dialer
}
return c, nil
}
func (c *Conn) initTLSConfig() {
// create a new config if not already set
if c.tlsConfig == nil {
c.tlsConfig = new(tls.Config)
}
// TLS config must have ServerName or InsecureSkipVerify set
if c.tlsConfig.ServerName == "" && !c.tlsConfig.InsecureSkipVerify {
c.tlsConfig.ServerName = c.hostname
}
}
// start establishes the connection and begins multiplexing network IO.
// It is an error to call Start() on a connection that's been closed.
func (c *Conn) start(ctx context.Context) (err error) {
// if the context has a deadline or is cancellable, start the interruptor goroutine.
// this will close the underlying net.Conn in response to the context.
if ctx.Done() != nil {
done := make(chan struct{})
interruptRes := make(chan error, 1)
defer func() {
close(done)
if ctxErr := <-interruptRes; ctxErr != nil {
// return context error to caller
err = ctxErr
}
}()
go func() {
select {
case <-ctx.Done():
c.closeDuringStart()
interruptRes <- ctx.Err()
case <-done:
interruptRes <- nil
}
}()
}
if err = c.startImpl(ctx); err != nil {
return err
}
// we can't create the channel bitmap until the connection has been established.
// this is because our peer can tell us the max channels they support.
c.channels = bitmap.New(uint32(c.channelMax))
go c.connWriter()
go c.connReader()
return
}
func (c *Conn) startImpl(ctx context.Context) error {
// set connection establishment deadline as required
if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
_ = c.net.SetDeadline(deadline)
// remove connection establishment deadline
defer func() {
_ = c.net.SetDeadline(time.Time{})
}()
}
// run connection establishment state machine
for state := c.negotiateProto; state != nil; {
var err error
state, err = state(ctx)
// check if err occurred
if err != nil {
c.closeDuringStart()
return err
}
}
return nil
2017-04-01 23:00:36 +03:00
}
// Close closes the connection.
func (c *Conn) Close() error {
c.close()
// wait until the reader/writer goroutines have exited before proceeding.
// this is to prevent a race between calling Close() and a reader/writer
// goroutine calling close() due to a terminal error.
<-c.txDone
<-c.rxDone
var connErr *ConnError
if errors.As(c.doneErr, &connErr) && connErr.RemoteErr == nil && connErr.inner == nil {
// an empty ConnectionError means the connection was closed by the caller
return nil
}
// there was an error during shut-down or connReader/connWriter
// experienced a terminal error
return c.doneErr
}
// close is called once, either from Close() or when connReader/connWriter exits
func (c *Conn) close() {
c.closeOnce.Do(func() {
defer close(c.done)
close(c.rxtxExit)
// wait for writing to stop, allows it to send the final close frame
<-c.txDone
closeErr := c.net.Close()
// check rxDone after closing net, otherwise may block
// for up to c.idleTimeout
<-c.rxDone
if errors.Is(c.rxErr, net.ErrClosed) {
// this is the expected error when the connection is closed, swallow it
c.rxErr = nil
}
2017-04-01 23:00:36 +03:00
if c.txErr == nil && c.rxErr == nil && closeErr == nil {
// if there are no errors, it means user initiated close() and we shut down cleanly
c.doneErr = &ConnError{}
} else if amqpErr, ok := c.rxErr.(*Error); ok {
// we experienced a peer-initiated close that contained an Error. return it
c.doneErr = &ConnError{RemoteErr: amqpErr}
} else if c.txErr != nil {
// c.txErr is already wrapped in a ConnError
c.doneErr = c.txErr
} else if c.rxErr != nil {
c.doneErr = &ConnError{inner: c.rxErr}
} else {
c.doneErr = &ConnError{inner: closeErr}
}
})
}
// closeDuringStart is a special close to be used only during startup (i.e. c.start() and any of its children)
func (c *Conn) closeDuringStart() {
c.closeOnce.Do(func() {
c.net.Close()
})
}
// NewSession starts a new session on the connection.
// - ctx controls waiting for the peer to acknowledge the session
// - opts contains optional values, pass nil to accept the defaults
//
// If the context's deadline expires or is cancelled before the operation
// completes, an error is returned. If the Session was successfully
// created, it will be cleaned up in future calls to NewSession.
func (c *Conn) NewSession(ctx context.Context, opts *SessionOptions) (*Session, error) {
// clean up any abandoned sessions first
if err := c.freeAbandonedSessions(ctx); err != nil {
return nil, err
}
session, err := c.newSession(opts)
if err != nil {
return nil, err
}
if err := session.begin(ctx); err != nil {
c.abandonSession(session)
return nil, err
}
return session, nil
}
func (c *Conn) freeAbandonedSessions(ctx context.Context) error {
c.abandonedSessionsMu.Lock()
defer c.abandonedSessionsMu.Unlock()
debug.Log(3, "TX (Conn %p): cleaning up %d abandoned sessions", c, len(c.abandonedSessions))
for _, s := range c.abandonedSessions {
fr := frames.PerformEnd{}
if err := s.txFrameAndWait(ctx, &fr); err != nil {
return err
}
}
c.abandonedSessions = nil
return nil
}
func (c *Conn) newSession(opts *SessionOptions) (*Session, error) {
c.sessionsByChannelMu.Lock()
defer c.sessionsByChannelMu.Unlock()
// create the next session to allocate
// note that channel always start at 0
channel, ok := c.channels.Next()
if !ok {
if err := c.Close(); err != nil {
return nil, err
}
return nil, &ConnError{inner: fmt.Errorf("reached connection channel max (%d)", c.channelMax)}
}
session := newSession(c, uint16(channel), opts)
c.sessionsByChannel[session.channel] = session
return session, nil
}
func (c *Conn) deleteSession(s *Session) {
c.sessionsByChannelMu.Lock()
defer c.sessionsByChannelMu.Unlock()
delete(c.sessionsByChannel, s.channel)
c.channels.Remove(uint32(s.channel))
}
func (c *Conn) abandonSession(s *Session) {
c.abandonedSessionsMu.Lock()
defer c.abandonedSessionsMu.Unlock()
c.abandonedSessions = append(c.abandonedSessions, s)
}
// connReader reads from the net.Conn, decodes frames, and either handles
// them here as appropriate or sends them to the session.rx channel.
func (c *Conn) connReader() {
defer func() {
close(c.rxDone)
c.close()
}()
2017-04-27 06:35:29 +03:00
var sessionsByRemoteChannel = make(map[uint16]*Session)
var err error
2017-04-01 23:00:36 +03:00
for {
if err != nil {
debug.Log(0, "RX (connReader %p): terminal error: %v", c, err)
c.rxErr = err
2017-04-24 06:24:12 +03:00
return
2017-04-01 23:00:36 +03:00
}
var fr frames.Frame
fr, err = c.readFrame()
if err != nil {
continue
}
debug.Log(0, "RX (connReader %p): %s", c, fr)
var (
session *Session
ok bool
)
switch body := fr.Body.(type) {
// Server initiated close.
case *frames.PerformClose:
// connWriter will send the close performative ack on its way out.
// it's a SHOULD though, not a MUST.
if body.Error == nil {
return
}
err = body.Error
continue
// RemoteChannel should be used when frame is Begin
case *frames.PerformBegin:
if body.RemoteChannel == nil {
// since we only support remotely-initiated sessions, this is an error
// TODO: it would be ideal to not have this kill the connection
err = fmt.Errorf("%T: nil RemoteChannel", fr.Body)
continue
}
c.sessionsByChannelMu.RLock()
session, ok = c.sessionsByChannel[*body.RemoteChannel]
c.sessionsByChannelMu.RUnlock()
if !ok {
// this can happen if NewSession() exits due to the context expiring/cancelled
// before the begin ack is received.
err = fmt.Errorf("unexpected remote channel number %d", *body.RemoteChannel)
continue
2017-04-01 23:00:36 +03:00
}
session.remoteChannel = fr.Channel
sessionsByRemoteChannel[fr.Channel] = session
case *frames.PerformEnd:
session, ok = sessionsByRemoteChannel[fr.Channel]
if !ok {
err = fmt.Errorf("%T: didn't find channel %d in sessionsByRemoteChannel (PerformEnd)", fr.Body, fr.Channel)
continue
}
// we MUST remove the remote channel from our map as soon as we receive
// the ack (i.e. before passing it on to the session mux) on the session
// ending since the numbers are recycled.
delete(sessionsByRemoteChannel, fr.Channel)
c.deleteSession(session)
default:
// pass on performative to the correct session
session, ok = sessionsByRemoteChannel[fr.Channel]
if !ok {
err = fmt.Errorf("%T: didn't find channel %d in sessionsByRemoteChannel", fr.Body, fr.Channel)
continue
}
}
2017-04-01 23:00:36 +03:00
Merge flowcontrol branch into main (#260) * Replace messages channel with a queue (#244) * Replace messages channel with a queue The Receiver.messages channel placed an arbitrary restriction on the amount of link credit that could be issued to a Receiver. Once the Receiver has been created, it can never be issued credit that exceeds the size of the channel. In addition, if the Receiver were to receive messages that exceeds the size of the channel, due to flow control bugs or other, the writes to the channel could block leading to hangs. The channel has been replaced with a segmented FIFO queue. While this in theory could allow for unbounded growth, the reality is that the total size can never be greater than that of the Session's incoming window. * use Ring from standard library * switch to require.Same for pointer comparisons fixed issue in last seg check and added another test * refine and add another test * size message queue to the incoming window * add Holder[T] to abstract syncronized access * Remove concept of "max credit" from Receivers (#251) * Remove concept of "max credit" from Receivers This exposed an implementation detail of how Receivers worked. With the removal of the Message channel, this is no longer required and never really made sense anyways. The MaxCredit and ManualCredits options have been consolidated into a single Credit option. This is used to set the total credit for a Receiver in auto-flow mode, or to disable auto-flow. Disposition batching needed some slight refactoring. Now you can directly specify the batch size instead of it being tied to link credit. Received messages that are sender-settled now correctly count towards a Receiver's credit and must be settled to reclaim it. * fix linter * back out double-buffering change for now * refine threshold logic * switch to mutex instead of channel for better perf * add back fix to remove double buffering * rename local var for clarity * revert cosmetic change * Replace incoming frame channels with queues (#253) * Replace incoming frame channels with queues The rx channel in Session and link has been replaced with a queue. This ensures that parents enqueueing frames to their children is always a non blocking operation and removes the need to "pump the mux". Consolidated some link creation code into newLink(). Links echoing a flow frame now correctly include session info. Reverted workaround for sending disposition frames from senders as we can now send directly from muxHandleFrame. * minor cleanup from review * Remove configuration of session window (#257) The values weren't actually honored which is ok per spec, so remove them from the public surface area. Cleaned up handling of sender link credit. Since we don't use availableCredit, it's been removed. * Improve handling of sender-settled messages (#258) Reclaim credit for sender-settled messages when Prefetch or Receive are called. This removes the need to explicitly settle the message.
2023-03-15 22:51:36 +03:00
q := session.rxQ.Acquire()
q.Enqueue(fr.Body)
session.rxQ.Release(q)
debug.Log(2, "RX (connReader %p): mux frame to Session (%p): %s", c, session, fr)
2017-04-01 23:00:36 +03:00
}
}
// readFrame reads a complete frame from c.net.
// it assumes that any read deadline has already been applied.
// used externally by SASL only.
func (c *Conn) readFrame() (frames.Frame, error) {
switch {
// Cheaply reuse free buffer space when fully read.
case c.rxBuf.Len() == 0:
c.rxBuf.Reset()
// Prevent excessive/unbounded growth by shifting data to beginning of buffer.
case int64(c.rxBuf.Size()) > int64(c.maxFrameSize):
c.rxBuf.Reclaim()
}
2017-04-24 06:24:12 +03:00
2017-04-30 02:38:15 +03:00
var (
currentHeader frames.Header // keep track of the current header, for frames split across multiple TCP packets
frameInProgress bool // true if in the middle of receiving data for currentHeader
2017-04-30 02:38:15 +03:00
)
2017-04-27 06:35:29 +03:00
for {
// need to read more if buf doesn't contain the complete frame
// or there's not enough in buf to parse the header
if frameInProgress || c.rxBuf.Len() < frames.HeaderSize {
// we MUST reset the idle timeout before each read from net.Conn
2018-06-01 06:34:23 +03:00
if c.idleTimeout > 0 {
_ = c.net.SetReadDeadline(time.Now().Add(c.idleTimeout))
}
err := c.rxBuf.ReadFromOnce(c.net)
2017-04-27 06:35:29 +03:00
if err != nil {
return frames.Frame{}, err
2017-04-24 06:24:12 +03:00
}
2017-04-27 06:35:29 +03:00
}
// parse the header if a frame isn't in progress
2017-04-27 06:35:29 +03:00
if !frameInProgress {
// read more if buf doesn't contain enough to parse the header
// NOTE: we MUST do this ONLY if a frame isn't in progress else we can
// end up stalling when reading frames with bodies smaller than HeaderSize
if c.rxBuf.Len() < frames.HeaderSize {
continue
}
var err error
currentHeader, err = frames.ParseHeader(&c.rxBuf)
2017-04-27 06:35:29 +03:00
if err != nil {
return frames.Frame{}, err
2017-04-27 06:35:29 +03:00
}
frameInProgress = true
}
// check size is reasonable
2017-04-30 02:38:15 +03:00
if currentHeader.Size > math.MaxInt32 { // make max size configurable
return frames.Frame{}, errors.New("payload too large")
2017-04-30 02:38:15 +03:00
}
bodySize := int64(currentHeader.Size - frames.HeaderSize)
2017-04-30 02:38:15 +03:00
// the full frame hasn't been received, keep reading
if int64(c.rxBuf.Len()) < bodySize {
2017-04-27 06:35:29 +03:00
continue
}
frameInProgress = false
// check if body is empty (keepalive)
2017-04-30 02:38:15 +03:00
if bodySize == 0 {
debug.Log(3, "RX (connReader %p): received keep-alive frame", c)
continue
2017-04-30 02:38:15 +03:00
}
// parse the frame
b, ok := c.rxBuf.Next(bodySize)
Additional encoding/decoding optimization * Replace reader/writer interfaces with concrete `buffer` type. * Avoid intermediate buffer during map encoding. * Avoid `milliseconds` marshal allocation. * Remove `errNull`/`isNull` from marshal and avoid defer in hot path. * Cleanup of decoding code. * Minimize bounds checks by adding hints. * Check interface types last in type switches. * Add fastpath in unmarshal for `**uint32`. ``` name old time/op new time/op delta FrameMarshal/transfer-8 420ns ± 4% 197ns ± 5% -53.04% (p=0.000 n=10+10) FrameUnmarshal/transfer-8 1.84µs ± 0% 0.61µs ± 5% -66.64% (p=0.000 n=8+10) Marshal/*amqp.performOpen-8 787ns ± 3% 293ns ± 5% -62.83% (p=0.000 n=10+10) Marshal/*amqp.performBegin-8 621ns ± 1% 216ns ± 3% -65.27% (p=0.000 n=10+9) Marshal/*amqp.performAttach-8 2.45µs ± 1% 1.12µs ± 3% -54.13% (p=0.000 n=10+10) Marshal/amqp.role-8 30.5ns ± 2% 20.5ns ± 2% -32.75% (p=0.000 n=10+10) Marshal/*amqp.unsettled-8 258ns ± 8% 100ns ± 3% -61.10% (p=0.000 n=10+9) Marshal/*amqp.source-8 900ns ± 1% 401ns ± 5% -55.43% (p=0.000 n=10+10) Marshal/*amqp.target-8 516ns ± 1% 244ns ± 3% -52.79% (p=0.000 n=10+10) Marshal/*amqp.performFlow-8 576ns ± 1% 193ns ± 4% -66.42% (p=0.000 n=10+10) Marshal/*amqp.performTransfer-8 404ns ± 6% 184ns ± 2% -54.35% (p=0.000 n=10+10) Marshal/*amqp.performDisposition-8 215ns ± 5% 102ns ± 4% -52.54% (p=0.000 n=10+10) Marshal/*amqp.performDetach-8 612ns ± 2% 279ns ± 0% -54.37% (p=0.000 n=10+6) Marshal/*amqp.performDetach#01-8 1.23µs ± 8% 0.42µs ± 4% -65.71% (p=0.000 n=9+10) Marshal/amqp.ErrorCondition-8 69.9ns ± 1% 27.3ns ± 4% -60.96% (p=0.000 n=10+10) Marshal/*amqp.Error-8 493ns ± 1% 221ns ± 5% -55.12% (p=0.000 n=10+10) Marshal/*amqp.performEnd-8 595ns ± 1% 264ns ± 3% -55.69% (p=0.000 n=8+10) Marshal/*amqp.performClose-8 601ns ± 2% 263ns ± 4% -56.29% (p=0.000 n=10+10) Marshal/*amqp.Message-8 1.83µs ± 0% 0.80µs ± 4% -56.33% (p=0.000 n=8+10) Marshal/*amqp.MessageHeader-8 194ns ± 2% 82ns ± 3% -57.39% (p=0.000 n=10+10) Marshal/*amqp.MessageProperties-8 546ns ± 3% 264ns ± 5% -51.56% (p=0.000 n=8+10) Marshal/*amqp.stateReceived-8 137ns ± 3% 48ns ± 2% -65.10% (p=0.000 n=9+10) Marshal/*amqp.stateAccepted-8 30.1ns ± 2% 21.4ns ± 4% -28.80% (p=0.000 n=8+10) Marshal/*amqp.stateRejected-8 608ns ± 1% 261ns ± 3% -57.04% (p=0.000 n=10+9) Marshal/*amqp.stateReleased-8 30.6ns ± 5% 22.2ns ± 3% -27.30% (p=0.000 n=8+10) Marshal/*amqp.stateModified-8 352ns ± 4% 145ns ± 6% -58.84% (p=0.000 n=10+10) Marshal/amqp.lifetimePolicy-8 29.9ns ± 3% 19.8ns ± 3% -33.73% (p=0.000 n=10+10) Marshal/amqp.SenderSettleMode-8 35.1ns ± 3% 23.7ns ± 3% -32.44% (p=0.000 n=9+9) Marshal/amqp.ReceiverSettleMode-8 36.3ns ±13% 23.6ns ± 4% -35.07% (p=0.000 n=10+10) Marshal/*amqp.saslInit-8 160ns ± 5% 90ns ± 4% -43.69% (p=0.000 n=8+10) Marshal/*amqp.saslMechanisms-8 235ns ± 1% 74ns ± 7% -68.69% (p=0.000 n=10+10) Marshal/*amqp.saslOutcome-8 169ns ± 1% 71ns ± 9% -57.88% (p=0.000 n=10+10) Marshal/amqp.milliseconds-8 60.2ns ± 2% 19.0ns ± 5% -68.40% (p=0.000 n=10+10) Marshal/amqp.symbol-8 29.0ns ± 5% 25.1ns ± 5% -13.40% (p=0.000 n=10+10) Marshal/map[amqp.symbol]interface_{}-8 242ns ± 9% 81ns ± 2% -66.57% (p=0.000 n=10+9) Marshal/amqp.UUID-8 46.4ns ± 2% 19.2ns ± 6% -58.73% (p=0.000 n=9+10) Marshal/bool-8 16.6ns ± 5% 6.2ns ± 4% -62.82% (p=0.000 n=10+10) Marshal/int8-8 19.4ns ± 1% 8.3ns ± 5% -57.28% (p=0.000 n=9+10) Marshal/int8#01-8 19.5ns ± 2% 8.4ns ± 4% -57.10% (p=0.000 n=9+10) Marshal/int16-8 24.3ns ± 6% 6.8ns ± 5% -72.13% (p=0.000 n=10+10) Marshal/int16#01-8 24.9ns ± 2% 7.0ns ± 6% -71.90% (p=0.000 n=9+10) Marshal/int32-8 33.1ns ± 2% 6.9ns ± 3% -79.13% (p=0.000 n=9+10) Marshal/int32#01-8 32.6ns ± 5% 6.9ns ± 5% -78.94% (p=0.000 n=10+10) Marshal/int64-8 45.8ns ± 4% 7.0ns ± 4% -84.66% (p=0.000 n=10+10) Marshal/int64#01-8 45.7ns ± 3% 7.1ns ± 5% -84.54% (p=0.000 n=8+10) Marshal/uint8-8 19.0ns ± 2% 8.3ns ± 5% -56.49% (p=0.000 n=9+10) Marshal/uint16-8 24.8ns ± 4% 7.4ns ± 2% -70.23% (p=0.000 n=10+9) Marshal/uint32-8 33.4ns ± 3% 7.1ns ± 5% -78.78% (p=0.000 n=8+10) Marshal/uint64-8 46.5ns ± 3% 8.5ns ± 4% -81.78% (p=0.000 n=9+10) Marshal/float32-8 33.7ns ± 7% 7.2ns ± 6% -78.73% (p=0.000 n=10+10) Marshal/float32#01-8 33.5ns ± 3% 7.1ns ± 5% -78.89% (p=0.000 n=10+10) Marshal/float32#02-8 33.4ns ± 5% 7.0ns ± 5% -78.99% (p=0.000 n=10+10) Marshal/float32#03-8 34.1ns ± 6% 7.2ns ± 4% -78.86% (p=0.000 n=10+10) Marshal/float64-8 47.3ns ± 3% 7.4ns ± 4% -84.38% (p=0.000 n=9+10) Marshal/float64#01-8 47.3ns ± 3% 7.4ns ± 6% -84.37% (p=0.000 n=8+10) Marshal/float64#02-8 46.9ns ± 5% 7.6ns ± 1% -83.87% (p=0.000 n=10+10) Marshal/float64#03-8 47.6ns ± 4% 7.3ns ± 4% -84.57% (p=0.000 n=9+10) Marshal/amqp.describedType-8 119ns ± 5% 65ns ± 5% -45.63% (p=0.000 n=10+9) Marshal/map[interface_{}]interface_{}-8 253ns ± 9% 79ns ± 4% -68.82% (p=0.000 n=9+10) Marshal/map[string]interface_{}-8 252ns ±11% 83ns ± 3% -67.08% (p=0.000 n=10+9) Marshal/amqp.ArrayUByte-8 38.5ns ± 4% 29.6ns ± 1% -23.25% (p=0.000 n=10+9) Marshal/[]int8-8 47.2ns ± 5% 24.9ns ± 5% -47.28% (p=0.000 n=10+9) Marshal/[]uint16-8 75.1ns ± 3% 24.1ns ± 5% -67.84% (p=0.000 n=10+10) Marshal/[]uint16#01-8 75.4ns ± 4% 24.4ns ± 5% -67.60% (p=0.000 n=10+10) Marshal/[]int16-8 75.0ns ± 6% 24.6ns ± 4% -67.26% (p=0.000 n=10+10) Marshal/[]int16#01-8 73.7ns ± 4% 23.9ns ± 7% -67.64% (p=0.000 n=10+10) Marshal/[]uint32-8 106ns ± 4% 24ns ± 2% -77.50% (p=0.000 n=10+9) Marshal/[]uint32#01-8 49.6ns ± 5% 26.7ns ± 6% -46.18% (p=0.000 n=10+10) Marshal/[]int32-8 105ns ± 3% 23ns ± 4% -77.70% (p=0.000 n=10+8) Marshal/[]int32#01-8 49.0ns ± 3% 27.1ns ± 5% -44.69% (p=0.000 n=9+9) Marshal/[]uint64-8 172ns ± 4% 24ns ± 3% -85.81% (p=0.000 n=10+10) Marshal/[]uint64#01-8 49.2ns ± 3% 26.7ns ± 2% -45.72% (p=0.000 n=10+8) Marshal/[]int64-8 172ns ± 2% 25ns ± 3% -85.57% (p=0.000 n=8+9) Marshal/[]int64#01-8 49.1ns ± 4% 27.2ns ± 4% -44.62% (p=0.000 n=10+10) Marshal/[]float32-8 90.6ns ± 3% 23.0ns ± 3% -74.58% (p=0.000 n=9+9) Marshal/[]float64-8 143ns ± 6% 23ns ± 9% -83.87% (p=0.000 n=10+10) Marshal/[]bool-8 44.0ns ± 4% 21.8ns ±10% -50.45% (p=0.000 n=10+10) Marshal/[]string-8 131ns ± 6% 43ns ± 3% -67.25% (p=0.000 n=10+10) Marshal/[]amqp.symbol-8 130ns ± 3% 41ns ± 2% -68.39% (p=0.000 n=10+10) Marshal/[][]uint8-8 127ns ± 4% 37ns ± 6% -71.02% (p=0.000 n=10+8) Marshal/[]time.Time-8 58.9ns ± 4% 19.5ns ± 4% -66.87% (p=0.000 n=10+10) Marshal/[]amqp.UUID-8 55.0ns ± 2% 20.2ns ± 5% -63.20% (p=0.000 n=10+10) Marshal/[]interface_{}-8 125ns ± 3% 43ns ± 5% -65.89% (p=0.000 n=8+10) Unmarshal/*amqp.performOpen-8 1.65µs ± 3% 0.91µs ±15% -44.61% (p=0.000 n=10+10) Unmarshal/*amqp.performBegin-8 1.33µs ± 4% 0.78µs ±14% -41.35% (p=0.000 n=10+10) Unmarshal/*amqp.performAttach-8 6.09µs ± 6% 3.80µs ±17% -37.52% (p=0.000 n=10+10) Unmarshal/amqp.role-8 215ns ±14% 58ns ± 8% -73.18% (p=0.000 n=10+10) Unmarshal/*amqp.unsettled-8 938ns ±20% 629ns ± 9% -33.01% (p=0.000 n=10+9) Unmarshal/*amqp.source-8 2.19µs ±11% 1.43µs ±25% -34.87% (p=0.000 n=10+10) Unmarshal/*amqp.target-8 1.29µs ± 5% 0.78µs ± 9% -39.50% (p=0.000 n=10+10) Unmarshal/*amqp.performFlow-8 1.82µs ± 1% 0.77µs ±15% -57.89% (p=0.000 n=10+10) Unmarshal/*amqp.performTransfer-8 1.71µs ± 2% 0.47µs ± 1% -72.26% (p=0.000 n=10+10) Unmarshal/*amqp.performDisposition-8 910ns ± 1% 242ns ± 1% -73.37% (p=0.000 n=10+10) Unmarshal/*amqp.performDetach-8 1.49µs ± 3% 0.85µs ± 9% -42.86% (p=0.000 n=10+9) Unmarshal/*amqp.performDetach#01-8 1.93µs ± 7% 1.22µs ±13% -36.82% (p=0.000 n=10+10) Unmarshal/amqp.ErrorCondition-8 271ns ±15% 92ns ±14% -65.93% (p=0.000 n=10+10) Unmarshal/*amqp.Error-8 1.19µs ± 9% 0.76µs ±17% -36.36% (p=0.000 n=10+10) Unmarshal/*amqp.performEnd-8 1.38µs ± 4% 0.86µs ±23% -37.86% (p=0.000 n=10+10) Unmarshal/*amqp.performClose-8 1.32µs ± 2% 0.82µs ± 8% -38.12% (p=0.000 n=8+10) Unmarshal/*amqp.Message-8 4.66µs ± 4% 2.94µs ±16% -36.87% (p=0.000 n=10+10) Unmarshal/*amqp.MessageHeader-8 647ns ± 0% 206ns ± 1% -68.18% (p=0.000 n=8+9) Unmarshal/*amqp.MessageProperties-8 1.47µs ± 1% 0.53µs ± 1% -63.75% (p=0.000 n=10+10) Unmarshal/*amqp.stateReceived-8 385ns ± 2% 126ns ± 1% -67.23% (p=0.000 n=9+10) Unmarshal/*amqp.stateAccepted-8 255ns ±17% 94ns ± 3% -63.08% (p=0.000 n=10+10) Unmarshal/*amqp.stateRejected-8 1.40µs ± 4% 0.87µs ±11% -38.12% (p=0.000 n=9+10) Unmarshal/*amqp.stateReleased-8 251ns ± 9% 94ns ± 4% -62.81% (p=0.000 n=10+10) Unmarshal/*amqp.stateModified-8 1.01µs ± 8% 0.68µs ±21% -33.07% (p=0.000 n=9+10) Unmarshal/amqp.lifetimePolicy-8 203ns ± 7% 63ns ± 7% -68.74% (p=0.000 n=10+9) Unmarshal/amqp.SenderSettleMode-8 218ns ± 9% 57ns ±21% -73.84% (p=0.000 n=9+10) Unmarshal/amqp.ReceiverSettleMode-8 221ns ±11% 57ns ± 7% -74.38% (p=0.000 n=10+9) Unmarshal/*amqp.saslInit-8 551ns ± 1% 220ns ± 1% -60.10% (p=0.000 n=10+10) Unmarshal/*amqp.saslMechanisms-8 420ns ± 2% 187ns ± 1% -55.35% (p=0.000 n=10+9) Unmarshal/*amqp.saslOutcome-8 511ns ± 2% 187ns ± 2% -63.46% (p=0.000 n=10+9) Unmarshal/amqp.milliseconds-8 189ns ±22% 60ns ±17% -68.31% (p=0.000 n=10+10) Unmarshal/amqp.symbol-8 201ns ±12% 74ns ±21% -63.44% (p=0.000 n=10+10) Unmarshal/map[amqp.symbol]interface_{}-8 897ns ±31% 614ns ±16% -31.57% (p=0.000 n=10+10) Unmarshal/amqp.UUID-8 215ns ±16% 66ns ±12% -69.16% (p=0.000 n=10+10) Unmarshal/bool-8 174ns ±34% 56ns ±10% -67.75% (p=0.000 n=10+10) Unmarshal/int8-8 201ns ±26% 54ns ±17% -72.95% (p=0.000 n=10+10) Unmarshal/int8#01-8 175ns ±23% 57ns ±21% -67.47% (p=0.000 n=10+10) Unmarshal/int16-8 189ns ±15% 56ns ±16% -70.29% (p=0.000 n=10+10) Unmarshal/int16#01-8 185ns ±22% 55ns ±17% -70.31% (p=0.000 n=10+10) Unmarshal/int32-8 198ns ±13% 53ns ±11% -73.27% (p=0.000 n=10+9) Unmarshal/int32#01-8 200ns ±14% 55ns ±13% -72.32% (p=0.000 n=10+10) Unmarshal/int64-8 206ns ±16% 56ns ±19% -72.93% (p=0.000 n=10+10) Unmarshal/int64#01-8 190ns ±14% 52ns ±12% -72.48% (p=0.000 n=10+9) Unmarshal/uint8-8 188ns ±11% 55ns ±13% -70.70% (p=0.000 n=10+10) Unmarshal/uint16-8 197ns ±12% 55ns ±11% -72.16% (p=0.000 n=10+10) Unmarshal/uint32-8 187ns ±14% 57ns ±10% -69.62% (p=0.000 n=8+9) Unmarshal/uint64-8 174ns ±23% 54ns ±27% -68.90% (p=0.000 n=10+10) Unmarshal/float32-8 198ns ±24% 55ns ±20% -72.17% (p=0.000 n=10+10) Unmarshal/float32#01-8 187ns ±15% 55ns ±12% -70.82% (p=0.000 n=10+10) Unmarshal/float32#02-8 186ns ±19% 56ns ±13% -69.76% (p=0.000 n=10+10) Unmarshal/float32#03-8 184ns ±12% 52ns ±13% -71.93% (p=0.000 n=10+10) Unmarshal/float64-8 179ns ± 7% 54ns ± 7% -69.55% (p=0.000 n=9+10) Unmarshal/float64#01-8 188ns ±17% 54ns ±16% -71.39% (p=0.000 n=10+10) Unmarshal/float64#02-8 186ns ±15% 55ns ±19% -70.35% (p=0.000 n=10+10) Unmarshal/float64#03-8 185ns ±13% 56ns ±21% -69.69% (p=0.000 n=10+10) Unmarshal/amqp.describedType-8 413ns ±12% 203ns ±11% -50.91% (p=0.000 n=10+10) Unmarshal/map[interface_{}]interface_{}-8 774ns ±22% 618ns ±17% -20.15% (p=0.000 n=10+10) Unmarshal/map[string]interface_{}-8 769ns ±35% 591ns ±17% -23.16% (p=0.015 n=10+10) Unmarshal/amqp.ArrayUByte-8 203ns ±16% 88ns ±10% -56.70% (p=0.000 n=10+10) Unmarshal/[]int8-8 205ns ±12% 58ns ±10% -71.96% (p=0.000 n=9+9) Unmarshal/[]uint16-8 194ns ±14% 63ns ±18% -67.66% (p=0.000 n=10+10) Unmarshal/[]uint16#01-8 194ns ±20% 62ns ±12% -68.16% (p=0.000 n=10+10) Unmarshal/[]int16-8 200ns ±12% 61ns ± 6% -69.48% (p=0.000 n=10+9) Unmarshal/[]int16#01-8 200ns ± 7% 64ns ±14% -68.04% (p=0.000 n=10+10) Unmarshal/[]uint32-8 193ns ±16% 61ns ±10% -68.53% (p=0.000 n=10+10) Unmarshal/[]uint32#01-8 200ns ±20% 58ns ±11% -70.86% (p=0.000 n=10+10) Unmarshal/[]int32-8 201ns ±20% 64ns ±15% -68.14% (p=0.000 n=10+10) Unmarshal/[]int32#01-8 187ns ±14% 60ns ±17% -67.67% (p=0.000 n=9+10) Unmarshal/[]uint64-8 182ns ±12% 63ns ±12% -65.47% (p=0.000 n=10+10) Unmarshal/[]uint64#01-8 207ns ± 8% 60ns ±16% -70.82% (p=0.000 n=9+10) Unmarshal/[]int64-8 202ns ±20% 64ns ±10% -68.57% (p=0.000 n=10+10) Unmarshal/[]int64#01-8 197ns ±19% 56ns ± 9% -71.50% (p=0.000 n=10+9) Unmarshal/[]float32-8 197ns ±14% 61ns ±16% -68.78% (p=0.000 n=10+9) Unmarshal/[]float64-8 202ns ±16% 64ns ± 7% -68.32% (p=0.000 n=10+9) Unmarshal/[]bool-8 195ns ±15% 61ns ± 6% -68.76% (p=0.000 n=10+9) Unmarshal/[]string-8 249ns ±10% 109ns ± 5% -56.19% (p=0.000 n=10+10) Unmarshal/[]amqp.symbol-8 253ns ± 9% 110ns ± 5% -56.60% (p=0.000 n=10+10) Unmarshal/[][]uint8-8 285ns ± 3% 139ns ± 6% -51.29% (p=0.000 n=8+10) Unmarshal/[]time.Time-8 192ns ±15% 61ns ± 6% -68.44% (p=0.000 n=10+10) Unmarshal/[]amqp.UUID-8 192ns ±12% 61ns ±12% -67.98% (p=0.000 n=10+10) Unmarshal/[]interface_{}-8 296ns ± 8% 142ns ± 4% -51.92% (p=0.000 n=9+10) name old alloc/op new alloc/op delta FrameMarshal/transfer-8 0.00B 0.00B ~ (all equal) FrameUnmarshal/transfer-8 312B ± 0% 232B ± 0% -25.64% (p=0.000 n=10+10) Marshal/*amqp.performOpen-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performBegin-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performAttach-8 576B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/amqp.role-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.unsettled-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.source-8 230B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.target-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performFlow-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performTransfer-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.performDisposition-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.performDetach-8 131B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performDetach#01-8 617B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/amqp.ErrorCondition-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.Error-8 131B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performEnd-8 131B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performClose-8 131B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.Message-8 464B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.MessageHeader-8 4.00B ± 0% 0.00B -100.00% (p=0.000 n=10+10) Marshal/*amqp.MessageProperties-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.stateReceived-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.stateAccepted-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.stateRejected-8 131B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.stateReleased-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.stateModified-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/amqp.lifetimePolicy-8 0.00B 0.00B ~ (all equal) Marshal/amqp.SenderSettleMode-8 0.00B 0.00B ~ (all equal) Marshal/amqp.ReceiverSettleMode-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.saslInit-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.saslMechanisms-8 32.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.saslOutcome-8 32.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Marshal/amqp.milliseconds-8 4.00B ± 0% 0.00B -100.00% (p=0.000 n=10+10) Marshal/amqp.symbol-8 0.00B 0.00B ~ (all equal) Marshal/map[amqp.symbol]interface_{}-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/amqp.UUID-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Marshal/bool-8 0.00B 0.00B ~ (all equal) Marshal/int8-8 0.00B 0.00B ~ (all equal) Marshal/int8#01-8 0.00B 0.00B ~ (all equal) Marshal/int16-8 0.00B 0.00B ~ (all equal) Marshal/int16#01-8 0.00B 0.00B ~ (all equal) Marshal/int32-8 0.00B 0.00B ~ (all equal) Marshal/int32#01-8 0.00B 0.00B ~ (all equal) Marshal/int64-8 0.00B 0.00B ~ (all equal) Marshal/int64#01-8 0.00B 0.00B ~ (all equal) Marshal/uint8-8 0.00B 0.00B ~ (all equal) Marshal/uint16-8 0.00B 0.00B ~ (all equal) Marshal/uint32-8 0.00B 0.00B ~ (all equal) Marshal/uint64-8 0.00B 0.00B ~ (all equal) Marshal/float32-8 0.00B 0.00B ~ (all equal) Marshal/float32#01-8 0.00B 0.00B ~ (all equal) Marshal/float32#02-8 0.00B 0.00B ~ (all equal) Marshal/float32#03-8 0.00B 0.00B ~ (all equal) Marshal/float64-8 0.00B 0.00B ~ (all equal) Marshal/float64#01-8 0.00B 0.00B ~ (all equal) Marshal/float64#02-8 0.00B 0.00B ~ (all equal) Marshal/float64#03-8 0.00B 0.00B ~ (all equal) Marshal/amqp.describedType-8 0.00B 0.00B ~ (all equal) Marshal/map[interface_{}]interface_{}-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/map[string]interface_{}-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/amqp.ArrayUByte-8 0.00B 0.00B ~ (all equal) Marshal/[]int8-8 0.00B 0.00B ~ (all equal) Marshal/[]uint16-8 0.00B 0.00B ~ (all equal) Marshal/[]uint16#01-8 0.00B 0.00B ~ (all equal) Marshal/[]int16-8 0.00B 0.00B ~ (all equal) Marshal/[]int16#01-8 0.00B 0.00B ~ (all equal) Marshal/[]uint32-8 0.00B 0.00B ~ (all equal) Marshal/[]uint32#01-8 0.00B 0.00B ~ (all equal) Marshal/[]int32-8 0.00B 0.00B ~ (all equal) Marshal/[]int32#01-8 0.00B 0.00B ~ (all equal) Marshal/[]uint64-8 0.00B 0.00B ~ (all equal) Marshal/[]uint64#01-8 0.00B 0.00B ~ (all equal) Marshal/[]int64-8 0.00B 0.00B ~ (all equal) Marshal/[]int64#01-8 0.00B 0.00B ~ (all equal) Marshal/[]float32-8 0.00B 0.00B ~ (all equal) Marshal/[]float64-8 0.00B 0.00B ~ (all equal) Marshal/[]bool-8 0.00B 0.00B ~ (all equal) Marshal/[]string-8 0.00B 0.00B ~ (all equal) Marshal/[]amqp.symbol-8 0.00B 0.00B ~ (all equal) Marshal/[][]uint8-8 0.00B 0.00B ~ (all equal) Marshal/[]time.Time-8 0.00B 0.00B ~ (all equal) Marshal/[]amqp.UUID-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Marshal/[]interface_{}-8 0.00B 0.00B ~ (all equal) Unmarshal/*amqp.performOpen-8 544B ± 0% 464B ± 0% -14.71% (p=0.000 n=10+10) Unmarshal/*amqp.performBegin-8 496B ± 0% 416B ± 0% -16.13% (p=0.000 n=10+10) Unmarshal/*amqp.performAttach-8 2.08kB ± 0% 2.00kB ± 0% -3.85% (p=0.000 n=10+10) Unmarshal/amqp.role-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/*amqp.unsettled-8 480B ± 0% 400B ± 0% -16.67% (p=0.000 n=10+10) Unmarshal/*amqp.source-8 928B ± 0% 848B ± 0% -8.62% (p=0.000 n=10+10) Unmarshal/*amqp.target-8 512B ± 0% 432B ± 0% -15.62% (p=0.000 n=10+10) Unmarshal/*amqp.performFlow-8 464B ± 0% 400B ± 0% -13.79% (p=0.000 n=10+10) Unmarshal/*amqp.performTransfer-8 168B ± 0% 96B ± 0% -42.86% (p=0.000 n=10+10) Unmarshal/*amqp.performDisposition-8 112B ± 0% 36B ± 0% -67.86% (p=0.000 n=10+10) Unmarshal/*amqp.performDetach-8 512B ± 0% 432B ± 0% -15.62% (p=0.000 n=10+10) Unmarshal/*amqp.performDetach#01-8 728B ± 0% 648B ± 0% -10.99% (p=0.000 n=10+10) Unmarshal/amqp.ErrorCondition-8 128B ± 0% 48B ± 0% -62.50% (p=0.000 n=10+10) Unmarshal/*amqp.Error-8 512B ± 0% 432B ± 0% -15.62% (p=0.000 n=10+10) Unmarshal/*amqp.performEnd-8 512B ± 0% 432B ± 0% -15.62% (p=0.000 n=10+10) Unmarshal/*amqp.performClose-8 512B ± 0% 432B ± 0% -15.62% (p=0.000 n=10+10) Unmarshal/*amqp.Message-8 1.73kB ± 0% 1.65kB ± 0% -4.63% (p=0.000 n=10+10) Unmarshal/*amqp.MessageHeader-8 128B ± 0% 48B ± 0% -62.50% (p=0.000 n=10+10) Unmarshal/*amqp.MessageProperties-8 208B ± 0% 128B ± 0% -38.46% (p=0.000 n=10+10) Unmarshal/*amqp.stateReceived-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/*amqp.stateAccepted-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/*amqp.stateRejected-8 517B ± 0% 437B ± 0% -15.47% (p=0.000 n=10+10) Unmarshal/*amqp.stateReleased-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/*amqp.stateModified-8 480B ± 0% 400B ± 0% -16.67% (p=0.000 n=10+10) Unmarshal/amqp.lifetimePolicy-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/amqp.SenderSettleMode-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/amqp.ReceiverSettleMode-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/*amqp.saslInit-8 134B ± 0% 54B ± 0% -59.70% (p=0.000 n=10+10) Unmarshal/*amqp.saslMechanisms-8 121B ± 0% 41B ± 0% -66.12% (p=0.000 n=10+10) Unmarshal/*amqp.saslOutcome-8 144B ± 0% 64B ± 0% -55.56% (p=0.000 n=10+10) Unmarshal/amqp.milliseconds-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/amqp.symbol-8 120B ± 0% 40B ± 0% -66.67% (p=0.000 n=10+10) Unmarshal/map[amqp.symbol]interface_{}-8 500B ± 0% 420B ± 0% -16.00% (p=0.000 n=10+10) Unmarshal/amqp.UUID-8 128B ± 0% 32B ± 0% -75.00% (p=0.000 n=10+10) Unmarshal/bool-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int8-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int8#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int16-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int16#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int32#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int64#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/uint8-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/uint16-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/uint32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/uint64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float32#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float32#02-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float32#03-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float64#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float64#02-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float64#03-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/amqp.describedType-8 184B ± 0% 104B ± 0% -43.48% (p=0.000 n=10+10) Unmarshal/map[interface_{}]interface_{}-8 500B ± 0% 420B ± 0% -16.00% (p=0.000 n=10+10) Unmarshal/map[string]interface_{}-8 500B ± 0% 420B ± 0% -16.00% (p=0.000 n=10+10) Unmarshal/amqp.ArrayUByte-8 112B ± 0% 40B ± 0% -64.29% (p=0.000 n=10+10) Unmarshal/[]int8-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint16-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint16#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int16-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int16#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint32#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int32#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint64#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int64#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]float32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]float64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]bool-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]string-8 121B ± 0% 41B ± 0% -66.12% (p=0.000 n=10+10) Unmarshal/[]amqp.symbol-8 121B ± 0% 41B ± 0% -66.12% (p=0.000 n=10+10) Unmarshal/[][]uint8-8 136B ± 0% 56B ± 0% -58.82% (p=0.000 n=10+10) Unmarshal/[]time.Time-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]amqp.UUID-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]interface_{}-8 136B ± 0% 56B ± 0% -58.82% (p=0.000 n=10+10) name old allocs/op new allocs/op delta FrameMarshal/transfer-8 0.00 0.00 ~ (all equal) FrameUnmarshal/transfer-8 8.00 ± 0% 8.00 ± 0% ~ (all equal) Marshal/*amqp.performOpen-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performBegin-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performAttach-8 10.0 ± 0% 0.0 -100.00% (p=0.000 n=10+10) Marshal/amqp.role-8 0.00 0.00 ~ (all equal) Marshal/*amqp.unsettled-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.source-8 4.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.target-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performFlow-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performTransfer-8 0.00 0.00 ~ (all equal) Marshal/*amqp.performDisposition-8 0.00 0.00 ~ (all equal) Marshal/*amqp.performDetach-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performDetach#01-8 4.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.ErrorCondition-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.Error-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performEnd-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performClose-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.Message-8 9.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.MessageHeader-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.MessageProperties-8 0.00 0.00 ~ (all equal) Marshal/*amqp.stateReceived-8 0.00 0.00 ~ (all equal) Marshal/*amqp.stateAccepted-8 0.00 0.00 ~ (all equal) Marshal/*amqp.stateRejected-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.stateReleased-8 0.00 0.00 ~ (all equal) Marshal/*amqp.stateModified-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.lifetimePolicy-8 0.00 0.00 ~ (all equal) Marshal/amqp.SenderSettleMode-8 0.00 0.00 ~ (all equal) Marshal/amqp.ReceiverSettleMode-8 0.00 0.00 ~ (all equal) Marshal/*amqp.saslInit-8 0.00 0.00 ~ (all equal) Marshal/*amqp.saslMechanisms-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.saslOutcome-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.milliseconds-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.symbol-8 0.00 0.00 ~ (all equal) Marshal/map[amqp.symbol]interface_{}-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.UUID-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/bool-8 0.00 0.00 ~ (all equal) Marshal/int8-8 0.00 0.00 ~ (all equal) Marshal/int8#01-8 0.00 0.00 ~ (all equal) Marshal/int16-8 0.00 0.00 ~ (all equal) Marshal/int16#01-8 0.00 0.00 ~ (all equal) Marshal/int32-8 0.00 0.00 ~ (all equal) Marshal/int32#01-8 0.00 0.00 ~ (all equal) Marshal/int64-8 0.00 0.00 ~ (all equal) Marshal/int64#01-8 0.00 0.00 ~ (all equal) Marshal/uint8-8 0.00 0.00 ~ (all equal) Marshal/uint16-8 0.00 0.00 ~ (all equal) Marshal/uint32-8 0.00 0.00 ~ (all equal) Marshal/uint64-8 0.00 0.00 ~ (all equal) Marshal/float32-8 0.00 0.00 ~ (all equal) Marshal/float32#01-8 0.00 0.00 ~ (all equal) Marshal/float32#02-8 0.00 0.00 ~ (all equal) Marshal/float32#03-8 0.00 0.00 ~ (all equal) Marshal/float64-8 0.00 0.00 ~ (all equal) Marshal/float64#01-8 0.00 0.00 ~ (all equal) Marshal/float64#02-8 0.00 0.00 ~ (all equal) Marshal/float64#03-8 0.00 0.00 ~ (all equal) Marshal/amqp.describedType-8 0.00 0.00 ~ (all equal) Marshal/map[interface_{}]interface_{}-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/map[string]interface_{}-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.ArrayUByte-8 0.00 0.00 ~ (all equal) Marshal/[]int8-8 0.00 0.00 ~ (all equal) Marshal/[]uint16-8 0.00 0.00 ~ (all equal) Marshal/[]uint16#01-8 0.00 0.00 ~ (all equal) Marshal/[]int16-8 0.00 0.00 ~ (all equal) Marshal/[]int16#01-8 0.00 0.00 ~ (all equal) Marshal/[]uint32-8 0.00 0.00 ~ (all equal) Marshal/[]uint32#01-8 0.00 0.00 ~ (all equal) Marshal/[]int32-8 0.00 0.00 ~ (all equal) Marshal/[]int32#01-8 0.00 0.00 ~ (all equal) Marshal/[]uint64-8 0.00 0.00 ~ (all equal) Marshal/[]uint64#01-8 0.00 0.00 ~ (all equal) Marshal/[]int64-8 0.00 0.00 ~ (all equal) Marshal/[]int64#01-8 0.00 0.00 ~ (all equal) Marshal/[]float32-8 0.00 0.00 ~ (all equal) Marshal/[]float64-8 0.00 0.00 ~ (all equal) Marshal/[]bool-8 0.00 0.00 ~ (all equal) Marshal/[]string-8 0.00 0.00 ~ (all equal) Marshal/[]amqp.symbol-8 0.00 0.00 ~ (all equal) Marshal/[][]uint8-8 0.00 0.00 ~ (all equal) Marshal/[]time.Time-8 0.00 0.00 ~ (all equal) Marshal/[]amqp.UUID-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/[]interface_{}-8 0.00 0.00 ~ (all equal) Unmarshal/*amqp.performOpen-8 13.0 ± 0% 13.0 ± 0% ~ (all equal) Unmarshal/*amqp.performBegin-8 8.00 ± 0% 8.00 ± 0% ~ (all equal) Unmarshal/*amqp.performAttach-8 33.0 ± 0% 33.0 ± 0% ~ (all equal) Unmarshal/amqp.role-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/*amqp.unsettled-8 5.00 ± 0% 5.00 ± 0% ~ (all equal) Unmarshal/*amqp.source-8 15.0 ± 0% 15.0 ± 0% ~ (all equal) Unmarshal/*amqp.target-8 8.00 ± 0% 8.00 ± 0% ~ (all equal) Unmarshal/*amqp.performFlow-8 5.00 ± 0% 10.00 ± 0% +100.00% (p=0.000 n=10+10) Unmarshal/*amqp.performTransfer-8 4.00 ± 0% 6.00 ± 0% +50.00% (p=0.000 n=10+10) Unmarshal/*amqp.performDisposition-8 1.00 ± 0% 2.00 ± 0% +100.00% (p=0.000 n=10+10) Unmarshal/*amqp.performDetach-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) Unmarshal/*amqp.performDetach#01-8 15.0 ± 0% 15.0 ± 0% ~ (all equal) Unmarshal/amqp.ErrorCondition-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) Unmarshal/*amqp.Error-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) Unmarshal/*amqp.performEnd-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) Unmarshal/*amqp.performClose-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) Unmarshal/*amqp.Message-8 33.0 ± 0% 33.0 ± 0% ~ (all equal) Unmarshal/*amqp.MessageHeader-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) Unmarshal/*amqp.MessageProperties-8 12.0 ± 0% 12.0 ± 0% ~ (all equal) Unmarshal/*amqp.stateReceived-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/*amqp.stateAccepted-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/*amqp.stateRejected-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) Unmarshal/*amqp.stateReleased-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/*amqp.stateModified-8 6.00 ± 0% 6.00 ± 0% ~ (all equal) Unmarshal/amqp.lifetimePolicy-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/amqp.SenderSettleMode-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/amqp.ReceiverSettleMode-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/*amqp.saslInit-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/*amqp.saslMechanisms-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/*amqp.saslOutcome-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) Unmarshal/amqp.milliseconds-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/amqp.symbol-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) Unmarshal/map[amqp.symbol]interface_{}-8 6.00 ± 0% 6.00 ± 0% ~ (all equal) Unmarshal/amqp.UUID-8 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10) Unmarshal/bool-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int8-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int8#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int16-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int16#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int32#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int64#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/uint8-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/uint16-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/uint32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/uint64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float32#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float32#02-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float32#03-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float64#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float64#02-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float64#03-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/amqp.describedType-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/map[interface_{}]interface_{}-8 6.00 ± 0% 6.00 ± 0% ~ (all equal) Unmarshal/map[string]interface_{}-8 6.00 ± 0% 6.00 ± 0% ~ (all equal) Unmarshal/amqp.ArrayUByte-8 1.00 ± 0% 2.00 ± 0% +100.00% (p=0.000 n=10+10) Unmarshal/[]int8-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint16-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint16#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int16-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int16#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint32#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int32#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint64#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int64#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]float32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]float64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]bool-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]string-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/[]amqp.symbol-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/[][]uint8-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/[]time.Time-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]amqp.UUID-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]interface_{}-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) ```
2018-02-03 22:54:49 +03:00
if !ok {
return frames.Frame{}, fmt.Errorf("buffer EOF; requested bytes: %d, actual size: %d", bodySize, c.rxBuf.Len())
Additional encoding/decoding optimization * Replace reader/writer interfaces with concrete `buffer` type. * Avoid intermediate buffer during map encoding. * Avoid `milliseconds` marshal allocation. * Remove `errNull`/`isNull` from marshal and avoid defer in hot path. * Cleanup of decoding code. * Minimize bounds checks by adding hints. * Check interface types last in type switches. * Add fastpath in unmarshal for `**uint32`. ``` name old time/op new time/op delta FrameMarshal/transfer-8 420ns ± 4% 197ns ± 5% -53.04% (p=0.000 n=10+10) FrameUnmarshal/transfer-8 1.84µs ± 0% 0.61µs ± 5% -66.64% (p=0.000 n=8+10) Marshal/*amqp.performOpen-8 787ns ± 3% 293ns ± 5% -62.83% (p=0.000 n=10+10) Marshal/*amqp.performBegin-8 621ns ± 1% 216ns ± 3% -65.27% (p=0.000 n=10+9) Marshal/*amqp.performAttach-8 2.45µs ± 1% 1.12µs ± 3% -54.13% (p=0.000 n=10+10) Marshal/amqp.role-8 30.5ns ± 2% 20.5ns ± 2% -32.75% (p=0.000 n=10+10) Marshal/*amqp.unsettled-8 258ns ± 8% 100ns ± 3% -61.10% (p=0.000 n=10+9) Marshal/*amqp.source-8 900ns ± 1% 401ns ± 5% -55.43% (p=0.000 n=10+10) Marshal/*amqp.target-8 516ns ± 1% 244ns ± 3% -52.79% (p=0.000 n=10+10) Marshal/*amqp.performFlow-8 576ns ± 1% 193ns ± 4% -66.42% (p=0.000 n=10+10) Marshal/*amqp.performTransfer-8 404ns ± 6% 184ns ± 2% -54.35% (p=0.000 n=10+10) Marshal/*amqp.performDisposition-8 215ns ± 5% 102ns ± 4% -52.54% (p=0.000 n=10+10) Marshal/*amqp.performDetach-8 612ns ± 2% 279ns ± 0% -54.37% (p=0.000 n=10+6) Marshal/*amqp.performDetach#01-8 1.23µs ± 8% 0.42µs ± 4% -65.71% (p=0.000 n=9+10) Marshal/amqp.ErrorCondition-8 69.9ns ± 1% 27.3ns ± 4% -60.96% (p=0.000 n=10+10) Marshal/*amqp.Error-8 493ns ± 1% 221ns ± 5% -55.12% (p=0.000 n=10+10) Marshal/*amqp.performEnd-8 595ns ± 1% 264ns ± 3% -55.69% (p=0.000 n=8+10) Marshal/*amqp.performClose-8 601ns ± 2% 263ns ± 4% -56.29% (p=0.000 n=10+10) Marshal/*amqp.Message-8 1.83µs ± 0% 0.80µs ± 4% -56.33% (p=0.000 n=8+10) Marshal/*amqp.MessageHeader-8 194ns ± 2% 82ns ± 3% -57.39% (p=0.000 n=10+10) Marshal/*amqp.MessageProperties-8 546ns ± 3% 264ns ± 5% -51.56% (p=0.000 n=8+10) Marshal/*amqp.stateReceived-8 137ns ± 3% 48ns ± 2% -65.10% (p=0.000 n=9+10) Marshal/*amqp.stateAccepted-8 30.1ns ± 2% 21.4ns ± 4% -28.80% (p=0.000 n=8+10) Marshal/*amqp.stateRejected-8 608ns ± 1% 261ns ± 3% -57.04% (p=0.000 n=10+9) Marshal/*amqp.stateReleased-8 30.6ns ± 5% 22.2ns ± 3% -27.30% (p=0.000 n=8+10) Marshal/*amqp.stateModified-8 352ns ± 4% 145ns ± 6% -58.84% (p=0.000 n=10+10) Marshal/amqp.lifetimePolicy-8 29.9ns ± 3% 19.8ns ± 3% -33.73% (p=0.000 n=10+10) Marshal/amqp.SenderSettleMode-8 35.1ns ± 3% 23.7ns ± 3% -32.44% (p=0.000 n=9+9) Marshal/amqp.ReceiverSettleMode-8 36.3ns ±13% 23.6ns ± 4% -35.07% (p=0.000 n=10+10) Marshal/*amqp.saslInit-8 160ns ± 5% 90ns ± 4% -43.69% (p=0.000 n=8+10) Marshal/*amqp.saslMechanisms-8 235ns ± 1% 74ns ± 7% -68.69% (p=0.000 n=10+10) Marshal/*amqp.saslOutcome-8 169ns ± 1% 71ns ± 9% -57.88% (p=0.000 n=10+10) Marshal/amqp.milliseconds-8 60.2ns ± 2% 19.0ns ± 5% -68.40% (p=0.000 n=10+10) Marshal/amqp.symbol-8 29.0ns ± 5% 25.1ns ± 5% -13.40% (p=0.000 n=10+10) Marshal/map[amqp.symbol]interface_{}-8 242ns ± 9% 81ns ± 2% -66.57% (p=0.000 n=10+9) Marshal/amqp.UUID-8 46.4ns ± 2% 19.2ns ± 6% -58.73% (p=0.000 n=9+10) Marshal/bool-8 16.6ns ± 5% 6.2ns ± 4% -62.82% (p=0.000 n=10+10) Marshal/int8-8 19.4ns ± 1% 8.3ns ± 5% -57.28% (p=0.000 n=9+10) Marshal/int8#01-8 19.5ns ± 2% 8.4ns ± 4% -57.10% (p=0.000 n=9+10) Marshal/int16-8 24.3ns ± 6% 6.8ns ± 5% -72.13% (p=0.000 n=10+10) Marshal/int16#01-8 24.9ns ± 2% 7.0ns ± 6% -71.90% (p=0.000 n=9+10) Marshal/int32-8 33.1ns ± 2% 6.9ns ± 3% -79.13% (p=0.000 n=9+10) Marshal/int32#01-8 32.6ns ± 5% 6.9ns ± 5% -78.94% (p=0.000 n=10+10) Marshal/int64-8 45.8ns ± 4% 7.0ns ± 4% -84.66% (p=0.000 n=10+10) Marshal/int64#01-8 45.7ns ± 3% 7.1ns ± 5% -84.54% (p=0.000 n=8+10) Marshal/uint8-8 19.0ns ± 2% 8.3ns ± 5% -56.49% (p=0.000 n=9+10) Marshal/uint16-8 24.8ns ± 4% 7.4ns ± 2% -70.23% (p=0.000 n=10+9) Marshal/uint32-8 33.4ns ± 3% 7.1ns ± 5% -78.78% (p=0.000 n=8+10) Marshal/uint64-8 46.5ns ± 3% 8.5ns ± 4% -81.78% (p=0.000 n=9+10) Marshal/float32-8 33.7ns ± 7% 7.2ns ± 6% -78.73% (p=0.000 n=10+10) Marshal/float32#01-8 33.5ns ± 3% 7.1ns ± 5% -78.89% (p=0.000 n=10+10) Marshal/float32#02-8 33.4ns ± 5% 7.0ns ± 5% -78.99% (p=0.000 n=10+10) Marshal/float32#03-8 34.1ns ± 6% 7.2ns ± 4% -78.86% (p=0.000 n=10+10) Marshal/float64-8 47.3ns ± 3% 7.4ns ± 4% -84.38% (p=0.000 n=9+10) Marshal/float64#01-8 47.3ns ± 3% 7.4ns ± 6% -84.37% (p=0.000 n=8+10) Marshal/float64#02-8 46.9ns ± 5% 7.6ns ± 1% -83.87% (p=0.000 n=10+10) Marshal/float64#03-8 47.6ns ± 4% 7.3ns ± 4% -84.57% (p=0.000 n=9+10) Marshal/amqp.describedType-8 119ns ± 5% 65ns ± 5% -45.63% (p=0.000 n=10+9) Marshal/map[interface_{}]interface_{}-8 253ns ± 9% 79ns ± 4% -68.82% (p=0.000 n=9+10) Marshal/map[string]interface_{}-8 252ns ±11% 83ns ± 3% -67.08% (p=0.000 n=10+9) Marshal/amqp.ArrayUByte-8 38.5ns ± 4% 29.6ns ± 1% -23.25% (p=0.000 n=10+9) Marshal/[]int8-8 47.2ns ± 5% 24.9ns ± 5% -47.28% (p=0.000 n=10+9) Marshal/[]uint16-8 75.1ns ± 3% 24.1ns ± 5% -67.84% (p=0.000 n=10+10) Marshal/[]uint16#01-8 75.4ns ± 4% 24.4ns ± 5% -67.60% (p=0.000 n=10+10) Marshal/[]int16-8 75.0ns ± 6% 24.6ns ± 4% -67.26% (p=0.000 n=10+10) Marshal/[]int16#01-8 73.7ns ± 4% 23.9ns ± 7% -67.64% (p=0.000 n=10+10) Marshal/[]uint32-8 106ns ± 4% 24ns ± 2% -77.50% (p=0.000 n=10+9) Marshal/[]uint32#01-8 49.6ns ± 5% 26.7ns ± 6% -46.18% (p=0.000 n=10+10) Marshal/[]int32-8 105ns ± 3% 23ns ± 4% -77.70% (p=0.000 n=10+8) Marshal/[]int32#01-8 49.0ns ± 3% 27.1ns ± 5% -44.69% (p=0.000 n=9+9) Marshal/[]uint64-8 172ns ± 4% 24ns ± 3% -85.81% (p=0.000 n=10+10) Marshal/[]uint64#01-8 49.2ns ± 3% 26.7ns ± 2% -45.72% (p=0.000 n=10+8) Marshal/[]int64-8 172ns ± 2% 25ns ± 3% -85.57% (p=0.000 n=8+9) Marshal/[]int64#01-8 49.1ns ± 4% 27.2ns ± 4% -44.62% (p=0.000 n=10+10) Marshal/[]float32-8 90.6ns ± 3% 23.0ns ± 3% -74.58% (p=0.000 n=9+9) Marshal/[]float64-8 143ns ± 6% 23ns ± 9% -83.87% (p=0.000 n=10+10) Marshal/[]bool-8 44.0ns ± 4% 21.8ns ±10% -50.45% (p=0.000 n=10+10) Marshal/[]string-8 131ns ± 6% 43ns ± 3% -67.25% (p=0.000 n=10+10) Marshal/[]amqp.symbol-8 130ns ± 3% 41ns ± 2% -68.39% (p=0.000 n=10+10) Marshal/[][]uint8-8 127ns ± 4% 37ns ± 6% -71.02% (p=0.000 n=10+8) Marshal/[]time.Time-8 58.9ns ± 4% 19.5ns ± 4% -66.87% (p=0.000 n=10+10) Marshal/[]amqp.UUID-8 55.0ns ± 2% 20.2ns ± 5% -63.20% (p=0.000 n=10+10) Marshal/[]interface_{}-8 125ns ± 3% 43ns ± 5% -65.89% (p=0.000 n=8+10) Unmarshal/*amqp.performOpen-8 1.65µs ± 3% 0.91µs ±15% -44.61% (p=0.000 n=10+10) Unmarshal/*amqp.performBegin-8 1.33µs ± 4% 0.78µs ±14% -41.35% (p=0.000 n=10+10) Unmarshal/*amqp.performAttach-8 6.09µs ± 6% 3.80µs ±17% -37.52% (p=0.000 n=10+10) Unmarshal/amqp.role-8 215ns ±14% 58ns ± 8% -73.18% (p=0.000 n=10+10) Unmarshal/*amqp.unsettled-8 938ns ±20% 629ns ± 9% -33.01% (p=0.000 n=10+9) Unmarshal/*amqp.source-8 2.19µs ±11% 1.43µs ±25% -34.87% (p=0.000 n=10+10) Unmarshal/*amqp.target-8 1.29µs ± 5% 0.78µs ± 9% -39.50% (p=0.000 n=10+10) Unmarshal/*amqp.performFlow-8 1.82µs ± 1% 0.77µs ±15% -57.89% (p=0.000 n=10+10) Unmarshal/*amqp.performTransfer-8 1.71µs ± 2% 0.47µs ± 1% -72.26% (p=0.000 n=10+10) Unmarshal/*amqp.performDisposition-8 910ns ± 1% 242ns ± 1% -73.37% (p=0.000 n=10+10) Unmarshal/*amqp.performDetach-8 1.49µs ± 3% 0.85µs ± 9% -42.86% (p=0.000 n=10+9) Unmarshal/*amqp.performDetach#01-8 1.93µs ± 7% 1.22µs ±13% -36.82% (p=0.000 n=10+10) Unmarshal/amqp.ErrorCondition-8 271ns ±15% 92ns ±14% -65.93% (p=0.000 n=10+10) Unmarshal/*amqp.Error-8 1.19µs ± 9% 0.76µs ±17% -36.36% (p=0.000 n=10+10) Unmarshal/*amqp.performEnd-8 1.38µs ± 4% 0.86µs ±23% -37.86% (p=0.000 n=10+10) Unmarshal/*amqp.performClose-8 1.32µs ± 2% 0.82µs ± 8% -38.12% (p=0.000 n=8+10) Unmarshal/*amqp.Message-8 4.66µs ± 4% 2.94µs ±16% -36.87% (p=0.000 n=10+10) Unmarshal/*amqp.MessageHeader-8 647ns ± 0% 206ns ± 1% -68.18% (p=0.000 n=8+9) Unmarshal/*amqp.MessageProperties-8 1.47µs ± 1% 0.53µs ± 1% -63.75% (p=0.000 n=10+10) Unmarshal/*amqp.stateReceived-8 385ns ± 2% 126ns ± 1% -67.23% (p=0.000 n=9+10) Unmarshal/*amqp.stateAccepted-8 255ns ±17% 94ns ± 3% -63.08% (p=0.000 n=10+10) Unmarshal/*amqp.stateRejected-8 1.40µs ± 4% 0.87µs ±11% -38.12% (p=0.000 n=9+10) Unmarshal/*amqp.stateReleased-8 251ns ± 9% 94ns ± 4% -62.81% (p=0.000 n=10+10) Unmarshal/*amqp.stateModified-8 1.01µs ± 8% 0.68µs ±21% -33.07% (p=0.000 n=9+10) Unmarshal/amqp.lifetimePolicy-8 203ns ± 7% 63ns ± 7% -68.74% (p=0.000 n=10+9) Unmarshal/amqp.SenderSettleMode-8 218ns ± 9% 57ns ±21% -73.84% (p=0.000 n=9+10) Unmarshal/amqp.ReceiverSettleMode-8 221ns ±11% 57ns ± 7% -74.38% (p=0.000 n=10+9) Unmarshal/*amqp.saslInit-8 551ns ± 1% 220ns ± 1% -60.10% (p=0.000 n=10+10) Unmarshal/*amqp.saslMechanisms-8 420ns ± 2% 187ns ± 1% -55.35% (p=0.000 n=10+9) Unmarshal/*amqp.saslOutcome-8 511ns ± 2% 187ns ± 2% -63.46% (p=0.000 n=10+9) Unmarshal/amqp.milliseconds-8 189ns ±22% 60ns ±17% -68.31% (p=0.000 n=10+10) Unmarshal/amqp.symbol-8 201ns ±12% 74ns ±21% -63.44% (p=0.000 n=10+10) Unmarshal/map[amqp.symbol]interface_{}-8 897ns ±31% 614ns ±16% -31.57% (p=0.000 n=10+10) Unmarshal/amqp.UUID-8 215ns ±16% 66ns ±12% -69.16% (p=0.000 n=10+10) Unmarshal/bool-8 174ns ±34% 56ns ±10% -67.75% (p=0.000 n=10+10) Unmarshal/int8-8 201ns ±26% 54ns ±17% -72.95% (p=0.000 n=10+10) Unmarshal/int8#01-8 175ns ±23% 57ns ±21% -67.47% (p=0.000 n=10+10) Unmarshal/int16-8 189ns ±15% 56ns ±16% -70.29% (p=0.000 n=10+10) Unmarshal/int16#01-8 185ns ±22% 55ns ±17% -70.31% (p=0.000 n=10+10) Unmarshal/int32-8 198ns ±13% 53ns ±11% -73.27% (p=0.000 n=10+9) Unmarshal/int32#01-8 200ns ±14% 55ns ±13% -72.32% (p=0.000 n=10+10) Unmarshal/int64-8 206ns ±16% 56ns ±19% -72.93% (p=0.000 n=10+10) Unmarshal/int64#01-8 190ns ±14% 52ns ±12% -72.48% (p=0.000 n=10+9) Unmarshal/uint8-8 188ns ±11% 55ns ±13% -70.70% (p=0.000 n=10+10) Unmarshal/uint16-8 197ns ±12% 55ns ±11% -72.16% (p=0.000 n=10+10) Unmarshal/uint32-8 187ns ±14% 57ns ±10% -69.62% (p=0.000 n=8+9) Unmarshal/uint64-8 174ns ±23% 54ns ±27% -68.90% (p=0.000 n=10+10) Unmarshal/float32-8 198ns ±24% 55ns ±20% -72.17% (p=0.000 n=10+10) Unmarshal/float32#01-8 187ns ±15% 55ns ±12% -70.82% (p=0.000 n=10+10) Unmarshal/float32#02-8 186ns ±19% 56ns ±13% -69.76% (p=0.000 n=10+10) Unmarshal/float32#03-8 184ns ±12% 52ns ±13% -71.93% (p=0.000 n=10+10) Unmarshal/float64-8 179ns ± 7% 54ns ± 7% -69.55% (p=0.000 n=9+10) Unmarshal/float64#01-8 188ns ±17% 54ns ±16% -71.39% (p=0.000 n=10+10) Unmarshal/float64#02-8 186ns ±15% 55ns ±19% -70.35% (p=0.000 n=10+10) Unmarshal/float64#03-8 185ns ±13% 56ns ±21% -69.69% (p=0.000 n=10+10) Unmarshal/amqp.describedType-8 413ns ±12% 203ns ±11% -50.91% (p=0.000 n=10+10) Unmarshal/map[interface_{}]interface_{}-8 774ns ±22% 618ns ±17% -20.15% (p=0.000 n=10+10) Unmarshal/map[string]interface_{}-8 769ns ±35% 591ns ±17% -23.16% (p=0.015 n=10+10) Unmarshal/amqp.ArrayUByte-8 203ns ±16% 88ns ±10% -56.70% (p=0.000 n=10+10) Unmarshal/[]int8-8 205ns ±12% 58ns ±10% -71.96% (p=0.000 n=9+9) Unmarshal/[]uint16-8 194ns ±14% 63ns ±18% -67.66% (p=0.000 n=10+10) Unmarshal/[]uint16#01-8 194ns ±20% 62ns ±12% -68.16% (p=0.000 n=10+10) Unmarshal/[]int16-8 200ns ±12% 61ns ± 6% -69.48% (p=0.000 n=10+9) Unmarshal/[]int16#01-8 200ns ± 7% 64ns ±14% -68.04% (p=0.000 n=10+10) Unmarshal/[]uint32-8 193ns ±16% 61ns ±10% -68.53% (p=0.000 n=10+10) Unmarshal/[]uint32#01-8 200ns ±20% 58ns ±11% -70.86% (p=0.000 n=10+10) Unmarshal/[]int32-8 201ns ±20% 64ns ±15% -68.14% (p=0.000 n=10+10) Unmarshal/[]int32#01-8 187ns ±14% 60ns ±17% -67.67% (p=0.000 n=9+10) Unmarshal/[]uint64-8 182ns ±12% 63ns ±12% -65.47% (p=0.000 n=10+10) Unmarshal/[]uint64#01-8 207ns ± 8% 60ns ±16% -70.82% (p=0.000 n=9+10) Unmarshal/[]int64-8 202ns ±20% 64ns ±10% -68.57% (p=0.000 n=10+10) Unmarshal/[]int64#01-8 197ns ±19% 56ns ± 9% -71.50% (p=0.000 n=10+9) Unmarshal/[]float32-8 197ns ±14% 61ns ±16% -68.78% (p=0.000 n=10+9) Unmarshal/[]float64-8 202ns ±16% 64ns ± 7% -68.32% (p=0.000 n=10+9) Unmarshal/[]bool-8 195ns ±15% 61ns ± 6% -68.76% (p=0.000 n=10+9) Unmarshal/[]string-8 249ns ±10% 109ns ± 5% -56.19% (p=0.000 n=10+10) Unmarshal/[]amqp.symbol-8 253ns ± 9% 110ns ± 5% -56.60% (p=0.000 n=10+10) Unmarshal/[][]uint8-8 285ns ± 3% 139ns ± 6% -51.29% (p=0.000 n=8+10) Unmarshal/[]time.Time-8 192ns ±15% 61ns ± 6% -68.44% (p=0.000 n=10+10) Unmarshal/[]amqp.UUID-8 192ns ±12% 61ns ±12% -67.98% (p=0.000 n=10+10) Unmarshal/[]interface_{}-8 296ns ± 8% 142ns ± 4% -51.92% (p=0.000 n=9+10) name old alloc/op new alloc/op delta FrameMarshal/transfer-8 0.00B 0.00B ~ (all equal) FrameUnmarshal/transfer-8 312B ± 0% 232B ± 0% -25.64% (p=0.000 n=10+10) Marshal/*amqp.performOpen-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performBegin-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performAttach-8 576B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/amqp.role-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.unsettled-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.source-8 230B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.target-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performFlow-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performTransfer-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.performDisposition-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.performDetach-8 131B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performDetach#01-8 617B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/amqp.ErrorCondition-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.Error-8 131B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performEnd-8 131B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.performClose-8 131B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.Message-8 464B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.MessageHeader-8 4.00B ± 0% 0.00B -100.00% (p=0.000 n=10+10) Marshal/*amqp.MessageProperties-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.stateReceived-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.stateAccepted-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.stateRejected-8 131B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.stateReleased-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.stateModified-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/amqp.lifetimePolicy-8 0.00B 0.00B ~ (all equal) Marshal/amqp.SenderSettleMode-8 0.00B 0.00B ~ (all equal) Marshal/amqp.ReceiverSettleMode-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.saslInit-8 0.00B 0.00B ~ (all equal) Marshal/*amqp.saslMechanisms-8 32.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Marshal/*amqp.saslOutcome-8 32.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Marshal/amqp.milliseconds-8 4.00B ± 0% 0.00B -100.00% (p=0.000 n=10+10) Marshal/amqp.symbol-8 0.00B 0.00B ~ (all equal) Marshal/map[amqp.symbol]interface_{}-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/amqp.UUID-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Marshal/bool-8 0.00B 0.00B ~ (all equal) Marshal/int8-8 0.00B 0.00B ~ (all equal) Marshal/int8#01-8 0.00B 0.00B ~ (all equal) Marshal/int16-8 0.00B 0.00B ~ (all equal) Marshal/int16#01-8 0.00B 0.00B ~ (all equal) Marshal/int32-8 0.00B 0.00B ~ (all equal) Marshal/int32#01-8 0.00B 0.00B ~ (all equal) Marshal/int64-8 0.00B 0.00B ~ (all equal) Marshal/int64#01-8 0.00B 0.00B ~ (all equal) Marshal/uint8-8 0.00B 0.00B ~ (all equal) Marshal/uint16-8 0.00B 0.00B ~ (all equal) Marshal/uint32-8 0.00B 0.00B ~ (all equal) Marshal/uint64-8 0.00B 0.00B ~ (all equal) Marshal/float32-8 0.00B 0.00B ~ (all equal) Marshal/float32#01-8 0.00B 0.00B ~ (all equal) Marshal/float32#02-8 0.00B 0.00B ~ (all equal) Marshal/float32#03-8 0.00B 0.00B ~ (all equal) Marshal/float64-8 0.00B 0.00B ~ (all equal) Marshal/float64#01-8 0.00B 0.00B ~ (all equal) Marshal/float64#02-8 0.00B 0.00B ~ (all equal) Marshal/float64#03-8 0.00B 0.00B ~ (all equal) Marshal/amqp.describedType-8 0.00B 0.00B ~ (all equal) Marshal/map[interface_{}]interface_{}-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/map[string]interface_{}-8 115B ± 0% 0B -100.00% (p=0.000 n=10+10) Marshal/amqp.ArrayUByte-8 0.00B 0.00B ~ (all equal) Marshal/[]int8-8 0.00B 0.00B ~ (all equal) Marshal/[]uint16-8 0.00B 0.00B ~ (all equal) Marshal/[]uint16#01-8 0.00B 0.00B ~ (all equal) Marshal/[]int16-8 0.00B 0.00B ~ (all equal) Marshal/[]int16#01-8 0.00B 0.00B ~ (all equal) Marshal/[]uint32-8 0.00B 0.00B ~ (all equal) Marshal/[]uint32#01-8 0.00B 0.00B ~ (all equal) Marshal/[]int32-8 0.00B 0.00B ~ (all equal) Marshal/[]int32#01-8 0.00B 0.00B ~ (all equal) Marshal/[]uint64-8 0.00B 0.00B ~ (all equal) Marshal/[]uint64#01-8 0.00B 0.00B ~ (all equal) Marshal/[]int64-8 0.00B 0.00B ~ (all equal) Marshal/[]int64#01-8 0.00B 0.00B ~ (all equal) Marshal/[]float32-8 0.00B 0.00B ~ (all equal) Marshal/[]float64-8 0.00B 0.00B ~ (all equal) Marshal/[]bool-8 0.00B 0.00B ~ (all equal) Marshal/[]string-8 0.00B 0.00B ~ (all equal) Marshal/[]amqp.symbol-8 0.00B 0.00B ~ (all equal) Marshal/[][]uint8-8 0.00B 0.00B ~ (all equal) Marshal/[]time.Time-8 0.00B 0.00B ~ (all equal) Marshal/[]amqp.UUID-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Marshal/[]interface_{}-8 0.00B 0.00B ~ (all equal) Unmarshal/*amqp.performOpen-8 544B ± 0% 464B ± 0% -14.71% (p=0.000 n=10+10) Unmarshal/*amqp.performBegin-8 496B ± 0% 416B ± 0% -16.13% (p=0.000 n=10+10) Unmarshal/*amqp.performAttach-8 2.08kB ± 0% 2.00kB ± 0% -3.85% (p=0.000 n=10+10) Unmarshal/amqp.role-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/*amqp.unsettled-8 480B ± 0% 400B ± 0% -16.67% (p=0.000 n=10+10) Unmarshal/*amqp.source-8 928B ± 0% 848B ± 0% -8.62% (p=0.000 n=10+10) Unmarshal/*amqp.target-8 512B ± 0% 432B ± 0% -15.62% (p=0.000 n=10+10) Unmarshal/*amqp.performFlow-8 464B ± 0% 400B ± 0% -13.79% (p=0.000 n=10+10) Unmarshal/*amqp.performTransfer-8 168B ± 0% 96B ± 0% -42.86% (p=0.000 n=10+10) Unmarshal/*amqp.performDisposition-8 112B ± 0% 36B ± 0% -67.86% (p=0.000 n=10+10) Unmarshal/*amqp.performDetach-8 512B ± 0% 432B ± 0% -15.62% (p=0.000 n=10+10) Unmarshal/*amqp.performDetach#01-8 728B ± 0% 648B ± 0% -10.99% (p=0.000 n=10+10) Unmarshal/amqp.ErrorCondition-8 128B ± 0% 48B ± 0% -62.50% (p=0.000 n=10+10) Unmarshal/*amqp.Error-8 512B ± 0% 432B ± 0% -15.62% (p=0.000 n=10+10) Unmarshal/*amqp.performEnd-8 512B ± 0% 432B ± 0% -15.62% (p=0.000 n=10+10) Unmarshal/*amqp.performClose-8 512B ± 0% 432B ± 0% -15.62% (p=0.000 n=10+10) Unmarshal/*amqp.Message-8 1.73kB ± 0% 1.65kB ± 0% -4.63% (p=0.000 n=10+10) Unmarshal/*amqp.MessageHeader-8 128B ± 0% 48B ± 0% -62.50% (p=0.000 n=10+10) Unmarshal/*amqp.MessageProperties-8 208B ± 0% 128B ± 0% -38.46% (p=0.000 n=10+10) Unmarshal/*amqp.stateReceived-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/*amqp.stateAccepted-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/*amqp.stateRejected-8 517B ± 0% 437B ± 0% -15.47% (p=0.000 n=10+10) Unmarshal/*amqp.stateReleased-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/*amqp.stateModified-8 480B ± 0% 400B ± 0% -16.67% (p=0.000 n=10+10) Unmarshal/amqp.lifetimePolicy-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/amqp.SenderSettleMode-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/amqp.ReceiverSettleMode-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/*amqp.saslInit-8 134B ± 0% 54B ± 0% -59.70% (p=0.000 n=10+10) Unmarshal/*amqp.saslMechanisms-8 121B ± 0% 41B ± 0% -66.12% (p=0.000 n=10+10) Unmarshal/*amqp.saslOutcome-8 144B ± 0% 64B ± 0% -55.56% (p=0.000 n=10+10) Unmarshal/amqp.milliseconds-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/amqp.symbol-8 120B ± 0% 40B ± 0% -66.67% (p=0.000 n=10+10) Unmarshal/map[amqp.symbol]interface_{}-8 500B ± 0% 420B ± 0% -16.00% (p=0.000 n=10+10) Unmarshal/amqp.UUID-8 128B ± 0% 32B ± 0% -75.00% (p=0.000 n=10+10) Unmarshal/bool-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int8-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int8#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int16-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int16#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int32#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/int64#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/uint8-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/uint16-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/uint32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/uint64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float32#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float32#02-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float32#03-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float64#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float64#02-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/float64#03-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/amqp.describedType-8 184B ± 0% 104B ± 0% -43.48% (p=0.000 n=10+10) Unmarshal/map[interface_{}]interface_{}-8 500B ± 0% 420B ± 0% -16.00% (p=0.000 n=10+10) Unmarshal/map[string]interface_{}-8 500B ± 0% 420B ± 0% -16.00% (p=0.000 n=10+10) Unmarshal/amqp.ArrayUByte-8 112B ± 0% 40B ± 0% -64.29% (p=0.000 n=10+10) Unmarshal/[]int8-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint16-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint16#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int16-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int16#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint32#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int32#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]uint64#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]int64#01-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]float32-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]float64-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]bool-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]string-8 121B ± 0% 41B ± 0% -66.12% (p=0.000 n=10+10) Unmarshal/[]amqp.symbol-8 121B ± 0% 41B ± 0% -66.12% (p=0.000 n=10+10) Unmarshal/[][]uint8-8 136B ± 0% 56B ± 0% -58.82% (p=0.000 n=10+10) Unmarshal/[]time.Time-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]amqp.UUID-8 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) Unmarshal/[]interface_{}-8 136B ± 0% 56B ± 0% -58.82% (p=0.000 n=10+10) name old allocs/op new allocs/op delta FrameMarshal/transfer-8 0.00 0.00 ~ (all equal) FrameUnmarshal/transfer-8 8.00 ± 0% 8.00 ± 0% ~ (all equal) Marshal/*amqp.performOpen-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performBegin-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performAttach-8 10.0 ± 0% 0.0 -100.00% (p=0.000 n=10+10) Marshal/amqp.role-8 0.00 0.00 ~ (all equal) Marshal/*amqp.unsettled-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.source-8 4.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.target-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performFlow-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performTransfer-8 0.00 0.00 ~ (all equal) Marshal/*amqp.performDisposition-8 0.00 0.00 ~ (all equal) Marshal/*amqp.performDetach-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performDetach#01-8 4.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.ErrorCondition-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.Error-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performEnd-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.performClose-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.Message-8 9.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.MessageHeader-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.MessageProperties-8 0.00 0.00 ~ (all equal) Marshal/*amqp.stateReceived-8 0.00 0.00 ~ (all equal) Marshal/*amqp.stateAccepted-8 0.00 0.00 ~ (all equal) Marshal/*amqp.stateRejected-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.stateReleased-8 0.00 0.00 ~ (all equal) Marshal/*amqp.stateModified-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.lifetimePolicy-8 0.00 0.00 ~ (all equal) Marshal/amqp.SenderSettleMode-8 0.00 0.00 ~ (all equal) Marshal/amqp.ReceiverSettleMode-8 0.00 0.00 ~ (all equal) Marshal/*amqp.saslInit-8 0.00 0.00 ~ (all equal) Marshal/*amqp.saslMechanisms-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/*amqp.saslOutcome-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.milliseconds-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.symbol-8 0.00 0.00 ~ (all equal) Marshal/map[amqp.symbol]interface_{}-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.UUID-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/bool-8 0.00 0.00 ~ (all equal) Marshal/int8-8 0.00 0.00 ~ (all equal) Marshal/int8#01-8 0.00 0.00 ~ (all equal) Marshal/int16-8 0.00 0.00 ~ (all equal) Marshal/int16#01-8 0.00 0.00 ~ (all equal) Marshal/int32-8 0.00 0.00 ~ (all equal) Marshal/int32#01-8 0.00 0.00 ~ (all equal) Marshal/int64-8 0.00 0.00 ~ (all equal) Marshal/int64#01-8 0.00 0.00 ~ (all equal) Marshal/uint8-8 0.00 0.00 ~ (all equal) Marshal/uint16-8 0.00 0.00 ~ (all equal) Marshal/uint32-8 0.00 0.00 ~ (all equal) Marshal/uint64-8 0.00 0.00 ~ (all equal) Marshal/float32-8 0.00 0.00 ~ (all equal) Marshal/float32#01-8 0.00 0.00 ~ (all equal) Marshal/float32#02-8 0.00 0.00 ~ (all equal) Marshal/float32#03-8 0.00 0.00 ~ (all equal) Marshal/float64-8 0.00 0.00 ~ (all equal) Marshal/float64#01-8 0.00 0.00 ~ (all equal) Marshal/float64#02-8 0.00 0.00 ~ (all equal) Marshal/float64#03-8 0.00 0.00 ~ (all equal) Marshal/amqp.describedType-8 0.00 0.00 ~ (all equal) Marshal/map[interface_{}]interface_{}-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/map[string]interface_{}-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/amqp.ArrayUByte-8 0.00 0.00 ~ (all equal) Marshal/[]int8-8 0.00 0.00 ~ (all equal) Marshal/[]uint16-8 0.00 0.00 ~ (all equal) Marshal/[]uint16#01-8 0.00 0.00 ~ (all equal) Marshal/[]int16-8 0.00 0.00 ~ (all equal) Marshal/[]int16#01-8 0.00 0.00 ~ (all equal) Marshal/[]uint32-8 0.00 0.00 ~ (all equal) Marshal/[]uint32#01-8 0.00 0.00 ~ (all equal) Marshal/[]int32-8 0.00 0.00 ~ (all equal) Marshal/[]int32#01-8 0.00 0.00 ~ (all equal) Marshal/[]uint64-8 0.00 0.00 ~ (all equal) Marshal/[]uint64#01-8 0.00 0.00 ~ (all equal) Marshal/[]int64-8 0.00 0.00 ~ (all equal) Marshal/[]int64#01-8 0.00 0.00 ~ (all equal) Marshal/[]float32-8 0.00 0.00 ~ (all equal) Marshal/[]float64-8 0.00 0.00 ~ (all equal) Marshal/[]bool-8 0.00 0.00 ~ (all equal) Marshal/[]string-8 0.00 0.00 ~ (all equal) Marshal/[]amqp.symbol-8 0.00 0.00 ~ (all equal) Marshal/[][]uint8-8 0.00 0.00 ~ (all equal) Marshal/[]time.Time-8 0.00 0.00 ~ (all equal) Marshal/[]amqp.UUID-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Marshal/[]interface_{}-8 0.00 0.00 ~ (all equal) Unmarshal/*amqp.performOpen-8 13.0 ± 0% 13.0 ± 0% ~ (all equal) Unmarshal/*amqp.performBegin-8 8.00 ± 0% 8.00 ± 0% ~ (all equal) Unmarshal/*amqp.performAttach-8 33.0 ± 0% 33.0 ± 0% ~ (all equal) Unmarshal/amqp.role-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/*amqp.unsettled-8 5.00 ± 0% 5.00 ± 0% ~ (all equal) Unmarshal/*amqp.source-8 15.0 ± 0% 15.0 ± 0% ~ (all equal) Unmarshal/*amqp.target-8 8.00 ± 0% 8.00 ± 0% ~ (all equal) Unmarshal/*amqp.performFlow-8 5.00 ± 0% 10.00 ± 0% +100.00% (p=0.000 n=10+10) Unmarshal/*amqp.performTransfer-8 4.00 ± 0% 6.00 ± 0% +50.00% (p=0.000 n=10+10) Unmarshal/*amqp.performDisposition-8 1.00 ± 0% 2.00 ± 0% +100.00% (p=0.000 n=10+10) Unmarshal/*amqp.performDetach-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) Unmarshal/*amqp.performDetach#01-8 15.0 ± 0% 15.0 ± 0% ~ (all equal) Unmarshal/amqp.ErrorCondition-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) Unmarshal/*amqp.Error-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) Unmarshal/*amqp.performEnd-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) Unmarshal/*amqp.performClose-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) Unmarshal/*amqp.Message-8 33.0 ± 0% 33.0 ± 0% ~ (all equal) Unmarshal/*amqp.MessageHeader-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) Unmarshal/*amqp.MessageProperties-8 12.0 ± 0% 12.0 ± 0% ~ (all equal) Unmarshal/*amqp.stateReceived-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/*amqp.stateAccepted-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/*amqp.stateRejected-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) Unmarshal/*amqp.stateReleased-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/*amqp.stateModified-8 6.00 ± 0% 6.00 ± 0% ~ (all equal) Unmarshal/amqp.lifetimePolicy-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/amqp.SenderSettleMode-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/amqp.ReceiverSettleMode-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/*amqp.saslInit-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/*amqp.saslMechanisms-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/*amqp.saslOutcome-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) Unmarshal/amqp.milliseconds-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/amqp.symbol-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) Unmarshal/map[amqp.symbol]interface_{}-8 6.00 ± 0% 6.00 ± 0% ~ (all equal) Unmarshal/amqp.UUID-8 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10) Unmarshal/bool-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int8-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int8#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int16-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int16#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int32#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/int64#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/uint8-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/uint16-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/uint32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/uint64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float32#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float32#02-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float32#03-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float64#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float64#02-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/float64#03-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/amqp.describedType-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/map[interface_{}]interface_{}-8 6.00 ± 0% 6.00 ± 0% ~ (all equal) Unmarshal/map[string]interface_{}-8 6.00 ± 0% 6.00 ± 0% ~ (all equal) Unmarshal/amqp.ArrayUByte-8 1.00 ± 0% 2.00 ± 0% +100.00% (p=0.000 n=10+10) Unmarshal/[]int8-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint16-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint16#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int16-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int16#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint32#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int32#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]uint64#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]int64#01-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]float32-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]float64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]bool-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]string-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/[]amqp.symbol-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/[][]uint8-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) Unmarshal/[]time.Time-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]amqp.UUID-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Unmarshal/[]interface_{}-8 4.00 ± 0% 4.00 ± 0% ~ (all equal) ```
2018-02-03 22:54:49 +03:00
}
parsedBody, err := frames.ParseBody(buffer.New(b))
2017-04-27 06:35:29 +03:00
if err != nil {
return frames.Frame{}, err
2017-04-27 06:35:29 +03:00
}
return frames.Frame{Channel: currentHeader.Channel, Body: parsedBody}, nil
2017-04-01 23:00:36 +03:00
}
}
// frameContext is an extended context.Context used to track writes to the network.
// this is required in order to remove ambiguities that can arise when simply waiting
// on context.Context.Done() to be signaled.
type frameContext struct {
// Ctx contains the caller's context and is used to set the write deadline.
Ctx context.Context
// Done is closed when the frame was successfully written to net.Conn or Ctx was cancelled/timed out.
// Can be nil, but shouldn't be for callers that care about confirmation of sending.
Done chan struct{}
// Err contains the context error. MUST be set before closing Done and ONLY read if Done is closed.
// ONLY Conn.connWriter may write to this field.
Err error
}
// frameEnvelope is used when sending a frame to connWriter to be written to net.Conn
type frameEnvelope struct {
FrameCtx *frameContext
Frame frames.Frame
}
func (c *Conn) connWriter() {
defer func() {
close(c.txDone)
c.close()
}()
var (
// keepalives are sent at a rate of 1/2 idle timeout
keepaliveInterval = c.peerIdleTimeout / 2
// 0 disables keepalives
keepalivesEnabled = keepaliveInterval > 0
// set if enable, nil if not; nil channels block forever
keepalive <-chan time.Time
)
if keepalivesEnabled {
ticker := time.NewTicker(keepaliveInterval)
defer ticker.Stop()
keepalive = ticker.C
}
var err error
for {
if err != nil {
debug.Log(0, "TX (connWriter %p): terminal error: %v", c, err)
c.txErr = err
return
}
select {
// frame write request
case env := <-c.txFrame:
timeout, ctxErr := c.getWriteTimeout(env.FrameCtx.Ctx)
if ctxErr != nil {
debug.Log(1, "TX (connWriter %p) getWriteTimeout: %s: %s", c, ctxErr.Error(), env.Frame)
if env.FrameCtx.Done != nil {
// the error MUST be set before closing the channel
env.FrameCtx.Err = ctxErr
close(env.FrameCtx.Done)
}
continue
}
debug.Log(0, "TX (connWriter %p) timeout %s: %s", c, timeout, env.Frame)
err = c.writeFrame(timeout, env.Frame)
if err == nil && env.FrameCtx.Done != nil {
close(env.FrameCtx.Done)
}
// in the event of write failure, Conn will close and a
// *ConnError will be propagated to all of the sessions/link.
// keepalive timer
case <-keepalive:
debug.Log(3, "TX (connWriter %p): sending keep-alive frame", c)
_ = c.net.SetWriteDeadline(time.Now().Add(c.writeTimeout))
if _, err = c.net.Write(keepaliveFrame); err != nil {
err = &ConnError{inner: err}
}
// It would be slightly more efficient in terms of network
// resources to reset the timer each time a frame is sent.
// However, keepalives are small (8 bytes) and the interval
// is usually on the order of minutes. It does not seem
// worth it to add extra operations in the write path to
// avoid. (To properly reset a timer it needs to be stopped,
// possibly drained, then reset.)
// connection complete
case <-c.rxtxExit:
// send close performative. note that the spec says we
// SHOULD wait for the ack but we don't HAVE to, in order
// to be resilient to bad actors etc. so we just send
// the close performative and exit.
fr := frames.Frame{
Type: frames.TypeAMQP,
Body: &frames.PerformClose{},
}
debug.Log(1, "TX (connWriter %p): %s", c, fr)
c.txErr = c.writeFrame(c.writeTimeout, fr)
return
}
}
}
// writeFrame writes a frame to the network.
// used externally by SASL only.
// - timeout - the write deadline to set. zero means no deadline
//
// errors are wrapped in a ConnError as they can be returned to outside callers.
func (c *Conn) writeFrame(timeout time.Duration, fr frames.Frame) error {
2017-05-07 02:57:27 +03:00
// writeFrame into txBuf
c.txBuf.Reset()
err := frames.Write(&c.txBuf, fr)
if err != nil {
return &ConnError{inner: err}
}
// validate the frame isn't exceeding peer's max frame size
requiredFrameSize := c.txBuf.Len()
if uint64(requiredFrameSize) > uint64(c.peerMaxFrameSize) {
return &ConnError{inner: fmt.Errorf("%T frame size %d larger than peer's max frame size %d", fr, requiredFrameSize, c.peerMaxFrameSize)}
}
if timeout == 0 {
_ = c.net.SetWriteDeadline(time.Time{})
} else if timeout > 0 {
_ = c.net.SetWriteDeadline(time.Now().Add(timeout))
}
2017-05-07 02:57:27 +03:00
// write to network
n, err := c.net.Write(c.txBuf.Bytes())
if l := c.txBuf.Len(); n > 0 && n < l && err != nil {
debug.Log(1, "TX (writeFrame %p): wrote %d bytes less than len %d: %v", c, n, l, err)
}
if err != nil {
err = &ConnError{inner: err}
}
return err
}
2017-05-07 02:57:27 +03:00
// writeProtoHeader writes an AMQP protocol header to the
// network
func (c *Conn) writeProtoHeader(pID protoID) error {
_, err := c.net.Write([]byte{'A', 'M', 'Q', 'P', byte(pID), 1, 0, 0})
return err
}
// keepaliveFrame is an AMQP frame with no body, used for keepalives
var keepaliveFrame = []byte{0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00}
// SendFrame is used by sessions and links to send frames across the network.
func (c *Conn) sendFrame(frameEnv frameEnvelope) {
select {
case c.txFrame <- frameEnv:
debug.Log(2, "TX (Conn %p): mux frame to connWriter: %s", c, frameEnv.Frame)
case <-c.done:
// Conn has closed
}
}
// stateFunc is a state in a state machine.
//
// The state is advanced by returning the next state.
// The state machine concludes when nil is returned.
type stateFunc func(context.Context) (stateFunc, error)
// negotiateProto determines which proto to negotiate next.
// used externally by SASL only.
func (c *Conn) negotiateProto(ctx context.Context) (stateFunc, error) {
// in the order each must be negotiated
2017-04-01 23:00:36 +03:00
switch {
case c.tlsNegotiation && !c.tlsComplete:
2017-04-23 21:01:44 +03:00
return c.exchangeProtoHeader(protoTLS)
2017-04-01 23:00:36 +03:00
case c.saslHandlers != nil && !c.saslComplete:
2017-04-23 21:01:44 +03:00
return c.exchangeProtoHeader(protoSASL)
2017-04-01 23:00:36 +03:00
default:
2017-04-23 21:01:44 +03:00
return c.exchangeProtoHeader(protoAMQP)
2017-04-01 23:00:36 +03:00
}
}
type protoID uint8
// protocol IDs received in protoHeaders
2017-04-01 23:00:36 +03:00
const (
protoAMQP protoID = 0x0
protoTLS protoID = 0x2
protoSASL protoID = 0x3
2017-04-01 23:00:36 +03:00
)
2017-04-30 02:38:15 +03:00
// exchangeProtoHeader performs the round trip exchange of protocol
// headers, validation, and returns the protoID specific next state.
func (c *Conn) exchangeProtoHeader(pID protoID) (stateFunc, error) {
// write the proto header
if err := c.writeProtoHeader(pID); err != nil {
return nil, err
}
2017-04-01 23:00:36 +03:00
// read response header
p, err := c.readProtoHeader()
if err != nil {
return nil, err
2017-04-01 23:00:36 +03:00
}
if pID != p.ProtoID {
return nil, fmt.Errorf("unexpected protocol header %#00x, expected %#00x", p.ProtoID, pID)
2017-04-01 23:00:36 +03:00
}
// go to the proto specific state
switch pID {
2017-04-23 21:01:44 +03:00
case protoAMQP:
return c.openAMQP, nil
2017-04-23 21:01:44 +03:00
case protoTLS:
return c.startTLS, nil
2017-04-23 21:01:44 +03:00
case protoSASL:
return c.negotiateSASL, nil
2017-04-01 23:00:36 +03:00
default:
return nil, fmt.Errorf("unknown protocol ID %#02x", p.ProtoID)
2017-04-01 23:00:36 +03:00
}
}
2017-05-07 02:57:27 +03:00
// readProtoHeader reads a protocol header packet from c.rxProto.
func (c *Conn) readProtoHeader() (protoHeader, error) {
const protoHeaderSize = 8
// only read from the network once our buffer has been exhausted.
// TODO: this preserves existing behavior as some tests rely on this
// implementation detail (it lets you replay a stream of bytes). we
// might want to consider removing this and fixing the tests as the
// protocol doesn't actually work this way.
if c.rxBuf.Len() == 0 {
for {
err := c.rxBuf.ReadFromOnce(c.net)
if err != nil {
return protoHeader{}, err
}
2017-04-30 05:33:03 +03:00
// read more if buf doesn't contain enough to parse the header
if c.rxBuf.Len() >= protoHeaderSize {
break
}
}
}
buf, ok := c.rxBuf.Next(protoHeaderSize)
if !ok {
return protoHeader{}, errors.New("invalid protoHeader")
}
// bounds check hint to compiler; see golang.org/issue/14808
_ = buf[protoHeaderSize-1]
if !bytes.Equal(buf[:4], []byte{'A', 'M', 'Q', 'P'}) {
return protoHeader{}, fmt.Errorf("unexpected protocol %q", buf[:4])
}
p := protoHeader{
ProtoID: protoID(buf[4]),
Major: buf[5],
Minor: buf[6],
Revision: buf[7],
}
if p.Major != 1 || p.Minor != 0 || p.Revision != 0 {
return protoHeader{}, fmt.Errorf("unexpected protocol version %d.%d.%d", p.Major, p.Minor, p.Revision)
}
return p, nil
}
// startTLS wraps the conn with TLS and returns to Client.negotiateProto
func (c *Conn) startTLS(ctx context.Context) (stateFunc, error) {
c.initTLSConfig()
_ = c.net.SetReadDeadline(time.Time{}) // clear timeout
// wrap existing net.Conn and perform TLS handshake
tlsConn := tls.Client(c.net, c.tlsConfig)
if err := tlsConn.HandshakeContext(ctx); err != nil {
return nil, err
2017-04-30 05:33:03 +03:00
}
// swap net.Conn
c.net = tlsConn
c.tlsComplete = true
// go to next protocol
return c.negotiateProto, nil
2017-04-23 04:32:50 +03:00
}
2017-04-30 02:38:15 +03:00
// openAMQP round trips the AMQP open performative
func (c *Conn) openAMQP(ctx context.Context) (stateFunc, error) {
// send open frame
open := &frames.PerformOpen{
ContainerID: c.containerID,
Hostname: c.hostname,
MaxFrameSize: c.maxFrameSize,
ChannelMax: c.channelMax,
IdleTimeout: c.idleTimeout / 2, // per spec, advertise half our idle timeout
Properties: c.properties,
}
fr := frames.Frame{
Type: frames.TypeAMQP,
Body: open,
Channel: 0,
}
debug.Log(1, "TX (openAMQP %p): %s", c, fr)
timeout, err := c.getWriteTimeout(ctx)
if err != nil {
return nil, err
}
if err = c.writeFrame(timeout, fr); err != nil {
return nil, err
}
2017-04-01 23:00:36 +03:00
// get the response
fr, err = c.readSingleFrame()
2017-04-01 23:00:36 +03:00
if err != nil {
return nil, err
2017-04-01 23:00:36 +03:00
}
debug.Log(1, "RX (openAMQP %p): %s", c, fr)
o, ok := fr.Body.(*frames.PerformOpen)
2017-04-24 06:24:12 +03:00
if !ok {
return nil, fmt.Errorf("openAMQP: unexpected frame type %T", fr.Body)
2017-04-01 23:00:36 +03:00
}
// update peer settings
2017-04-27 06:35:29 +03:00
if o.MaxFrameSize > 0 {
c.peerMaxFrameSize = o.MaxFrameSize
2017-04-27 06:35:29 +03:00
}
2017-04-23 21:01:44 +03:00
if o.IdleTimeout > 0 {
// TODO: reject very small idle timeouts
2017-04-30 02:38:15 +03:00
c.peerIdleTimeout = o.IdleTimeout
2017-04-17 06:39:31 +03:00
}
2017-04-01 23:00:36 +03:00
if o.ChannelMax < c.channelMax {
c.channelMax = o.ChannelMax
}
// connection established, exit state machine
return nil, nil
2017-04-01 23:00:36 +03:00
}
2017-04-30 02:38:15 +03:00
// negotiateSASL returns the SASL handler for the first matched
// mechanism specified by the server
func (c *Conn) negotiateSASL(context.Context) (stateFunc, error) {
// read mechanisms frame
fr, err := c.readSingleFrame()
2017-04-01 23:00:36 +03:00
if err != nil {
return nil, err
2017-04-01 23:00:36 +03:00
}
debug.Log(1, "RX (negotiateSASL %p): %s", c, fr)
sm, ok := fr.Body.(*frames.SASLMechanisms)
2017-04-24 06:24:12 +03:00
if !ok {
return nil, fmt.Errorf("negotiateSASL: unexpected frame type %T", fr.Body)
2017-04-01 23:00:36 +03:00
}
// return first match in c.saslHandlers based on order received
2017-04-01 23:00:36 +03:00
for _, mech := range sm.Mechanisms {
if state, ok := c.saslHandlers[mech]; ok {
return state, nil
2017-04-01 23:00:36 +03:00
}
}
// no match
return nil, fmt.Errorf("no supported auth mechanism (%v)", sm.Mechanisms) // TODO: send "auth not supported" frame?
2017-04-01 23:00:36 +03:00
}
// saslOutcome processes the SASL outcome frame and return Client.negotiateProto
2017-04-30 02:38:15 +03:00
// on success.
//
// SASL handlers return this stateFunc when the mechanism specific negotiation
// has completed.
// used externally by SASL only.
func (c *Conn) saslOutcome(context.Context) (stateFunc, error) {
// read outcome frame
fr, err := c.readSingleFrame()
2017-04-01 23:00:36 +03:00
if err != nil {
return nil, err
2017-04-01 23:00:36 +03:00
}
debug.Log(1, "RX (saslOutcome %p): %s", c, fr)
so, ok := fr.Body.(*frames.SASLOutcome)
2017-04-24 06:24:12 +03:00
if !ok {
return nil, fmt.Errorf("saslOutcome: unexpected frame type %T", fr.Body)
2017-04-01 23:00:36 +03:00
}
// check if auth succeeded
if so.Code != encoding.CodeSASLOK {
return nil, fmt.Errorf("SASL PLAIN auth failed with code %#00x: %s", so.Code, so.AdditionalData) // implement Stringer for so.Code
2017-04-01 23:00:36 +03:00
}
// return to c.negotiateProto
2017-04-01 23:00:36 +03:00
c.saslComplete = true
return c.negotiateProto, nil
2017-04-01 23:00:36 +03:00
}
2017-04-24 06:24:12 +03:00
// readSingleFrame is used during connection establishment to read a single frame.
2017-04-30 02:38:15 +03:00
//
// After setup, conn.connReader handles incoming frames.
func (c *Conn) readSingleFrame() (frames.Frame, error) {
fr, err := c.readFrame()
if err != nil {
return frames.Frame{}, err
2017-04-24 06:24:12 +03:00
}
return fr, nil
2017-04-24 06:24:12 +03:00
}
// getWriteTimeout returns the timeout as calculated from the context's deadline
// or the default write timeout if the context has no deadline.
// if the context has timed out or was cancelled, an error is returned.
func (c *Conn) getWriteTimeout(ctx context.Context) (time.Duration, error) {
if ctx.Err() != nil {
// if the context is already cancelled we can just bail.
return 0, ctx.Err()
}
if deadline, ok := ctx.Deadline(); ok {
until := time.Until(deadline)
if until <= 0 {
return 0, context.DeadlineExceeded
}
return until, nil
}
return c.writeTimeout, nil
}
type protoHeader struct {
ProtoID protoID
Major uint8
Minor uint8
Revision uint8
}