cuelang.org/go@v0.10.1/cue/stats/stats.go (about) 1 // Copyright 2022 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 stats is an experimental package for getting statistics on CUE 16 // evaluations. 17 package stats 18 19 import ( 20 "strings" 21 "sync" 22 "text/template" 23 ) 24 25 // Counts holds counters for key events during a CUE evaluation. 26 // 27 // This is an experimental type and the contents may change without notice. 28 type Counts struct { 29 // Operation counters 30 // 31 // These counters account for several key operations. 32 33 // Unifications counts the number of calls to adt.Unify 34 Unifications int64 35 36 // Disjuncts indicates the number of total disjuncts processed as part 37 // of a Unify operation. A unification with no | operator counts as a 38 // single disjunct, so Disjuncts is always greater than or equal to the 39 // number of Unifications. 40 // 41 // If Disjuncts is much larger than Unification, this may indicate room 42 // for optimization. In particular, most practical uses of disjunctions 43 // should allow for near-linear processing. 44 Disjuncts int64 45 46 // Conjuncts is an estimate of the number of conjunctions processed during 47 // the calls to Unify. This includes the conjuncts added in the compilation 48 // phase as well as the derivative conjuncts inserted from other nodes 49 // after following references. 50 // 51 // A number of Conjuncts much larger than Disjuncts may indicate non-linear 52 // algorithmic behavior. 53 Conjuncts int64 54 55 // Buffer counters 56 // 57 // Each unification and disjunct operation is associated with an object 58 // with temporary buffers. Reuse of this buffer is critical for performance. 59 // The following counters track this. 60 61 Freed int64 // Number of buffers returned to the free pool. 62 Reused int64 // Number of times a buffer is reused instead of allocated. 63 Allocs int64 // Total number of allocated buffer objects. 64 Retained int64 // Number of times a buffer is retained upon finalization. 65 } 66 67 // TODO: None of the methods below protect against overflows or underflows. 68 // If those start happening in practice, or if the counters get large enough, 69 // add checks on each of the operations. 70 71 func (c *Counts) Add(other Counts) { 72 c.Unifications += other.Unifications 73 c.Conjuncts += other.Conjuncts 74 c.Disjuncts += other.Disjuncts 75 76 c.Freed += other.Freed 77 c.Retained += other.Retained 78 c.Reused += other.Reused 79 c.Allocs += other.Allocs 80 } 81 82 func (c Counts) Since(start Counts) Counts { 83 c.Unifications -= start.Unifications 84 c.Conjuncts -= start.Conjuncts 85 c.Disjuncts -= start.Disjuncts 86 87 c.Freed -= start.Freed 88 c.Retained -= start.Retained 89 c.Reused -= start.Reused 90 c.Allocs -= start.Allocs 91 92 return c 93 } 94 95 // Leaks reports the number of nodeContext structs leaked. These are typically 96 // benign, as they will just be garbage collected, as long as the pointer from 97 // the original nodes has been eliminated or the original nodes are also not 98 // referred to. But Leaks may have notable impact on performance, and thus 99 // should be avoided. 100 func (s Counts) Leaks() int64 { 101 return s.Allocs + s.Reused - s.Freed 102 } 103 104 var stats = sync.OnceValue(func() *template.Template { 105 return template.Must(template.New("stats").Parse(`{{"" -}} 106 107 Leaks: {{.Leaks}} 108 Freed: {{.Freed}} 109 Reused: {{.Reused}} 110 Allocs: {{.Allocs}} 111 Retain: {{.Retained}} 112 113 Unifications: {{.Unifications}} 114 Conjuncts: {{.Conjuncts}} 115 Disjuncts: {{.Disjuncts}}`)) 116 }) 117 118 func (s Counts) String() string { 119 buf := &strings.Builder{} 120 err := stats().Execute(buf, s) 121 if err != nil { 122 panic(err) 123 } 124 return buf.String() 125 }