github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/cmd/util/ledger/reporters/atree_reporter.go (about) 1 package reporters 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 goRuntime "runtime" 8 "sync" 9 10 "github.com/onflow/atree" 11 "github.com/rs/zerolog" 12 "github.com/schollz/progressbar/v3" 13 14 "github.com/onflow/flow-go/ledger" 15 "github.com/onflow/flow-go/model/flow" 16 ) 17 18 // AtreeReporter iterates payloads and generates payload and atree stats. 19 type AtreeReporter struct { 20 Log zerolog.Logger 21 RWF ReportWriterFactory 22 } 23 24 var _ ledger.Reporter = &AtreeReporter{} 25 26 func (r *AtreeReporter) Name() string { 27 return "Atree Reporter" 28 } 29 30 func (r *AtreeReporter) Report(payloads []ledger.Payload, commit ledger.State) error { 31 rwa := r.RWF.ReportWriter("atree_report") 32 defer rwa.Close() 33 34 progress := progressbar.Default(int64(len(payloads)), "Processing:") 35 36 workerCount := goRuntime.NumCPU() / 2 37 if workerCount == 0 { 38 workerCount = 1 39 } 40 41 jobs := make(chan *ledger.Payload, workerCount) 42 43 results := make(chan payloadStats, workerCount) 44 defer close(results) 45 46 // create multiple workers to process payloads concurrently 47 wg := &sync.WaitGroup{} 48 wg.Add(workerCount) 49 50 for i := 0; i < workerCount; i++ { 51 go func() { 52 defer wg.Done() 53 54 var stats payloadStats 55 for p := range jobs { 56 err := stats.process(p) 57 if err != nil { 58 k, keyErr := p.Key() 59 if keyErr != nil { 60 r.Log.Err(keyErr).Msg("failed to get payload key") 61 } else { 62 r.Log.Err(err).Msgf("failed to process payload %s", k.String()) 63 } 64 } 65 } 66 results <- stats 67 }() 68 } 69 70 // produce jobs for workers to process 71 for i := 0; i < len(payloads); i++ { 72 jobs <- &payloads[i] 73 74 err := progress.Add(1) 75 if err != nil { 76 panic(fmt.Errorf("progress.Add(1): %w", err)) 77 } 78 } 79 close(jobs) 80 81 // wait until all jobs are done 82 wg.Wait() 83 84 err := progress.Finish() 85 if err != nil { 86 panic(fmt.Errorf("progress.Finish(): %w", err)) 87 } 88 89 // aggregate all payload stats 90 var stats payloadStats 91 for i := 0; i < workerCount; i++ { 92 r := <-results 93 stats.add(&r) 94 } 95 96 rwa.Write(stats) 97 98 return nil 99 } 100 101 type payloadType uint 102 103 const ( 104 unknownPayloadType payloadType = iota 105 fvmPayloadType 106 storagePayloadType 107 slabPayloadType 108 ) 109 110 func getPayloadType(p *ledger.Payload) (payloadType, error) { 111 k, err := p.Key() 112 if err != nil { 113 return unknownPayloadType, err 114 } 115 if len(k.KeyParts) < 2 { 116 return unknownPayloadType, nil 117 } 118 119 id := flow.NewRegisterID( 120 flow.BytesToAddress(k.KeyParts[0].Value), 121 string(k.KeyParts[1].Value)) 122 if id.IsInternalState() { 123 return fvmPayloadType, nil 124 } 125 126 if bytes.HasPrefix(k.KeyParts[1].Value, []byte(atree.LedgerBaseStorageSlabPrefix)) { 127 return slabPayloadType, nil 128 } 129 return storagePayloadType, nil 130 } 131 132 type slabPayloadStats struct { 133 SlabArrayMetaCount uint 134 SlabArrayDataCount uint 135 SlabMapMetaCount uint 136 SlabMapDataCount uint 137 SlabMapExternalCollisionCount uint 138 SlabStorableCount uint 139 SlabMapCollisionGroupCount uint 140 141 SlabMapCollisionCounts []uint 142 } 143 144 type payloadStats struct { 145 FVMPayloadCount uint 146 StoragePayloadCount uint 147 SlabPayloadCount uint 148 slabPayloadStats 149 } 150 151 func (s *payloadStats) add(s1 *payloadStats) { 152 s.FVMPayloadCount += s1.FVMPayloadCount 153 s.StoragePayloadCount += s1.StoragePayloadCount 154 s.SlabPayloadCount += s1.SlabPayloadCount 155 s.SlabArrayMetaCount += s1.SlabArrayMetaCount 156 s.SlabArrayDataCount += s1.SlabArrayDataCount 157 s.SlabMapMetaCount += s1.SlabMapMetaCount 158 s.SlabMapDataCount += s1.SlabMapDataCount 159 s.SlabMapExternalCollisionCount += s1.SlabMapExternalCollisionCount 160 s.SlabStorableCount += s1.SlabStorableCount 161 s.SlabMapCollisionGroupCount += s1.SlabMapCollisionGroupCount 162 163 if len(s1.SlabMapCollisionCounts) > 0 { 164 s.SlabMapCollisionCounts = append(s.SlabMapCollisionCounts, s1.SlabMapCollisionCounts...) 165 } 166 } 167 168 func (s *payloadStats) process(p *ledger.Payload) error { 169 pt, err := getPayloadType(p) 170 if err != nil { 171 return err 172 } 173 switch pt { 174 case unknownPayloadType: 175 return fmt.Errorf("unknown payload: %s", p.String()) 176 case fvmPayloadType: 177 s.FVMPayloadCount++ 178 case storagePayloadType: 179 s.StoragePayloadCount++ 180 case slabPayloadType: 181 s.SlabPayloadCount++ 182 } 183 184 if pt != slabPayloadType { 185 return nil 186 } 187 188 if len(p.Value()) < versionAndFlagSize { 189 return errors.New("data is too short") 190 } 191 192 flag := p.Value()[flagIndex] 193 194 switch dataType := getSlabType(flag); dataType { 195 case slabArray: 196 switch arrayDataType := getSlabArrayType(flag); arrayDataType { 197 case slabArrayData: 198 s.SlabArrayDataCount++ 199 200 case slabArrayMeta: 201 s.SlabArrayMetaCount++ 202 203 default: 204 return fmt.Errorf("slab array has invalid flag 0x%x", flag) 205 } 206 207 case slabMap: 208 switch mapDataType := getSlabMapType(flag); mapDataType { 209 case slabMapData: 210 _, collisionGroupCount, err := getCollisionGroupCountFromSlabMapData(p.Value()) 211 if err != nil { 212 return err 213 } 214 if collisionGroupCount > 0 { 215 _, inlineCollisionCount, err := getInlineCollisionCountsFromSlabMapData(p.Value()) 216 if err != nil { 217 return err 218 } 219 if len(inlineCollisionCount) > 0 { 220 s.SlabMapCollisionCounts = append(s.SlabMapCollisionCounts, inlineCollisionCount...) 221 } 222 } 223 s.SlabMapCollisionGroupCount += collisionGroupCount 224 s.SlabMapDataCount++ 225 226 case slabMapCollisionGroup: 227 elements, err := parseSlabMapData(p.Value()) 228 if err != nil { 229 return err 230 } 231 _, rawElements, err := parseRawElements(elements, decMode) 232 if err != nil { 233 return err 234 } 235 if len(rawElements) > 0 { 236 s.SlabMapCollisionCounts = append(s.SlabMapCollisionCounts, uint(len(rawElements))) 237 } 238 s.SlabMapExternalCollisionCount++ 239 240 case slabMapMeta: 241 s.SlabMapMetaCount++ 242 243 default: 244 return fmt.Errorf("slab map has invalid flag 0x%x", flag) 245 } 246 247 case slabStorable: 248 s.SlabStorableCount++ 249 250 default: 251 return fmt.Errorf("slab data has invalid flag 0x%x", flag) 252 } 253 254 return nil 255 }