Skip to content

Commit f118dce

Browse files
authored
Fix cost estimates to propagate result sizes. (#821)
1 parent 647ee3b commit f118dce

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

‎checker/cost.go‎

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -535,14 +535,34 @@ func (c *coster) functionCost(function, overloadID string, target *AstNode, args
535535

536536
if est := c.estimator.EstimateCallCost(function, overloadID, target, args); est != nil {
537537
callEst := *est
538-
return CallEstimate{CostEstimate: callEst.Add(argCostSum())}
538+
return CallEstimate{CostEstimate: callEst.Add(argCostSum()), ResultSize: est.ResultSize}
539539
}
540540
switch overloadID {
541541
// O(n) functions
542-
case overloads.StartsWithString, overloads.EndsWithString, overloads.StringToBytes, overloads.BytesToString, overloads.ExtQuoteString, overloads.ExtFormatString:
543-
if overloadID == overloads.ExtFormatString {
542+
case overloads.ExtFormatString:
543+
if target != nil {
544+
// ResultSize not calculated because we can't bound the max size.
544545
return CallEstimate{CostEstimate: c.sizeEstimate(*target).MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum())}
545546
}
547+
case overloads.StringToBytes:
548+
if len(args) == 1 {
549+
sz := c.sizeEstimate(args[0])
550+
// ResultSize max is when each char converts to 4 bytes.
551+
return CallEstimate{CostEstimate: sz.MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum()), ResultSize: &SizeEstimate{Min: sz.Min, Max: sz.Max * 4}}
552+
}
553+
case overloads.BytesToString:
554+
if len(args) == 1 {
555+
sz := c.sizeEstimate(args[0])
556+
// ResultSize min is when 4 bytes convert to 1 char.
557+
return CallEstimate{CostEstimate: sz.MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum()), ResultSize: &SizeEstimate{Min: sz.Min / 4, Max: sz.Max}}
558+
}
559+
case overloads.ExtQuoteString:
560+
if len(args) == 1 {
561+
sz := c.sizeEstimate(args[0])
562+
// ResultSize max is when each char is escaped. 2 quote chars always added.
563+
return CallEstimate{CostEstimate: sz.MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum()), ResultSize: &SizeEstimate{Min: sz.Min + 2, Max: sz.Max*2 + 2}}
564+
}
565+
case overloads.StartsWithString, overloads.EndsWithString:
546566
if len(args) == 1 {
547567
return CallEstimate{CostEstimate: c.sizeEstimate(args[0]).MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum())}
548568
}

‎checker/cost_test.go‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/google/cel-go/common/stdlib"
2626
"github.com/google/cel-go/common/types"
2727
"github.com/google/cel-go/parser"
28-
2928
proto3pb "github.com/google/cel-go/test/proto3pb"
3029
)
3130

@@ -261,13 +260,29 @@ func TestCost(t *testing.T) {
261260
expr: `string(input)`,
262261
wanted: CostEstimate{Min: 1, Max: 51},
263262
},
263+
{
264+
name: "bytes to string conversion equality",
265+
vars: []*decls.VariableDecl{decls.NewVariable("input", types.BytesType)},
266+
hints: map[string]int64{"input": 500},
267+
// equality check ensures that the resultSize calculation is included in cost
268+
expr: `string(input) == string(input)`,
269+
wanted: CostEstimate{Min: 3, Max: 152},
270+
},
264271
{
265272
name: "string to bytes conversion",
266273
vars: []*decls.VariableDecl{decls.NewVariable("input", types.StringType)},
267274
hints: map[string]int64{"input": 500},
268275
expr: `bytes(input)`,
269276
wanted: CostEstimate{Min: 1, Max: 51},
270277
},
278+
{
279+
name: "string to bytes conversion equality",
280+
vars: []*decls.VariableDecl{decls.NewVariable("input", types.StringType)},
281+
hints: map[string]int64{"input": 500},
282+
// equality check ensures that the resultSize calculation is included in cost
283+
expr: `bytes(input) == bytes(input)`,
284+
wanted: CostEstimate{Min: 3, Max: 302},
285+
},
271286
{
272287
name: "int to string conversion",
273288
expr: `string(1)`,

0 commit comments

Comments
 (0)