gopcua / opcua

Native Go OPC-UA library
MIT License
829 stars 253 forks source link

Feat: enhance message encode #726

Open ethan256 opened 2 months ago

ethan256 commented 2 months ago

Using stream reduces memory allocation during message encoding and improves performance. benchstat:

goos: linux
goarch: amd64
pkg: github.com/gopcua/opcua/uasc
cpu: AMD Ryzen 7 5800H with Radeon Graphics         
                │   old.txt    │               new.txt               │
                │    sec/op    │   sec/op     vs base                │
EncodeMessage-6   12.710µ ± 2%   6.748µ ± 2%  -46.91% (p=0.000 n=10)

                │   old.txt    │               new.txt               │
                │     B/op     │     B/op      vs base               │
EncodeMessage-6   4.375Ki ± 0%   4.492Ki ± 0%  +2.68% (p=0.000 n=10)

                │   old.txt   │              new.txt               │
                │  allocs/op  │ allocs/op   vs base                │
EncodeMessage-6   169.00 ± 0%   87.00 ± 0%  -48.52% (p=0.000 n=10)
ethan256 commented 2 months ago

@magiconair Can you help review it?

danomagnum commented 1 month ago

Is there a technical reason to not go all the way and replace the buffer allocations in all the write functions also?

func (b *Stream) WriteUint16(n uint16) {
    d := make([]byte, 2)
    binary.LittleEndian.PutUint16(d, n)
    b.Write(d)
}

could become

func (b *Stream) WriteUint16(n uint16) {
    b.buf = binary.LittleEndian.AppendUint16(b.buf, n)
}

Just a thought.

ethan256 commented 1 month ago

Is there a technical reason to not go all the way and replace the buffer allocations in all the write functions also?

func (b *Stream) WriteUint16(n uint16) {
  d := make([]byte, 2)
  binary.LittleEndian.PutUint16(d, n)
  b.Write(d)
}

could become

func (b *Stream) WriteUint16(n uint16) {
  b.buf = binary.LittleEndian.AppendUint16(b.buf, n)
}

Just a thought.

I think it's a good idea, I'll give it a try

ethan256 commented 1 month ago

commit 855932c benchstats results as follow:

goos: linux
goarch: amd64
pkg: github.com/gopcua/opcua/uasc
cpu: AMD Ryzen 7 5800H with Radeon Graphics         
                │   old.txt    │              codec.txt              │
                │    sec/op    │   sec/op     vs base                │
EncodeMessage-6   12.710µ ± 2%   3.613µ ± 1%  -71.57% (p=0.000 n=10)

                │   old.txt    │              codec.txt               │
                │     B/op     │     B/op      vs base                │
EncodeMessage-6   4.375Ki ± 0%   1.539Ki ± 0%  -64.82% (p=0.000 n=10)

                │   old.txt   │             codec.txt              │
                │  allocs/op  │ allocs/op   vs base                │
EncodeMessage-6   169.00 ± 0%   39.00 ± 0%  -76.92% (p=0.000 n=10)