-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmonitor.go
More file actions
166 lines (139 loc) · 3.9 KB
/
monitor.go
File metadata and controls
166 lines (139 loc) · 3.9 KB
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
package main
import (
"runtime"
"sync"
"time"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/mem"
)
// SystemMetrics holds the current system resource usage
type SystemMetrics struct {
CPUPercent float64
MemoryUsedMB float64
MemoryPercent float64
IOReadBytes uint64
IOWriteBytes uint64
IOReadOps uint64
IOWriteOps uint64
Timestamp time.Time
}
// ResourceMonitor monitors system resources
type ResourceMonitor struct {
mu sync.RWMutex
currentMetrics SystemMetrics
previousMetrics SystemMetrics
updateInterval time.Duration
stopCh chan struct{}
stopped bool
}
// NewResourceMonitor creates a new resource monitor
func NewResourceMonitor(updateInterval time.Duration) *ResourceMonitor {
return &ResourceMonitor{
updateInterval: updateInterval,
stopCh: make(chan struct{}),
}
}
// Start begins monitoring system resources
func (rm *ResourceMonitor) Start() {
go rm.monitorLoop()
}
// Stop stops the resource monitor
func (rm *ResourceMonitor) Stop() {
rm.mu.Lock()
if !rm.stopped {
close(rm.stopCh)
rm.stopped = true
}
rm.mu.Unlock()
}
func (rm *ResourceMonitor) monitorLoop() {
ticker := time.NewTicker(rm.updateInterval)
defer ticker.Stop()
// Initial update
rm.updateMetrics()
for {
select {
case <-ticker.C:
rm.updateMetrics()
case <-rm.stopCh:
return
}
}
}
func (rm *ResourceMonitor) updateMetrics() {
rm.mu.Lock()
defer rm.mu.Unlock()
rm.previousMetrics = rm.currentMetrics
// Get CPU usage
cpuPercent, err := cpu.Percent(0, false)
if err == nil && len(cpuPercent) > 0 {
rm.currentMetrics.CPUPercent = cpuPercent[0]
}
// Get memory usage
memInfo, err := mem.VirtualMemory()
if err == nil {
rm.currentMetrics.MemoryUsedMB = float64(memInfo.Used) / 1024 / 1024
rm.currentMetrics.MemoryPercent = memInfo.UsedPercent
}
// Get disk IO stats
ioCounters, err := disk.IOCounters()
if err == nil {
var totalReadBytes, totalWriteBytes, totalReadOps, totalWriteOps uint64
for _, counter := range ioCounters {
totalReadBytes += counter.ReadBytes
totalWriteBytes += counter.WriteBytes
totalReadOps += counter.ReadCount
totalWriteOps += counter.WriteCount
}
rm.currentMetrics.IOReadBytes = totalReadBytes
rm.currentMetrics.IOWriteBytes = totalWriteBytes
rm.currentMetrics.IOReadOps = totalReadOps
rm.currentMetrics.IOWriteOps = totalWriteOps
}
rm.currentMetrics.Timestamp = time.Now()
}
// GetMetrics returns the current system metrics
func (rm *ResourceMonitor) GetMetrics() SystemMetrics {
rm.mu.RLock()
defer rm.mu.RUnlock()
return rm.currentMetrics
}
// CanRunJob checks if the system has enough resources to run a job
func (rm *ResourceMonitor) CanRunJob(constraints ResourceConstraints) bool {
rm.mu.RLock()
defer rm.mu.RUnlock()
metrics := rm.currentMetrics
// Wait for metrics to be initialized
if metrics.Timestamp.IsZero() {
return false
}
// Check CPU constraint
if constraints.MaxCPUPercent > 0 && metrics.CPUPercent >= constraints.MaxCPUPercent {
return false
}
// Check memory constraint
if constraints.MaxMemoryMB > 0 && metrics.MemoryUsedMB >= constraints.MaxMemoryMB {
return false
}
// Check IO constraint (approximate ops per second)
if constraints.MaxIOOpsPerSec > 0 {
if rm.previousMetrics.Timestamp.IsZero() {
return true // Not enough data yet
}
timeDiff := metrics.Timestamp.Sub(rm.previousMetrics.Timestamp).Seconds()
if timeDiff > 0.1 { // Require at least 100ms of data
readOpsDiff := metrics.IOReadOps - rm.previousMetrics.IOReadOps
writeOpsDiff := metrics.IOWriteOps - rm.previousMetrics.IOWriteOps
opsPerSec := int(float64(readOpsDiff+writeOpsDiff) / timeDiff)
if opsPerSec >= constraints.MaxIOOpsPerSec {
return false
}
}
}
return true
}
// GetGoRoutineCount returns the current number of goroutines
func GetGoRoutineCount() int {
return runtime.NumGoroutine()
}