-
Notifications
You must be signed in to change notification settings - Fork 175
/
meter.go
123 lines (105 loc) · 3.92 KB
/
meter.go
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
package basic
import (
"github.com/onflow/cadence/runtime/common"
"github.com/onflow/flow-go/fvm/errors"
interfaceMeter "github.com/onflow/flow-go/fvm/meter"
)
var _ interfaceMeter.Meter = &Meter{}
// Meter collects memory and computation usage and enforces limits
// for any each memory/computation usage call it sums intensity to the total
// memory/computation usage metrics and returns error if limits are not met.
type Meter struct {
computationUsed uint
computationLimit uint
memoryUsed uint
memoryLimit uint
computationIntensities interfaceMeter.MeteredComputationIntensities
memoryIntensities interfaceMeter.MeteredMemoryIntensities
}
// NewMeter constructs a new Meter
func NewMeter(computationLimit, memoryLimit uint) *Meter {
return &Meter{
computationLimit: computationLimit,
memoryLimit: memoryLimit,
computationIntensities: make(interfaceMeter.MeteredComputationIntensities),
memoryIntensities: make(interfaceMeter.MeteredMemoryIntensities),
}
}
// NewChild construct a new Meter instance with the same limits as parent
func (m *Meter) NewChild() interfaceMeter.Meter {
return &Meter{
computationLimit: m.computationLimit,
memoryLimit: m.memoryLimit,
computationIntensities: make(interfaceMeter.MeteredComputationIntensities),
memoryIntensities: make(interfaceMeter.MeteredMemoryIntensities),
}
}
// MergeMeter merges the input meter into the current meter and checks for the limits
func (m *Meter) MergeMeter(child interfaceMeter.Meter, enforceLimits bool) error {
m.computationUsed = m.computationUsed + child.TotalComputationUsed()
if enforceLimits && m.computationUsed > m.computationLimit {
return errors.NewComputationLimitExceededError(uint64(m.computationLimit))
}
for key, intensity := range child.ComputationIntensities() {
m.computationIntensities[key] += intensity
}
m.memoryUsed = m.memoryUsed + child.TotalMemoryUsed()
if enforceLimits && m.memoryUsed > m.memoryLimit {
return errors.NewMemoryLimitExceededError(uint64(m.memoryLimit))
}
for key, intensity := range child.MemoryIntensities() {
m.memoryIntensities[key] += intensity
}
return nil
}
// MeterComputation captures computation usage and returns an error if it goes beyond the limit
func (m *Meter) MeterComputation(kind common.ComputationKind, intensity uint) error {
m.computationIntensities[kind] += intensity
var meterable bool
switch kind {
case common.ComputationKindStatement,
common.ComputationKindLoop,
common.ComputationKindFunctionInvocation:
meterable = true
}
if meterable {
m.computationUsed += intensity
if m.computationUsed > m.computationLimit {
return errors.NewComputationLimitExceededError(uint64(m.computationLimit))
}
}
return nil
}
// ComputationIntensities returns all the measured computational intensities
func (m *Meter) ComputationIntensities() interfaceMeter.MeteredComputationIntensities {
return m.computationIntensities
}
// TotalComputationUsed returns the total computation used
func (m *Meter) TotalComputationUsed() uint {
return m.computationUsed
}
// TotalComputationLimit returns the total computation limit
func (m *Meter) TotalComputationLimit() uint {
return m.computationLimit
}
// MeterMemory captures memory usage and returns an error if it goes beyond the limit
func (m *Meter) MeterMemory(kind common.MemoryKind, intensity uint) error {
m.memoryIntensities[kind] += intensity
m.memoryUsed += intensity
if m.memoryUsed > m.memoryLimit {
return errors.NewMemoryLimitExceededError(uint64(m.memoryLimit))
}
return nil
}
// MemoryIntensities returns all the measured memory intensities
func (m *Meter) MemoryIntensities() interfaceMeter.MeteredMemoryIntensities {
return m.memoryIntensities
}
// TotalMemoryUsed returns the total memory used
func (m *Meter) TotalMemoryUsed() uint {
return m.memoryUsed
}
// TotalMemoryLimit returns the total memory limit
func (m *Meter) TotalMemoryLimit() uint {
return m.memoryLimit
}