Skip to content

Commit

Permalink
Merge pull request #2880 from onflow/supun/computation-metering
Browse files Browse the repository at this point in the history
Add computation metering to the new stdlib functions
  • Loading branch information
SupunS authored Oct 19, 2023
2 parents e69d6bb + a07342f commit c16b00f
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 4 deletions.
2 changes: 1 addition & 1 deletion runtime/common/computationkind.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const (
ComputationKindCreateArrayValue
ComputationKindTransferArrayValue
ComputationKindDestroyArrayValue
_
ComputationKindIterateArrayValue
_
_
_
Expand Down
7 changes: 4 additions & 3 deletions runtime/common/computationkind_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions runtime/interpreter/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -2996,6 +2996,9 @@ func (v *ArrayValue) Reverse(
return nil
}

// Meter computation for iterating the array.
interpreter.ReportComputation(common.ComputationKindIterateArrayValue, 1)

value := v.Get(interpreter, locationRange, index)
index--

Expand Down Expand Up @@ -3046,6 +3049,9 @@ func (v *ArrayValue) Filter(
var value Value

for {
// Meter computation for iterating the array.
interpreter.ReportComputation(common.ComputationKindIterateArrayValue, 1)

atreeValue, err := iterator.Next()
if err != nil {
panic(errors.NewExternalError(err))
Expand Down Expand Up @@ -3139,6 +3145,9 @@ func (v *ArrayValue) Map(
uint64(v.Count()),
func() Value {

// Meter computation for iterating the array.
interpreter.ReportComputation(common.ComputationKindIterateArrayValue, 1)

atreeValue, err := iterator.Next()
if err != nil {
panic(errors.NewExternalError(err))
Expand Down
4 changes: 4 additions & 0 deletions runtime/interpreter/value_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ func stringFunctionJoin(invocation Invocation) Value {
first := true

stringArray.Iterate(inter, func(element Value) (resume bool) {

// Meter computation for iterating the array.
inter.ReportComputation(common.ComputationKindIterateArrayValue, 1)

// Add separator
if !first {
// Construct directly instead of using NewStringMemoryUsage to avoid
Expand Down
115 changes: 115 additions & 0 deletions runtime/tests/interpreter/metering_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,118 @@ func TestInterpretFunctionInvocationHandler(t *testing.T) {
occurrences,
)
}

func TestInterpretArrayFunctionsComputationMetering(t *testing.T) {

t.Parallel()

t.Run("reverse", func(t *testing.T) {
t.Parallel()

computationMeteredValues := make(map[common.ComputationKind]uint)
inter, err := parseCheckAndInterpretWithOptions(t, `
fun main() {
let x = [1, 2, 3]
let y = x.reverse()
}`,
ParseCheckAndInterpretOptions{
Config: &interpreter.Config{
OnMeterComputation: func(compKind common.ComputationKind, intensity uint) {
computationMeteredValues[compKind] += intensity
},
},
},
)
require.NoError(t, err)

_, err = inter.Invoke("main")
require.NoError(t, err)

assert.Equal(t, uint(3), computationMeteredValues[common.ComputationKindIterateArrayValue])
})

t.Run("map", func(t *testing.T) {
t.Parallel()

computationMeteredValues := make(map[common.ComputationKind]uint)
inter, err := parseCheckAndInterpretWithOptions(t, `
fun main() {
let x = [1, 2, 3, 4]
let trueForEven = fun (_ x: Int): Bool {
return x % 2 == 0
}
let y = x.map(trueForEven)
}`,
ParseCheckAndInterpretOptions{
Config: &interpreter.Config{
OnMeterComputation: func(compKind common.ComputationKind, intensity uint) {
computationMeteredValues[compKind] += intensity
},
},
},
)
require.NoError(t, err)

_, err = inter.Invoke("main")
require.NoError(t, err)

assert.Equal(t, uint(5), computationMeteredValues[common.ComputationKindIterateArrayValue])
})

t.Run("filter", func(t *testing.T) {
t.Parallel()

computationMeteredValues := make(map[common.ComputationKind]uint)
inter, err := parseCheckAndInterpretWithOptions(t, `
fun main() {
let x = [1, 2, 3, 4, 5]
let onlyEven = fun (_ x: Int): Bool {
return x % 2 == 0
}
let y = x.filter(onlyEven)
}`,
ParseCheckAndInterpretOptions{
Config: &interpreter.Config{
OnMeterComputation: func(compKind common.ComputationKind, intensity uint) {
computationMeteredValues[compKind] += intensity
},
},
},
)
require.NoError(t, err)

_, err = inter.Invoke("main")
require.NoError(t, err)

assert.Equal(t, uint(6), computationMeteredValues[common.ComputationKindIterateArrayValue])
})
}

func TestInterpretStdlibComputationMetering(t *testing.T) {

t.Parallel()

t.Run("string join", func(t *testing.T) {
t.Parallel()

computationMeteredValues := make(map[common.ComputationKind]uint)
inter, err := parseCheckAndInterpretWithOptions(t, `
fun main() {
let s = String.join(["one", "two", "three", "four"], separator: ", ")
}`,
ParseCheckAndInterpretOptions{
Config: &interpreter.Config{
OnMeterComputation: func(compKind common.ComputationKind, intensity uint) {
computationMeteredValues[compKind] += intensity
},
},
},
)
require.NoError(t, err)

_, err = inter.Invoke("main")
require.NoError(t, err)

assert.Equal(t, uint(4), computationMeteredValues[common.ComputationKindIterateArrayValue])
})
}

0 comments on commit c16b00f

Please sign in to comment.