From 43b23f4e6fcb34526fbcc2d7fdf96b8ab89e7545 Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Sat, 20 Nov 2021 11:34:42 +0800 Subject: [PATCH] jce: speed up write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit name old time/op new time/op delta JceWriter_WriteMap-8 2.46µs ± 1% 2.37µs ± 1% -3.88% (p=0.000 n=9+9) JceWriter_WriteJceStructRaw-8 1.78µs ± 1% 1.29µs ± 1% -27.38% (p=0.000 n=9+10) name old speed new speed delta JceWriter_WriteMap-8 37.7MB/s ± 1% 39.3MB/s ± 1% +4.04% (p=0.000 n=9+9) JceWriter_WriteJceStructRaw-8 59.0MB/s ± 1% 81.3MB/s ± 1% +37.70% (p=0.000 n=9+10) name old alloc/op new alloc/op delta JceWriter_WriteMap-8 1.30kB ± 0% 1.30kB ± 0% ~ (all equal) JceWriter_WriteJceStructRaw-8 724B ± 0% 640B ± 0% -11.60% (p=0.000 n=10+10) name old allocs/op new allocs/op delta JceWriter_WriteMap-8 30.0 ± 0% 30.0 ± 0% ~ (all equal) JceWriter_WriteJceStructRaw-8 29.0 ± 0% 15.0 ± 0% -48.28% (p=0.000 n=10+10) --- binary/jce/reflectx.go | 16 +++++ binary/jce/writer.go | 136 ++++++++++++++++++++++++++++++++--------- 2 files changed, 124 insertions(+), 28 deletions(-) create mode 100644 binary/jce/reflectx.go diff --git a/binary/jce/reflectx.go b/binary/jce/reflectx.go new file mode 100644 index 00000000..3adf69f4 --- /dev/null +++ b/binary/jce/reflectx.go @@ -0,0 +1,16 @@ +package jce + +import ( + "reflect" + "unsafe" +) + +type value struct { + typ unsafe.Pointer + data unsafe.Pointer + flag uintptr +} + +func pointerOf(v reflect.Value) unsafe.Pointer { + return (*value)(unsafe.Pointer(&v)).data +} diff --git a/binary/jce/writer.go b/binary/jce/writer.go index f78038b9..6159d1be 100644 --- a/binary/jce/writer.go +++ b/binary/jce/writer.go @@ -46,33 +46,64 @@ func (w *JceWriter) WriteBool(b bool, tag int) { } func (w *JceWriter) WriteInt16(n int16, tag int) { - if n >= -128 && n <= 127 { + switch { + case n >= -128 && n <= 127: w.WriteByte(byte(n), tag) - return + default: + w.putInt16(n, tag) } +} + +//go:nosplit +func (w *JceWriter) putInt16(n int16, tag int) { w.writeHead(1, tag) - _ = goBinary.Write(w.buf, goBinary.BigEndian, n) + var buf [2]byte + goBinary.BigEndian.PutUint16(buf[:], uint16(n)) + w.buf.Write(buf[:]) } func (w *JceWriter) WriteInt32(n int32, tag int) *JceWriter { - if n >= -32768 && n <= 32767 { // ? if ((n >= 32768) && (n <= 32767)) - w.WriteInt16(int16(n), tag) - return w + switch { + case n >= -128 && n <= 127: + w.WriteByte(byte(n), tag) + case n >= -32768 && n <= 32767: + w.putInt16(int16(n), tag) + default: + w.putInt32(n, tag) } - w.writeHead(2, tag) - _ = goBinary.Write(w.buf, goBinary.BigEndian, n) return w } +//go:nosplit +func (w *JceWriter) putInt32(n int32, tag int) { + w.writeHead(2, tag) + var buf [4]byte + goBinary.BigEndian.PutUint32(buf[:], uint32(n)) + w.buf.Write(buf[:]) +} + func (w *JceWriter) WriteInt64(n int64, tag int) *JceWriter { - if n >= -2147483648 && n <= 2147483647 { - return w.WriteInt32(int32(n), tag) + switch { + case n >= -128 && n <= 127: + w.WriteByte(byte(n), tag) + case n >= -32768 && n <= 32767: + w.putInt16(int16(n), tag) + case n >= -2147483648 && n <= 2147483647: + w.putInt32(int32(n), tag) + default: + w.putInt64(n, tag) } - w.writeHead(3, tag) - _ = goBinary.Write(w.buf, goBinary.BigEndian, n) return w } +//go:nosplit +func (w *JceWriter) putInt64(n int64, tag int) { + w.writeHead(3, tag) + var buf [8]byte + goBinary.BigEndian.PutUint64(buf[:], uint64(n)) + w.buf.Write(buf[:]) +} + func (w *JceWriter) WriteFloat32(n float32, tag int) { w.writeHead(4, tag) _ = goBinary.Write(w.buf, goBinary.BigEndian, n) @@ -120,17 +151,24 @@ func (w *JceWriter) WriteInt64Slice(l []int64, tag int) { func (w *JceWriter) WriteSlice(i interface{}, tag int) { va := reflect.ValueOf(i) if va.Kind() != reflect.Slice { + panic("JceWriter.WriteSlice: not a slice") + } + w.writeSlice(va, tag) +} + +func (w *JceWriter) writeSlice(slice reflect.Value, tag int) { + if slice.Kind() != reflect.Slice { return } w.writeHead(9, tag) - if va.Len() == 0 { + if slice.Len() == 0 { w.WriteInt32(0, 0) return } - w.WriteInt32(int32(va.Len()), 0) - for i := 0; i < va.Len(); i++ { - v := va.Index(i) - w.WriteObject(v.Interface(), 0) + w.WriteInt32(int32(slice.Len()), 0) + for i := 0; i < slice.Len(); i++ { + v := slice.Index(i) + w.writeObject(v, 0) } } @@ -147,21 +185,28 @@ func (w *JceWriter) WriteJceStructSlice(l []IJceStruct, tag int) { } func (w *JceWriter) WriteMap(m interface{}, tag int) { - if m == nil { + va := reflect.ValueOf(m) + if va.Kind() != reflect.Map { + panic("JceWriter.WriteMap: not a map") + } + w.writeMap(va, tag) +} + +func (w *JceWriter) writeMap(m reflect.Value, tag int) { + if m.IsNil() { w.writeHead(8, tag) w.WriteInt32(0, 0) return } - va := reflect.ValueOf(m) - if va.Kind() != reflect.Map { + if m.Kind() != reflect.Map { return } w.writeHead(8, tag) - w.WriteInt32(int32(va.Len()), 0) - iter := va.MapRange() + w.WriteInt32(int32(m.Len()), 0) + iter := m.MapRange() for iter.Next() { - w.WriteObject(iter.Key().Interface(), 0) - w.WriteObject(iter.Value().Interface(), 1) + w.writeObject(iter.Key(), 0) + w.writeObject(iter.Value(), 1) } } @@ -201,6 +246,43 @@ func (w *JceWriter) WriteObject(i interface{}, tag int) { } } +func (w *JceWriter) writeObject(v reflect.Value, tag int) { + k := v.Kind() + if k == reflect.Map { + w.writeMap(v, tag) + return + } + if k == reflect.Slice { + if v.Type().Elem().Kind() == reflect.Uint8 { + w.WriteBytes(v.Bytes(), tag) + return + } + w.writeSlice(v, tag) + return + } + switch k { + case reflect.Uint8, reflect.Int8: + w.WriteByte(*(*byte)(pointerOf(v)), tag) + case reflect.Uint16, reflect.Int16: + w.WriteInt16(*(*int16)(pointerOf(v)), tag) + case reflect.Uint32, reflect.Int32: + w.WriteInt32(*(*int32)(pointerOf(v)), tag) + case reflect.Uint64, reflect.Int64: + w.WriteInt64(*(*int64)(pointerOf(v)), tag) + case reflect.String: + w.WriteString(v.String(), tag) + default: + switch o := v.Interface().(type) { + case IJceStruct: + w.WriteJceStruct(o, tag) + case float32: + w.WriteFloat32(o, tag) + case float64: + w.WriteFloat64(o, tag) + } + } +} + type decoder struct { index int id int @@ -241,10 +323,8 @@ func (w *JceWriter) WriteJceStructRaw(s interface{}) { decoderCache.Store(t, jceDec) // 存入缓存 } for _, dec := range jceDec { - obj := v.Field(dec.index).Interface() - if obj != nil { - w.WriteObject(obj, dec.id) - } + obj := v.Field(dec.index) + w.writeObject(obj, dec.id) } }