-
Notifications
You must be signed in to change notification settings - Fork 178
/
computation_meter.go
115 lines (94 loc) · 3.68 KB
/
computation_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
package meter
import (
"math"
"github.com/onflow/cadence/runtime/common"
"github.com/onflow/flow-go/fvm/errors"
)
type MeteredComputationIntensities map[common.ComputationKind]uint
var (
// DefaultComputationWeights is the default weights for computation intensities
// these weighs make the computation metering the same as it was before dynamic execution fees
// these weighs make the computation metering the same as it was before dynamic execution fees
DefaultComputationWeights = ExecutionEffortWeights{
common.ComputationKindStatement: 1 << MeterExecutionInternalPrecisionBytes,
common.ComputationKindLoop: 1 << MeterExecutionInternalPrecisionBytes,
common.ComputationKindFunctionInvocation: 1 << MeterExecutionInternalPrecisionBytes,
}
)
// MeterExecutionInternalPrecisionBytes are the amount of bytes that are used internally by the
// WeigthedMeter to allow for metering computation smaller than one unit of computation.
// This allows for more fine weights. A weight of 1 unit of computation is equal to 1<<16.
// The minimum possible weight is 1/65536.
const MeterExecutionInternalPrecisionBytes = 16
type ExecutionEffortWeights map[common.ComputationKind]uint64
type ComputationMeterParameters struct {
computationLimit uint64
computationWeights ExecutionEffortWeights
}
func DefaultComputationMeterParameters() ComputationMeterParameters {
return ComputationMeterParameters{
computationLimit: math.MaxUint64,
computationWeights: DefaultComputationWeights,
}
}
func (params MeterParameters) WithComputationLimit(limit uint) MeterParameters {
newParams := params
newParams.computationLimit = uint64(limit) << MeterExecutionInternalPrecisionBytes
return newParams
}
func (params MeterParameters) WithComputationWeights(
weights ExecutionEffortWeights,
) MeterParameters {
newParams := params
newParams.computationWeights = weights
return newParams
}
func (params ComputationMeterParameters) ComputationWeights() ExecutionEffortWeights {
return params.computationWeights
}
// TotalComputationLimit returns the total computation limit
func (params ComputationMeterParameters) TotalComputationLimit() uint {
return uint(params.computationLimit >> MeterExecutionInternalPrecisionBytes)
}
type ComputationMeter struct {
params ComputationMeterParameters
computationUsed uint64
computationIntensities MeteredComputationIntensities
}
func NewComputationMeter(params ComputationMeterParameters) ComputationMeter {
return ComputationMeter{
params: params,
computationIntensities: make(MeteredComputationIntensities),
}
}
// MeterComputation captures computation usage and returns an error if it goes beyond the limit
func (m *ComputationMeter) MeterComputation(
kind common.ComputationKind,
intensity uint,
) error {
m.computationIntensities[kind] += intensity
w, ok := m.params.computationWeights[kind]
if !ok {
return nil
}
m.computationUsed += w * uint64(intensity)
if m.computationUsed > m.params.computationLimit {
return errors.NewComputationLimitExceededError(
uint64(m.params.TotalComputationLimit()))
}
return nil
}
// ComputationIntensities returns all the measured computational intensities
func (m *ComputationMeter) ComputationIntensities() MeteredComputationIntensities {
return m.computationIntensities
}
// TotalComputationUsed returns the total computation used
func (m *ComputationMeter) TotalComputationUsed() uint64 {
return m.computationUsed >> MeterExecutionInternalPrecisionBytes
}
func (m *ComputationMeter) Merge(child ComputationMeter) {
m.computationUsed = m.computationUsed + child.computationUsed
for key, intensity := range child.computationIntensities {
m.computationIntensities[key] += intensity
}
}