github.com/zeebo/mon@v0.0.0-20211012163247-13d39bdb54fa/inthist/histogram_serialize.go (about) 1 package inthist 2 3 import ( 4 "encoding/binary" 5 6 "github.com/zeebo/errs" 7 "github.com/zeebo/mon/internal/buffer" 8 ) 9 10 func (h *Histogram) Serialize(dst []byte) []byte { 11 le := binary.LittleEndian 12 13 if cap(dst) < 128 { 14 dst = make([]byte, 128) 15 } 16 17 buf := buffer.Of(dst).Advance(8) 18 aidx := uintptr(0) 19 20 acount := uint8(0) 21 action := uint64(0) 22 23 prev := uint32(0) 24 skip := uint32(0) 25 26 prevBucket := ^uint(0) 27 28 bm := h.bitmap.Clone() 29 for { 30 bucket, ok := bm.Next() 31 if !ok { 32 break 33 } 34 35 if delta := bucket - prevBucket; delta > 1 { 36 skip += histEntries * uint32(delta-1) 37 } 38 prevBucket = bucket 39 40 b := h.buckets[bucket] 41 for entry := range b.entries[:] { 42 count := b.entries[entry] 43 if count == 0 { 44 skip++ 45 continue 46 } 47 48 if skip > 0 { 49 if acount == 64 { 50 le.PutUint64(buf.Index8(aidx)[:], action) 51 aidx = buf.Pos() 52 buf = buf.Advance(8).Grow() 53 acount = 0 54 } 55 56 action = action>>1 | (1 << 63) 57 acount++ 58 59 nbytes, enc := varintStats(skip) 60 le.PutUint64(buf.Front8()[:], enc) 61 buf = buf.Advance(uintptr(nbytes)).Grow() 62 skip = 0 63 } 64 65 { 66 if acount == 64 { 67 le.PutUint64(buf.Index8(aidx)[:], action) 68 aidx = buf.Pos() 69 buf = buf.Advance(8).Grow() 70 acount = 0 71 } 72 73 action = action >> 1 74 acount++ 75 76 delta := int32(count) - int32(prev) 77 val := uint32((delta + delta) ^ (delta >> 31)) 78 79 nbytes, enc := varintStats(val) 80 le.PutUint64(buf.Front8()[:], enc) 81 buf = buf.Advance(uintptr(nbytes)).Grow() 82 } 83 84 prev = count 85 } 86 } 87 88 if delta := histBuckets - prevBucket; delta > 1 { 89 skip += histEntries * uint32(delta-1) 90 } 91 92 if skip > 0 { 93 if acount == 64 { 94 le.PutUint64(buf.Index8(aidx)[:], action) 95 aidx = buf.Pos() 96 buf = buf.Advance(8).Grow() 97 acount = 0 98 } 99 100 action = action>>1 | (1 << 63) 101 acount++ 102 103 nbytes, enc := varintStats(skip) 104 le.PutUint64(buf.Front8()[:], enc) 105 buf = buf.Advance(uintptr(nbytes)).Grow() 106 } 107 108 if acount > 0 { 109 action >>= (64 - acount) % 64 110 le.PutUint64(buf.Index8(aidx)[:], action) 111 } 112 113 return buf.Prefix() 114 } 115 116 func (h *Histogram) Load(data []byte) (err error) { 117 le := binary.LittleEndian 118 buf := buffer.OfLen(data) 119 120 b := (*histBucket)(nil) 121 122 bi := uint32(0) 123 entry := uint32(0) 124 value := uint32(0) 125 126 for buf.Remaining() > 8 { 127 actions := le.Uint64(buf.Front8()[:]) 128 buf = buf.Advance(8) 129 130 for i := 0; i < 64; i++ { 131 var dec uint32 132 133 rem := buf.Remaining() 134 if rem >= 8 { 135 var nbytes uint8 136 nbytes, dec = fastVarintConsume(le.Uint64(buf.Front8()[:])) 137 buf = buf.Advance(uintptr(nbytes)) 138 if buf.Pos() > buf.Cap() { 139 err = errs.New("invalid varint data") 140 goto done 141 } 142 143 } else if rem > 0 { 144 var ok bool 145 dec, buf, ok = safeVarintConsume(buf) 146 if !ok { 147 err = errs.New("invalid varint data") 148 goto done 149 } 150 151 } else { 152 goto check 153 154 } 155 156 if actions&1 != 0 { 157 entry += dec 158 159 } else { 160 delta := (dec >> 1) ^ -(dec & 1) 161 value += delta 162 163 if b == nil { 164 if int(bi) >= histBuckets { 165 err = errs.New("overflow number of buckets") 166 goto done 167 } 168 169 b = new(histBucket) 170 h.buckets[bi] = b 171 h.bitmap.Set(uint(bi)) 172 } 173 174 b.entries[entry%histEntries] = value 175 entry++ 176 } 177 178 if entry >= histEntries { 179 bi += entry / histEntries 180 entry %= histEntries 181 b = nil 182 } 183 184 actions >>= 1 185 } 186 } 187 188 check: 189 if bi != histBuckets || entry != 0 || buf.Remaining() != 0 { 190 err = errs.New("invalid encoded data") 191 } 192 193 done: 194 return err 195 }