cuelang.org/go@v0.13.0/cue/bench_test.go (about)

     1  // Copyright 2020 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cue_test
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"io/fs"
    21  	"os"
    22  	"path/filepath"
    23  	"testing"
    24  
    25  	"cuelang.org/go/cue/cuecontext"
    26  	"cuelang.org/go/internal/core/eval"
    27  	"cuelang.org/go/internal/core/runtime"
    28  	"cuelang.org/go/internal/cuetdtest"
    29  	"cuelang.org/go/internal/cuetest"
    30  	"cuelang.org/go/internal/cuetxtar"
    31  	"golang.org/x/tools/txtar"
    32  )
    33  
    34  var (
    35  	matrix = cuetdtest.FullMatrix
    36  )
    37  
    38  func Benchmark(b *testing.B) {
    39  	root := "testdata/benchmarks"
    40  	err := filepath.WalkDir(root, func(fullpath string, entry fs.DirEntry, err error) error {
    41  		if err != nil {
    42  			return err
    43  		}
    44  
    45  		if entry.IsDir() || filepath.Ext(fullpath) != ".txtar" {
    46  			return nil
    47  		}
    48  
    49  		a, err := txtar.ParseFile(fullpath)
    50  		if err != nil {
    51  			return err
    52  		}
    53  
    54  		inst := cuetxtar.Load(a, b.TempDir())[0]
    55  		if inst.Err != nil {
    56  			return inst.Err
    57  		}
    58  
    59  		r := runtime.New()
    60  		v, err := r.Build(nil, inst)
    61  		if err != nil {
    62  			b.Fatal(err)
    63  		}
    64  		e := eval.New(r)
    65  		ctx := e.NewContext(v)
    66  		v.Finalize(ctx)
    67  
    68  		if cuetest.UpdateGoldenFiles {
    69  			const statsFile = "stats.txt"
    70  			var stats txtar.File
    71  			var statsPos int
    72  			for i, f := range a.Files {
    73  				if f.Name == statsFile {
    74  					stats = f
    75  					statsPos = i
    76  					break
    77  				}
    78  			}
    79  			if stats.Name == "" {
    80  				// At stats.txt as the first file.
    81  				a.Files = append([]txtar.File{{
    82  					Name: statsFile,
    83  				}}, a.Files...)
    84  			}
    85  
    86  			a.Files[statsPos].Data = []byte(ctx.Stats().String() + "\n\n")
    87  
    88  			info, err := entry.Info()
    89  			if err != nil {
    90  				b.Fatal(err)
    91  			}
    92  			os.WriteFile(fullpath, txtar.Format(a), info.Mode())
    93  		}
    94  
    95  		b.Run(entry.Name(), func(b *testing.B) {
    96  			for _, m := range matrix {
    97  				b.Run(m.Name(), func(b *testing.B) {
    98  					b.ReportAllocs()
    99  					for i := 0; i < b.N; i++ {
   100  						ctx := m.CueContext()
   101  						value := ctx.BuildInstance(cuetxtar.Load(a, b.TempDir())[0])
   102  						value.Validate()
   103  					}
   104  				})
   105  			}
   106  		})
   107  		return nil
   108  	})
   109  	if err != nil {
   110  		b.Fatal(err)
   111  	}
   112  }
   113  
   114  // TODO(mvdan): move this benchmark to internal/encoding
   115  // and cover other encodings too.
   116  // We should also cover both encoding and decoding performance.
   117  func BenchmarkLargeValueMarshalJSON(b *testing.B) {
   118  	b.ReportAllocs()
   119  	size := 2000
   120  
   121  	var buf bytes.Buffer
   122  
   123  	fmt.Fprintf(&buf, "longString: \"")
   124  	for range size {
   125  		fmt.Fprintf(&buf, "x")
   126  	}
   127  	fmt.Fprintf(&buf, "\"\n")
   128  
   129  	fmt.Fprintf(&buf, "nestedList: ")
   130  	for range size {
   131  		fmt.Fprintf(&buf, "[")
   132  	}
   133  	fmt.Fprintf(&buf, "0")
   134  	for range size {
   135  		fmt.Fprintf(&buf, "]")
   136  	}
   137  	fmt.Fprintf(&buf, "\n")
   138  
   139  	fmt.Fprintf(&buf, "longList: [")
   140  	for i := range size {
   141  		if i > 0 {
   142  			fmt.Fprintf(&buf, ",")
   143  		}
   144  		fmt.Fprintf(&buf, "0")
   145  	}
   146  	fmt.Fprintf(&buf, "]\n")
   147  
   148  	fmt.Fprintf(&buf, "nestedStruct: ")
   149  	for range size {
   150  		fmt.Fprintf(&buf, "{k:")
   151  	}
   152  	fmt.Fprintf(&buf, "0")
   153  	for range size {
   154  		fmt.Fprintf(&buf, "}")
   155  	}
   156  	fmt.Fprintf(&buf, "\n")
   157  
   158  	fmt.Fprintf(&buf, "longStruct: {")
   159  	for i := range size {
   160  		if i > 0 {
   161  			fmt.Fprintf(&buf, ",")
   162  		}
   163  		fmt.Fprintf(&buf, "k%d: 0", i)
   164  	}
   165  	fmt.Fprintf(&buf, "}\n")
   166  
   167  	ctx := cuecontext.New()
   168  	val := ctx.CompileBytes(buf.Bytes())
   169  	if err := val.Err(); err != nil {
   170  		b.Fatal(err)
   171  	}
   172  	b.ResetTimer()
   173  	for i := 0; i < b.N; i++ {
   174  		data, err := val.MarshalJSON()
   175  		if err != nil {
   176  			b.Fatal(err)
   177  		}
   178  		_ = data
   179  	}
   180  }