mirror of
https://github.com/google/go-jsonnet.git
synced 2025-09-28 08:51:01 +02:00
feat: improve stdlib base64 performance by 98.58%+
Implements std.base64 in native Go, improving performance benchmark old ns/op new ns/op delta Benchmark_Builtin_base64-16 10805730974 23158636 -99.79% Benchmark_Builtin_base64_bytearray-16 8682808704 123360964 -98.58%
This commit is contained in:
parent
492503d13b
commit
e8bd3f4ff8
5
builtin-benchmarks/base64.jsonnet
Normal file
5
builtin-benchmarks/base64.jsonnet
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
foo: [
|
||||||
|
std.base64("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sed turpis tincidunt id aliquet risus. Eget mauris pharetra et ultrices neque ornare aenean euismod. Diam quis enim lobortis scelerisque fermentum. Varius duis at consectetur lorem donec massa sapien. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Lectus urna duis convallis convallis tellus. Nibh ipsum consequat nisl vel pretium lectus quam id leo. Feugiat in ante metus dictum at tempor commodo. Velit dignissim sodales ut eu sem integer. Dictum sit amet justo donec. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sed turpis tincidunt id aliquet risus. Eget mauris pharetra et ultrices neque ornare aenean euismod. Diam quis enim lobortis scelerisque fermentum. Varius duis at consectetur lorem donec massa sapien. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Lectus urna duis convallis convallis tellus. Nibh ipsum consequat nisl vel pretium lectus quam id leo. Feugiat in ante metus dictum at tempor commodo. Velit dignissim sodales ut eu sem integer. Dictum sit amet justo donec. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sed turpis tincidunt id aliquet risus. Eget mauris pharetra et ultrices neque ornare aenean euismod. Diam quis enim lobortis scelerisque fermentum. Varius duis at consectetur lorem donec massa sapien. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Lectus urna duis convallis convallis tellus. Nibh ipsum consequat nisl vel pretium lectus quam id leo. Feugiat in ante metus dictum at tempor commodo. Velit dignissim sodales ut eu sem integer. Dictum sit amet justo donec. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sed turpis tincidunt id aliquet risus. Eget mauris pharetra et ultrices neque ornare aenean euismod. Diam quis enim lobortis scelerisque fermentum. Varius duis at consectetur lorem donec massa sapien. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Lectus urna duis convallis convallis tellus. Nibh ipsum consequat nisl vel pretium lectus quam id leo. Feugiat in ante metus dictum at tempor commodo. Velit dignissim sodales ut eu sem integer. Dictum sit amet justo donec. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sed turpis tincidunt id aliquet risus. Eget mauris pharetra et ultrices neque ornare aenean euismod. Diam quis enim lobortis scelerisque fermentum. Varius duis at consectetur lorem donec massa sapien. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Lectus urna duis convallis convallis tellus. Nibh ipsum consequat nisl vel pretium lectus quam id leo. Feugiat in ante metus dictum at tempor commodo. Velit dignissim sodales ut eu sem integer. Dictum sit amet justo donec. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus. Scelerisque mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus.") for i in std.range(0,100)
|
||||||
|
],
|
||||||
|
}
|
5
builtin-benchmarks/base64_byte_array.jsonnet
Normal file
5
builtin-benchmarks/base64_byte_array.jsonnet
Normal file
File diff suppressed because one or more lines are too long
65
builtins.go
65
builtins.go
@ -19,6 +19,7 @@ package jsonnet
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -681,6 +682,69 @@ func builtinMd5(i *interpreter, trace traceElement, x value) (value, error) {
|
|||||||
return makeValueString(hex.EncodeToString(hash[:])), nil
|
return makeValueString(hex.EncodeToString(hash[:])), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func builtinBase64(i *interpreter, trace traceElement, input value) (value, error) {
|
||||||
|
var byteArr []byte
|
||||||
|
|
||||||
|
var sanityCheck = func(v int) (string, bool) {
|
||||||
|
if v < 0 || 255 < v {
|
||||||
|
msg := fmt.Sprintf("base64 encountered invalid codepoint value in the array (must be 0 <= X <= 255), got %d", v)
|
||||||
|
return msg, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch input.(type) {
|
||||||
|
case valueString:
|
||||||
|
vStr, err := i.getString(input, trace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
runes := []rune(vStr.getGoString())
|
||||||
|
for _, r := range runes {
|
||||||
|
n := int(r)
|
||||||
|
msg, ok := sanityCheck(n)
|
||||||
|
if !ok {
|
||||||
|
return nil, makeRuntimeError(msg, i.getCurrentStackTrace(trace))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byteArr = []byte(string(vStr.getGoString()))
|
||||||
|
case *valueArray:
|
||||||
|
vArr, err := i.getArray(input, trace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cThunk := range vArr.elements {
|
||||||
|
cTv, err := cThunk.getValue(i, trace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
vInt, err := i.getInt(cTv, trace)
|
||||||
|
if err != nil {
|
||||||
|
msg := fmt.Sprintf("base64 encountered a non-integer value in the array, got %s", cTv.getType().name)
|
||||||
|
return nil, makeRuntimeError(msg, i.getCurrentStackTrace(trace))
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, ok := sanityCheck(vInt)
|
||||||
|
if !ok {
|
||||||
|
return nil, makeRuntimeError(msg, i.getCurrentStackTrace(trace))
|
||||||
|
}
|
||||||
|
|
||||||
|
byteArr = append(byteArr, byte(vInt))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
msg := fmt.Sprintf("base64 can only base64 encode strings / arrays of single bytes, got %s", input.getType().name)
|
||||||
|
return nil, makeRuntimeError(msg, i.getCurrentStackTrace(trace))
|
||||||
|
}
|
||||||
|
|
||||||
|
sEnc := base64.StdEncoding.EncodeToString(byteArr)
|
||||||
|
return makeValueString(sEnc), nil
|
||||||
|
}
|
||||||
|
|
||||||
func builtinEncodeUTF8(i *interpreter, trace traceElement, x value) (value, error) {
|
func builtinEncodeUTF8(i *interpreter, trace traceElement, x value) (value, error) {
|
||||||
str, err := i.getString(x, trace)
|
str, err := i.getString(x, trace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1318,6 +1382,7 @@ var funcBuiltins = buildBuiltinMap([]builtin{
|
|||||||
&ternaryBuiltin{name: "splitLimit", function: builtinSplitLimit, parameters: ast.Identifiers{"str", "c", "maxsplits"}},
|
&ternaryBuiltin{name: "splitLimit", function: builtinSplitLimit, parameters: ast.Identifiers{"str", "c", "maxsplits"}},
|
||||||
&ternaryBuiltin{name: "strReplace", function: builtinStrReplace, parameters: ast.Identifiers{"str", "from", "to"}},
|
&ternaryBuiltin{name: "strReplace", function: builtinStrReplace, parameters: ast.Identifiers{"str", "from", "to"}},
|
||||||
&unaryBuiltin{name: "parseJson", function: builtinParseJSON, parameters: ast.Identifiers{"str"}},
|
&unaryBuiltin{name: "parseJson", function: builtinParseJSON, parameters: ast.Identifiers{"str"}},
|
||||||
|
&unaryBuiltin{name: "base64", function: builtinBase64, parameters: ast.Identifiers{"input"}},
|
||||||
&unaryBuiltin{name: "encodeUTF8", function: builtinEncodeUTF8, parameters: ast.Identifiers{"str"}},
|
&unaryBuiltin{name: "encodeUTF8", function: builtinEncodeUTF8, parameters: ast.Identifiers{"str"}},
|
||||||
&unaryBuiltin{name: "decodeUTF8", function: builtinDecodeUTF8, parameters: ast.Identifiers{"arr"}},
|
&unaryBuiltin{name: "decodeUTF8", function: builtinDecodeUTF8, parameters: ast.Identifiers{"arr"}},
|
||||||
&generalBuiltin{name: "sort", function: builtinSort, required: ast.Identifiers{"arr"}, optional: ast.Identifiers{"keyF"}, defaultValues: []value{functionID}},
|
&generalBuiltin{name: "sort", function: builtinSort, required: ast.Identifiers{"arr"}, optional: ast.Identifiers{"keyF"}, defaultValues: []value{functionID}},
|
||||||
|
@ -38,3 +38,11 @@ func Benchmark_Builtin_substr(b *testing.B) {
|
|||||||
func Benchmark_Builtin_reverse(b *testing.B) {
|
func Benchmark_Builtin_reverse(b *testing.B) {
|
||||||
RunBenchmark(b, "reverse")
|
RunBenchmark(b, "reverse")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Benchmark_Builtin_base64(b *testing.B) {
|
||||||
|
RunBenchmark(b, "base64")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_Builtin_base64_byte_array(b *testing.B) {
|
||||||
|
RunBenchmark(b, "base64_byte_array")
|
||||||
|
}
|
||||||
|
1
testdata/builtinBase64.golden
vendored
Normal file
1
testdata/builtinBase64.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
"aGVsbG8="
|
1
testdata/builtinBase64.jsonnet
vendored
Normal file
1
testdata/builtinBase64.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
std.base64("hello")
|
1
testdata/builtinBase64_byte_array.golden
vendored
Normal file
1
testdata/builtinBase64_byte_array.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
"aGVsbG8="
|
1
testdata/builtinBase64_byte_array.jsonnet
vendored
Normal file
1
testdata/builtinBase64_byte_array.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
std.base64([104, 101, 108, 108, 111])
|
10
testdata/builtinBase64_invalid_byte_array.golden
vendored
Normal file
10
testdata/builtinBase64_invalid_byte_array.golden
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
RUNTIME ERROR: base64 encountered a non-integer value in the array, got string
|
||||||
|
-------------------------------------------------
|
||||||
|
testdata/builtinBase64_invalid_byte_array:1:1-23 builtin function <base64>
|
||||||
|
|
||||||
|
std.base64([1, "foo"])
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
During evaluation
|
||||||
|
|
||||||
|
|
1
testdata/builtinBase64_invalid_byte_array.jsonnet
vendored
Normal file
1
testdata/builtinBase64_invalid_byte_array.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
std.base64([1, "foo"])
|
10
testdata/builtinBase64_invalid_byte_array1.golden
vendored
Normal file
10
testdata/builtinBase64_invalid_byte_array1.golden
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
RUNTIME ERROR: base64 encountered invalid codepoint value in the array (must be 0 <= X <= 255), got -1
|
||||||
|
-------------------------------------------------
|
||||||
|
testdata/builtinBase64_invalid_byte_array1:1:1-20 builtin function <base64>
|
||||||
|
|
||||||
|
std.base64([1, -1])
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
During evaluation
|
||||||
|
|
||||||
|
|
1
testdata/builtinBase64_invalid_byte_array1.jsonnet
vendored
Normal file
1
testdata/builtinBase64_invalid_byte_array1.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
std.base64([1, -1])
|
10
testdata/builtinBase64_invalid_byte_array2.golden
vendored
Normal file
10
testdata/builtinBase64_invalid_byte_array2.golden
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
RUNTIME ERROR: base64 encountered invalid codepoint value in the array (must be 0 <= X <= 255), got 256
|
||||||
|
-------------------------------------------------
|
||||||
|
testdata/builtinBase64_invalid_byte_array2:1:1-21 builtin function <base64>
|
||||||
|
|
||||||
|
std.base64([1, 256])
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
During evaluation
|
||||||
|
|
||||||
|
|
1
testdata/builtinBase64_invalid_byte_array2.jsonnet
vendored
Normal file
1
testdata/builtinBase64_invalid_byte_array2.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
std.base64([1, 256])
|
10
testdata/builtinBase64_non_string_non_array.golden
vendored
Normal file
10
testdata/builtinBase64_non_string_non_array.golden
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
RUNTIME ERROR: base64 can only base64 encode strings / arrays of single bytes, got number
|
||||||
|
-------------------------------------------------
|
||||||
|
testdata/builtinBase64_non_string_non_array:1:1-14 builtin function <base64>
|
||||||
|
|
||||||
|
std.base64(1)
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
During evaluation
|
||||||
|
|
||||||
|
|
1
testdata/builtinBase64_non_string_non_array.jsonnet
vendored
Normal file
1
testdata/builtinBase64_non_string_non_array.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
std.base64(1)
|
10
testdata/builtinBase64_string_high_codepoint.golden
vendored
Normal file
10
testdata/builtinBase64_string_high_codepoint.golden
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
RUNTIME ERROR: base64 encountered invalid codepoint value in the array (must be 0 <= X <= 255), got 256
|
||||||
|
-------------------------------------------------
|
||||||
|
testdata/builtinBase64_string_high_codepoint:1:1-17 builtin function <base64>
|
||||||
|
|
||||||
|
std.base64("Ā")
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
During evaluation
|
||||||
|
|
||||||
|
|
1
testdata/builtinBase64_string_high_codepoint.jsonnet
vendored
Normal file
1
testdata/builtinBase64_string_high_codepoint.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
std.base64("Ā")
|
Loading…
x
Reference in New Issue
Block a user