github.com/matrixorigin/matrixone@v1.2.0/pkg/util/trace/impl/motrace/statistic/stats_array.go (about) 1 // Copyright 2021 - 2023 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package statistic 16 17 import ( 18 "context" 19 "strconv" 20 "sync/atomic" 21 "time" 22 ) 23 24 type StatsArray [StatsArrayLength]float64 25 26 const ( 27 Decimal128ToFloat64Scale = 5 28 Float64PrecForMemorySize = 3 29 Float64PrecForCU = 4 30 ) 31 32 const StatsArrayVersion = StatsArrayVersionLatest 33 34 const ( 35 StatsArrayVersion0 = iota // raw statistics 36 37 StatsArrayVersion1 = 1 // float64 array 38 StatsArrayVersion2 = 2 // float64 array + plus one elem OutTrafficBytes 39 StatsArrayVersion3 = 3 // ... + 1 elem: ConnType 40 StatsArrayVersion4 = 4 // ... + 2 elem: OutPacketCount, CU 41 42 StatsArrayVersionLatest // same value as last variable StatsArrayVersion# 43 ) 44 45 const ( 46 StatsArrayIndexVersion = iota 47 StatsArrayIndexTimeConsumed 48 StatsArrayIndexMemorySize 49 StatsArrayIndexS3IOInputCount 50 StatsArrayIndexS3IOOutputCount // index: 4 51 StatsArrayIndexOutTrafficBytes // index: 5 52 StatsArrayIndexConnType // index: 6 53 StatsArrayIndexOutPacketCnt // index: 7, version: 4 54 StatsArrayIndexCU // index: 8, version: 4 55 56 StatsArrayLength 57 ) 58 59 const ( 60 StatsArrayLengthV1 = 5 61 StatsArrayLengthV2 = 6 62 StatsArrayLengthV3 = 7 63 StatsArrayLengthV4 = 9 64 ) 65 66 type ConnType float64 67 68 const ( 69 ConnTypeUnknown ConnType = 0 70 ConnTypeInternal ConnType = 1 71 ConnTypeExternal ConnType = 2 72 ) 73 74 func NewStatsArray() *StatsArray { 75 var s StatsArray 76 return s.Init() 77 } 78 79 func NewStatsArrayV1() *StatsArray { 80 return NewStatsArray().WithVersion(StatsArrayVersion1) 81 } 82 83 func NewStatsArrayV2() *StatsArray { 84 return NewStatsArray().WithVersion(StatsArrayVersion2) 85 } 86 87 func NewStatsArrayV3() *StatsArray { 88 return NewStatsArray().WithVersion(StatsArrayVersion3) 89 } 90 91 func NewStatsArrayV4() *StatsArray { 92 return NewStatsArray().WithVersion(StatsArrayVersion4) 93 } 94 95 func (s *StatsArray) Init() *StatsArray { 96 return s.WithVersion(StatsArrayVersion) 97 } 98 99 func (s *StatsArray) InitIfEmpty() *StatsArray { 100 for i := 1; i < StatsArrayLength; i++ { 101 if s[i] != 0 { 102 return s 103 } 104 } 105 return s.WithVersion(StatsArrayVersion) 106 } 107 108 func (s *StatsArray) Reset() *StatsArray { 109 *s = *initStatsArray 110 return s 111 } 112 113 func (s *StatsArray) GetVersion() float64 { return (*s)[StatsArrayIndexVersion] } 114 func (s *StatsArray) GetTimeConsumed() float64 { return (*s)[StatsArrayIndexTimeConsumed] } // unit: ns 115 func (s *StatsArray) GetMemorySize() float64 { return (*s)[StatsArrayIndexMemorySize] } // unit: byte 116 func (s *StatsArray) GetS3IOInputCount() float64 { return (*s)[StatsArrayIndexS3IOInputCount] } // unit: count 117 func (s *StatsArray) GetS3IOOutputCount() float64 { return (*s)[StatsArrayIndexS3IOOutputCount] } // unit: count 118 func (s *StatsArray) GetOutTrafficBytes() float64 { // unit: byte 119 if s.GetVersion() < StatsArrayVersion2 { 120 return 0 121 } 122 return (*s)[StatsArrayIndexOutTrafficBytes] 123 } 124 func (s *StatsArray) GetConnType() float64 { 125 if s.GetVersion() < StatsArrayVersion3 { 126 return 0 127 } 128 return (*s)[StatsArrayIndexConnType] 129 } 130 func (s *StatsArray) GetOutPacketCount() float64 { 131 if s.GetVersion() < StatsArrayVersion4 { 132 return 0 133 } 134 return s[StatsArrayIndexOutPacketCnt] 135 } 136 func (s *StatsArray) GetCU() float64 { 137 if s.GetVersion() < StatsArrayVersion4 { 138 return 0 139 } 140 return s[StatsArrayIndexCU] 141 } 142 143 // WithVersion set the version array in StatsArray, please carefully to use. 144 func (s *StatsArray) WithVersion(v float64) *StatsArray { (*s)[StatsArrayIndexVersion] = v; return s } 145 func (s *StatsArray) WithTimeConsumed(v float64) *StatsArray { 146 (*s)[StatsArrayIndexTimeConsumed] = v 147 return s 148 } 149 func (s *StatsArray) WithMemorySize(v float64) *StatsArray { 150 (*s)[StatsArrayIndexMemorySize] = v 151 return s 152 } 153 func (s *StatsArray) WithS3IOInputCount(v float64) *StatsArray { 154 (*s)[StatsArrayIndexS3IOInputCount] = v 155 return s 156 } 157 func (s *StatsArray) WithS3IOOutputCount(v float64) *StatsArray { 158 (*s)[StatsArrayIndexS3IOOutputCount] = v 159 return s 160 } 161 func (s *StatsArray) WithOutTrafficBytes(v float64) *StatsArray { 162 if s.GetVersion() >= StatsArrayVersion2 { 163 (*s)[StatsArrayIndexOutTrafficBytes] = v 164 } 165 return s 166 } 167 168 func (s *StatsArray) WithConnType(v ConnType) *StatsArray { 169 if s.GetVersion() >= StatsArrayVersion3 { 170 (*s)[StatsArrayIndexConnType] = float64(v) 171 } 172 return s 173 } 174 175 func (s *StatsArray) WithOutPacketCount(v float64) *StatsArray { 176 s[StatsArrayIndexOutPacketCnt] = v 177 return s 178 } 179 180 func (s *StatsArray) WithCU(v float64) *StatsArray { 181 s[StatsArrayIndexCU] = v 182 return s 183 } 184 185 func (s *StatsArray) ToJsonString() []byte { 186 switch s.GetVersion() { 187 case StatsArrayVersion1: 188 return StatsArrayToJsonString((*s)[:StatsArrayLengthV1]) 189 case StatsArrayVersion2: 190 return StatsArrayToJsonString((*s)[:StatsArrayLengthV2]) 191 case StatsArrayVersion3: 192 return StatsArrayToJsonString((*s)[:StatsArrayLengthV3]) 193 case StatsArrayVersion4: 194 return StatsArrayToJsonString((*s)[:StatsArrayLengthV4]) 195 default: 196 return StatsArrayToJsonString((*s)[:]) 197 } 198 } 199 200 // Add do add two stats array together 201 // except for Element ConnType, which idx = StatsArrayIndexConnType, just keep s[StatsArrayIndexConnType] value. 202 func (s *StatsArray) Add(delta *StatsArray) *StatsArray { 203 dstLen := len(*delta) 204 if len(*s) < len(*delta) { 205 dstLen = len(*s) 206 } 207 for idx := 1; idx < dstLen; idx++ { 208 if idx == StatsArrayIndexConnType { 209 continue 210 } 211 (*s)[idx] += (*delta)[idx] 212 } 213 return s 214 } 215 216 // StatsArrayToJsonString return json arr format 217 // example: 218 // [1,0,0,0,0] got `[1,0,0,0,0]` 219 // [1,2,3,4,5] got `[1,2,3.000,4,5]` 220 // [2,1,2,3,4,5] got `[2,3.000,4,5,6.000,7]` 221 func StatsArrayToJsonString(arr []float64) []byte { 222 // len([1,184467440737095516161,18446744073709551616,18446744073709551616,18446744073709551616]") = 88 223 buf := make([]byte, 0, 128) 224 buf = append(buf, '[') 225 for idx, v := range arr { 226 if idx > 0 { 227 buf = append(buf, ',') 228 } 229 if v == 0.0 { 230 buf = append(buf, '0') 231 } else if idx == StatsArrayIndexMemorySize { 232 buf = strconv.AppendFloat(buf, v, 'f', Float64PrecForMemorySize, 64) 233 } else if idx == StatsArrayIndexCU { 234 buf = strconv.AppendFloat(buf, v, 'f', Float64PrecForCU, 64) 235 } else { 236 buf = strconv.AppendFloat(buf, v, 'f', 0, 64) 237 } 238 } 239 buf = append(buf, ']') 240 return buf 241 } 242 243 var initStatsArray = NewStatsArray() 244 245 var DefaultStatsArray = *initStatsArray 246 247 var DefaultStatsArrayJsonString = initStatsArray.ToJsonString() 248 249 type statsInfoKey struct{} 250 251 // statistic info of sql 252 type StatsInfo struct { 253 ParseDuration time.Duration `json:"ParseDuration"` 254 PlanDuration time.Duration `json:"PlanDuration"` 255 CompileDuration time.Duration `json:"CompileDuration"` 256 ExecutionDuration time.Duration `json:"ExecutionDuration"` 257 258 //PipelineTimeConsumption time.Duration 259 //PipelineBlockTimeConsumption time.Duration 260 261 IOAccessTimeConsumption int64 262 //S3ReadBytes uint 263 //S3WriteBytes uint 264 265 LocalFSReadIOMergerTimeConsumption int64 266 LocalFSReadCacheIOMergerTimeConsumption int64 267 268 S3FSPrefetchFileIOMergerTimeConsumption int64 269 S3FSReadIOMergerTimeConsumption int64 270 S3FSReadCacheIOMergerTimeConsumption int64 271 272 ParseStartTime time.Time `json:"ParseStartTime"` 273 PlanStartTime time.Time `json:"PlanStartTime"` 274 CompileStartTime time.Time `json:"CompileStartTime"` 275 ExecutionStartTime time.Time `json:"ExecutionStartTime"` 276 ExecutionEndTime time.Time `json:"ExecutionEndTime"` 277 278 WaitActiveCost time.Duration `json:"WaitActive"` 279 } 280 281 func (stats *StatsInfo) CompileStart() { 282 if stats == nil { 283 return 284 } 285 if !stats.CompileStartTime.IsZero() { 286 return 287 } 288 stats.CompileStartTime = time.Now() 289 } 290 291 func (stats *StatsInfo) CompileEnd() { 292 if stats == nil { 293 return 294 } 295 stats.CompileDuration = time.Since(stats.CompileStartTime) 296 } 297 298 func (stats *StatsInfo) PlanStart() { 299 if stats == nil { 300 return 301 } 302 stats.PlanStartTime = time.Now() 303 } 304 305 func (stats *StatsInfo) PlanEnd() { 306 if stats == nil { 307 return 308 } 309 stats.PlanDuration = time.Since(stats.PlanStartTime) 310 } 311 312 func (stats *StatsInfo) ExecutionStart() { 313 if stats == nil { 314 return 315 } 316 stats.ExecutionStartTime = time.Now() 317 } 318 319 func (stats *StatsInfo) ExecutionEnd() { 320 if stats == nil { 321 return 322 } 323 stats.ExecutionEndTime = time.Now() 324 stats.ExecutionDuration = stats.ExecutionEndTime.Sub(stats.ExecutionStartTime) 325 } 326 327 func (stats *StatsInfo) AddIOAccessTimeConsumption(d time.Duration) { 328 if stats == nil { 329 return 330 } 331 atomic.AddInt64(&stats.IOAccessTimeConsumption, int64(d)) 332 } 333 334 func (stats *StatsInfo) AddLocalFSReadCacheIOMergerTimeConsumption(d time.Duration) { 335 if stats == nil { 336 return 337 } 338 atomic.AddInt64(&stats.LocalFSReadCacheIOMergerTimeConsumption, int64(d)) 339 } 340 func (stats *StatsInfo) AddLocalFSReadIOMergerTimeConsumption(d time.Duration) { 341 if stats == nil { 342 return 343 } 344 atomic.AddInt64(&stats.LocalFSReadIOMergerTimeConsumption, int64(d)) 345 } 346 func (stats *StatsInfo) AddS3FSPrefetchFileIOMergerTimeConsumption(d time.Duration) { 347 if stats == nil { 348 return 349 } 350 atomic.AddInt64(&stats.S3FSPrefetchFileIOMergerTimeConsumption, int64(d)) 351 } 352 func (stats *StatsInfo) AddS3FSReadIOMergerTimeConsumption(d time.Duration) { 353 if stats == nil { 354 return 355 } 356 atomic.AddInt64(&stats.S3FSReadIOMergerTimeConsumption, int64(d)) 357 } 358 func (stats *StatsInfo) AddS3FSReadCacheIOMergerTimeConsumption(d time.Duration) { 359 if stats == nil { 360 return 361 } 362 atomic.AddInt64(&stats.S3FSReadCacheIOMergerTimeConsumption, int64(d)) 363 } 364 365 func (stats *StatsInfo) IOMergerTimeConsumption() int64 { 366 if stats == nil { 367 return 0 368 } 369 return stats.LocalFSReadCacheIOMergerTimeConsumption + 370 stats.LocalFSReadIOMergerTimeConsumption + 371 stats.S3FSPrefetchFileIOMergerTimeConsumption + 372 stats.S3FSReadCacheIOMergerTimeConsumption + 373 stats.S3FSReadIOMergerTimeConsumption 374 } 375 376 func (stats *StatsInfo) SetWaitActiveCost(cost time.Duration) { 377 if stats == nil { 378 return 379 } 380 stats.WaitActiveCost = cost 381 } 382 383 // reset StatsInfo into zero state 384 func (stats *StatsInfo) Reset() { 385 if stats == nil { 386 return 387 } 388 *stats = StatsInfo{} 389 } 390 391 func ContextWithStatsInfo(requestCtx context.Context, stats *StatsInfo) context.Context { 392 return context.WithValue(requestCtx, statsInfoKey{}, stats) 393 } 394 395 func StatsInfoFromContext(requestCtx context.Context) *StatsInfo { 396 if requestCtx == nil { 397 return nil 398 } 399 if stats, ok := requestCtx.Value(statsInfoKey{}).(*StatsInfo); ok { 400 return stats 401 } 402 return nil 403 } 404 405 // EnsureStatsInfoCanBeFound ensure a statement statistic is set in context, if not, copy one from another context, this function is copied from EnsureStatementProfiler 406 func EnsureStatsInfoCanBeFound(ctx context.Context, from context.Context) context.Context { 407 if v := ctx.Value(statsInfoKey{}); v != nil { 408 // already set 409 return ctx 410 } 411 v := from.Value(statsInfoKey{}) 412 if v == nil { 413 // not set in from 414 return ctx 415 } 416 ctx = context.WithValue(ctx, statsInfoKey{}, v) 417 return ctx 418 }