github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/system/bus/statistic.go (about) 1 // This file is part of the Smart Home 2 // Program complex distribution https://github.com/e154/smart-home 3 // Copyright (C) 2024, Filippov Alex 4 // 5 // This library is free software: you can redistribute it and/or 6 // modify it under the terms of the GNU Lesser General Public 7 // License as published by the Free Software Foundation; either 8 // version 3 of the License, or (at your option) any later version. 9 // 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 // Library General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with this library. If not, see 17 // <https://www.gnu.org/licenses/>. 18 19 package bus 20 21 import ( 22 "go.uber.org/atomic" 23 "strings" 24 "time" 25 ) 26 27 type Statistic struct { 28 min *atomic.Duration 29 max *atomic.Duration 30 avg *atomic.Duration 31 rps *RPSCounter 32 } 33 34 func NewStatistic() *Statistic { 35 return &Statistic{ 36 min: atomic.NewDuration(0), 37 max: atomic.NewDuration(0), 38 avg: atomic.NewDuration(0), 39 rps: startRPSCounter(), 40 } 41 } 42 43 func (s *Statistic) setTime(t time.Duration) { 44 if s.min.Load() == 0 { 45 s.min.Store(t) 46 } 47 if s.min.Load() > t { 48 s.min.Store(t) 49 } 50 if s.max.Load() == 0 { 51 s.max.Store(t) 52 } 53 if t > s.max.Load() { 54 s.max.Store(t) 55 } 56 s.avg.Store((s.max.Load() + s.min.Load()) / 2) 57 } 58 59 // StatItem ... 60 type StatItem struct { 61 Topic string 62 Subscribers int 63 Min time.Duration 64 Max time.Duration 65 Avg time.Duration 66 Rps float64 67 } 68 69 // Stats ... 70 type Stats []*StatItem 71 72 func (s Stats) Len() int { return len(s) } 73 func (s Stats) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 74 func (s Stats) Less(i, j int) bool { return strings.Compare(s[i].Topic, s[j].Topic) == -1 } 75 76 type RPSCounter struct { 77 count *atomic.Int64 78 value *atomic.Float64 79 isRunning *atomic.Bool 80 } 81 82 func startRPSCounter() *RPSCounter { 83 counter := &RPSCounter{ 84 count: atomic.NewInt64(0), 85 value: atomic.NewFloat64(0), 86 isRunning: atomic.NewBool(true), 87 } 88 89 go func() { 90 ticker := time.NewTicker(time.Second * 5) 91 defer ticker.Stop() 92 for counter.isRunning.Load() { 93 select { 94 case <-ticker.C: 95 counter.value.Store(float64(counter.count.Load()) / 5) 96 counter.count.Store(0) 97 } 98 } 99 }() 100 101 return counter 102 } 103 104 func (c *RPSCounter) Inc() { 105 c.count.Inc() 106 } 107 108 func (c *RPSCounter) Value() float64 { 109 return c.value.Load() 110 } 111 112 func (c *RPSCounter) Stop() { 113 c.isRunning.Store(false) 114 }