1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
package stats
import (
"math"
"sort"
"sync"
"time"
)
// IOStats represents statistical data for I/O operations
type IOStats struct {
mu sync.RWMutex
// Basic metrics
Count int64
TotalBytes int64
TotalLatency time.Duration
// Latency statistics
MinLatency time.Duration
MaxLatency time.Duration
MeanLatency time.Duration
MedianLatency time.Duration
P95Latency time.Duration
P99Latency time.Duration
// Throughput statistics
MinBytes int64
MaxBytes int64
MeanBytes float64
MedianBytes int64
P95Bytes int64
P99Bytes int64
// Time series data for trend analysis
latencyHistory []time.Duration
bytesHistory []int64
timestamps []time.Time
}
// NewIOStats creates a new IOStats instance
func NewIOStats() *IOStats {
return &IOStats{
MinLatency: time.Duration(math.MaxInt64),
MinBytes: math.MaxInt64,
}
}
// AddOperation adds a new I/O operation to the statistics
func (s *IOStats) AddOperation(bytes int64, latency time.Duration) {
s.mu.Lock()
defer s.mu.Unlock()
now := time.Now()
s.Count++
s.TotalBytes += bytes
s.TotalLatency += latency
// Update latency statistics
if latency < s.MinLatency {
s.MinLatency = latency
}
if latency > s.MaxLatency {
s.MaxLatency = latency
}
// Update bytes statistics
if bytes < s.MinBytes {
s.MinBytes = bytes
}
if bytes > s.MaxBytes {
s.MaxBytes = bytes
}
// Store history
s.latencyHistory = append(s.latencyHistory, latency)
s.bytesHistory = append(s.bytesHistory, bytes)
s.timestamps = append(s.timestamps, now)
// Calculate percentiles if we have enough data
if len(s.latencyHistory) > 0 {
s.calculatePercentiles()
}
}
// calculatePercentiles calculates various statistical measures
func (s *IOStats) calculatePercentiles() {
// Sort the data for percentile calculations
latencies := make([]time.Duration, len(s.latencyHistory))
copy(latencies, s.latencyHistory)
sort.Slice(latencies, func(i, j int) bool {
return latencies[i] < latencies[j]
})
bytes := make([]int64, len(s.bytesHistory))
copy(bytes, s.bytesHistory)
sort.Slice(bytes, func(i, j int) bool {
return bytes[i] < bytes[j]
})
// Calculate mean
var totalLatency time.Duration
var totalBytes int64
for i := range latencies {
totalLatency += latencies[i]
totalBytes += bytes[i]
}
s.MeanLatency = totalLatency / time.Duration(len(latencies))
s.MeanBytes = float64(totalBytes) / float64(len(bytes))
// Calculate median and percentiles
mid := len(latencies) / 2
s.MedianLatency = latencies[mid]
s.MedianBytes = bytes[mid]
p95Index := int(float64(len(latencies)) * 0.95)
p99Index := int(float64(len(latencies)) * 0.99)
if p95Index < len(latencies) {
s.P95Latency = latencies[p95Index]
s.P95Bytes = bytes[p95Index]
}
if p99Index < len(latencies) {
s.P99Latency = latencies[p99Index]
s.P99Bytes = bytes[p99Index]
}
}
// GetStats returns a map of all statistics
func (s *IOStats) GetStats() map[string]interface{} {
s.mu.RLock()
defer s.mu.RUnlock()
return map[string]interface{}{
"count": s.Count,
"total_bytes": s.TotalBytes,
"total_latency": s.TotalLatency,
"latency": map[string]interface{}{
"min": s.MinLatency,
"max": s.MaxLatency,
"mean": s.MeanLatency,
"median": s.MedianLatency,
"p95": s.P95Latency,
"p99": s.P99Latency,
},
"bytes": map[string]interface{}{
"min": s.MinBytes,
"max": s.MaxBytes,
"mean": s.MeanBytes,
"median": s.MedianBytes,
"p95": s.P95Bytes,
"p99": s.P99Bytes,
},
}
}
// GetTimeSeriesData returns the historical data for trend analysis
func (s *IOStats) GetTimeSeriesData() ([]time.Time, []time.Duration, []int64) {
s.mu.RLock()
defer s.mu.RUnlock()
timestamps := make([]time.Time, len(s.timestamps))
latencies := make([]time.Duration, len(s.latencyHistory))
bytes := make([]int64, len(s.bytesHistory))
copy(timestamps, s.timestamps)
copy(latencies, s.latencyHistory)
copy(bytes, s.bytesHistory)
return timestamps, latencies, bytes
}
|