Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cue/load: implement shared syntax cache
We define a new optional `io.FS` interface which allows the `modpkgload` code (or, more specifically, the `modimports` code), to access the cached syntax maintained by `cue/load`. We then implement that interface in the `cue/load`-provided `io.FS` implementation, thus sharing the cache between `cue/load` and the modules dependency calculation code. One slightly adverse implication of this is that, when invoked from `cue/load`, the dependency code will now read entire CUE files rather than just the imports part, but that should hopefully not have a huge impact in practice, as CUE files will usually be included in the `build.Instance`, and therefore need the whole syntax to be parsed anyway. If it turns out to be a problem, we could fix it by using a somewhat more sophisticated cache in the future. To verify that the caching is actually working as expected, I ran the following testscript (with `testscript -v`), which creates a large module with many instances that span multiple directories. exec go run writemodule.go exec sh -c 'time cue fmt --check ./...' -- go.mod -- module test -- writemodule.go -- package main import ( "fmt" "log" "os" "path/filepath" "strings" ) var modDir = filepath.Join(os.Getenv("WORK")) func main() { if err := os.MkdirAll(modDir, 0o777); err != nil { log.Fatal(err) } for i := range 5 { writePackage(fmt.Sprintf("x%d.cue", i)) for j := range 10 { writePackage(fmt.Sprintf("d%d/x%d.cue", i, j)) for k := range 10 { writePackage(fmt.Sprintf("d%d/d%d/x%d.cue", i, j, k)) for l := range 10 { writePackage(fmt.Sprintf("d%d/d%d/d%d/x%d.cue", i, j, k, l)) } } } } writeFile("cue.mod/module.cue", ` module: "test.example" language: version: "v0.9.2" `) } const fillerLines = 100 var filler = func() string { var buf strings.Builder for i := range fillerLines { fmt.Fprintf(&buf, "\n_d%d: true\n", i) } return buf.String() }() func writePackage(name string) { contents := fmt.Sprintf(` package x value: %q: true `[1:], name) writeFile(name, contents+filler) } func writeFile(name string, contents string) { name = filepath.Join(modDir, name) if err := os.MkdirAll(filepath.Dir(name), 0o777); err != nil { log.Fatal(err) } if err := os.WriteFile(name, []byte(contents), 0o666); err != nil { log.Fatal(err) } } At the start of this CL chain (commit 27adbac) the result was: 9.85user 0.51system 0:05.40elapsed 191%CPU (0avgtext+0avgdata 436104maxresident)k 0inputs+0outputs (0major+122110minor)pagefaults 0swaps As of this CL, I get this: 6.22user 0.20system 0:03.24elapsed 198%CPU (0avgtext+0avgdata 476548maxresident)k 0inputs+0outputs (0major+142320minor)pagefaults 0swaps This is a reduction of 40%, indicating that the caching seems to be working as expected. There is still more to be done: we are not yet caching the results of directory reads, which should provide more speedup in a subsequent CL. Fixes #3177. Signed-off-by: Roger Peppe <[email protected]> Change-Id: I1f8328df09b5b6e457b202de2337d2dac2be1d19 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1197531 Reviewed-by: Paul Jolly <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
- Loading branch information