this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cue/stats: new package for getting operation statistics

The functionality is hoisted from adt, but the package should for all
practical purposes be seen as a new implementation.

Note that some of the methods are now by value. This will make it
easier to make things thread-safe in the future. We may also
opt to hide the struct fields later on. But for now, as this has been
working for a long time, we expect this to be sufficient for a while
to come.

The stats have been aggregated as experimental functionality to
the tools/flow package.

Issue #1795

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: Ifd3458d0fa03f3b2d91c50385e34e24b5a93bc70
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/542778
Reviewed-by: Paul Jolly <paul@myitcv.io>
Unity-Result: CUEcueckoo <cueckoo@cuelang.org>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+643 -46
+118
cue/stats/stats.go
··· 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 + "html/template" 21 + "strings" 22 + ) 23 + 24 + // Counts holds counters for key events during a CUE evaluation. 25 + // 26 + // This is an experimental type and the contents may change without notice. 27 + type Counts struct { 28 + // Operation counters 29 + // 30 + // These counters account for several key operations. 31 + 32 + // Unifications counts the number of calls to adt.Unify 33 + Unifications int 34 + 35 + // Disjuncts indicates the number of total disjuncts processed as part 36 + // of a Unify operation. A unification with no | operator counts as a 37 + // single disjunct, so Disjuncts is always greater than or equal to the 38 + // number of Unifications. 39 + // 40 + // If Disjuncts is much larger than Unification, this may indicate room 41 + // for optimization. In particular, most practical uses of disjunctions 42 + // should allow for near-linear processing. 43 + Disjuncts int 44 + 45 + // Conjuncts is an estimate of the number of conjunctions processed during 46 + // the calls to Unify. This includes the conjuncts added in the compilation 47 + // phase as well as the derivative conjuncts inserted from other nodes 48 + // after following references. 49 + // 50 + // A number of Conjuncts much larger than Disjuncts may indicate non-linear 51 + // algorithmic behavior. 52 + Conjuncts int 53 + 54 + // Buffer counters 55 + // 56 + // Each unification and disjunct operation is associated with an object 57 + // with temporary buffers. Reuse of this buffer is critical for performance. 58 + // The following counters track this. 59 + 60 + Freed int // Number of buffers returned to the free pool. 61 + Reused int // Number of times a buffer is reused instead of allocated. 62 + Allocs int // Total number of allocated buffer objects. 63 + Retained int // Number of times a buffer is retained upon finalization. 64 + } 65 + 66 + func (c *Counts) Add(other Counts) { 67 + c.Unifications += other.Unifications 68 + c.Conjuncts += other.Conjuncts 69 + c.Disjuncts += other.Disjuncts 70 + 71 + c.Freed += other.Freed 72 + c.Retained += other.Retained 73 + c.Reused += other.Reused 74 + c.Allocs += other.Allocs 75 + } 76 + 77 + func (c Counts) Since(start Counts) Counts { 78 + c.Unifications -= start.Unifications 79 + c.Conjuncts -= start.Conjuncts 80 + c.Disjuncts -= start.Disjuncts 81 + 82 + c.Freed -= start.Freed 83 + c.Retained -= start.Retained 84 + c.Reused -= start.Reused 85 + c.Allocs -= start.Allocs 86 + 87 + return c 88 + } 89 + 90 + // Leaks reports the number of nodeContext structs leaked. These are typically 91 + // benign, as they will just be garbage collected, as long as the pointer from 92 + // the original nodes has been eliminated or the original nodes are also not 93 + // referred to. But Leaks may have notable impact on performance, and thus 94 + // should be avoided. 95 + func (s Counts) Leaks() int { 96 + return s.Allocs + s.Reused - s.Freed 97 + } 98 + 99 + var stats = template.Must(template.New("stats").Parse(`{{"" -}} 100 + 101 + Leaks: {{.Leaks}} 102 + Freed: {{.Freed}} 103 + Reused: {{.Reused}} 104 + Allocs: {{.Allocs}} 105 + Retain: {{.Retained}} 106 + 107 + Unifications: {{.Unifications}} 108 + Conjuncts: {{.Conjuncts}} 109 + Disjuncts: {{.Disjuncts}}`)) 110 + 111 + func (s Counts) String() string { 112 + buf := &strings.Builder{} 113 + err := stats.Execute(buf, s) 114 + if err != nil { 115 + panic(err) 116 + } 117 + return buf.String() 118 + }
+2 -1
internal/core/adt/context.go
··· 28 28 29 29 "cuelang.org/go/cue/ast" 30 30 "cuelang.org/go/cue/errors" 31 + "cuelang.org/go/cue/stats" 31 32 "cuelang.org/go/cue/token" 32 33 ) 33 34 ··· 214 215 215 216 nest int 216 217 217 - stats Stats 218 + stats stats.Counts 218 219 freeListNode *nodeContext 219 220 220 221 e *Environment
+1 -1
internal/core/adt/disjunct.go
··· 124 124 parentMode defaultMode, // default mode of this disjunct 125 125 recursive, last bool) { 126 126 127 - n.ctx.stats.DisjunctCount++ 127 + n.ctx.stats.Disjuncts++ 128 128 129 129 node := n.node 130 130 defer func() {
+4 -43
internal/core/adt/eval.go
··· 26 26 27 27 import ( 28 28 "fmt" 29 - "html/template" 30 - "strings" 31 29 32 30 "cuelang.org/go/cue/ast" 33 31 "cuelang.org/go/cue/errors" 32 + "cuelang.org/go/cue/stats" 34 33 "cuelang.org/go/cue/token" 35 34 ) 36 35 ··· 43 42 // - Test closedness far more thoroughly. 44 43 // 45 44 46 - type Stats struct { 47 - UnifyCount int 48 - ConjunctCount int 49 - DisjunctCount int 50 - 51 - Freed int 52 - Retained int 53 - Reused int 54 - Allocs int 55 - } 56 - 57 - // Leaks reports the number of nodeContext structs leaked. These are typically 58 - // benign, as they will just be garbage collected, as long as the pointer from 59 - // the original nodes has been eliminated or the original nodes are also not 60 - // referred to. But Leaks may have notable impact on performance, and thus 61 - // should be avoided. 62 - func (s *Stats) Leaks() int { 63 - return s.Allocs + s.Reused - s.Freed 64 - } 65 - 66 - var stats = template.Must(template.New("stats").Parse(`{{"" -}} 67 - 68 - Leaks: {{.Leaks}} 69 - Freed: {{.Freed}} 70 - Reused: {{.Reused}} 71 - Allocs: {{.Allocs}} 72 - Retain: {{.Retained}} 73 - 74 - Unifications: {{.UnifyCount}} 75 - Conjuncts: {{.ConjunctCount}} 76 - Disjuncts: {{.DisjunctCount}}`)) 77 - 78 - func (s *Stats) String() string { 79 - buf := &strings.Builder{} 80 - _ = stats.Execute(buf, s) 81 - return buf.String() 82 - } 83 - 84 - func (c *OpContext) Stats() *Stats { 45 + func (c *OpContext) Stats() *stats.Counts { 85 46 return &c.stats 86 47 } 87 48 ··· 244 205 245 206 defer c.PopArc(c.PushArc(v)) 246 207 247 - c.stats.UnifyCount++ 208 + c.stats.Unifications++ 248 209 249 210 // Set the cache to a cycle error to ensure a cyclic reference will result 250 211 // in an error if applicable. A cyclic error may be ignored for ··· 1401 1362 // Must be Resolver or Evaluator. 1402 1363 n.evalExpr(v) 1403 1364 } 1404 - n.ctx.stats.ConjunctCount++ 1365 + n.ctx.stats.Conjuncts++ 1405 1366 } 1406 1367 1407 1368 // evalExpr is only called by addExprConjunct. If an error occurs, it records
+2 -1
internal/core/eval/eval.go
··· 15 15 package eval 16 16 17 17 import ( 18 + "cuelang.org/go/cue/stats" 18 19 "cuelang.org/go/internal/core/adt" 19 20 "cuelang.org/go/internal/core/debug" 20 21 ) ··· 43 44 e.e.Unify(v, state) 44 45 } 45 46 46 - func (e *Unifier) Stats() *adt.Stats { 47 + func (e *Unifier) Stats() *stats.Counts { 47 48 return e.e.Stats() 48 49 } 49 50
+3
internal/core/runtime/build.go
··· 21 21 "cuelang.org/go/cue/ast/astutil" 22 22 "cuelang.org/go/cue/build" 23 23 "cuelang.org/go/cue/errors" 24 + "cuelang.org/go/cue/stats" 24 25 "cuelang.org/go/cue/token" 25 26 "cuelang.org/go/internal" 26 27 "cuelang.org/go/internal/core/adt" ··· 31 32 Runtime *Runtime 32 33 Filename string 33 34 ImportPath string 35 + 36 + Counts *stats.Counts 34 37 35 38 compile.Config 36 39 }
+31
tools/flow/flow.go
··· 72 72 73 73 "cuelang.org/go/cue" 74 74 "cuelang.org/go/cue/errors" 75 + "cuelang.org/go/cue/stats" 75 76 "cuelang.org/go/internal/core/adt" 76 77 "cuelang.org/go/internal/core/convert" 77 78 "cuelang.org/go/internal/core/eval" ··· 164 165 context context.Context 165 166 cancelFunc context.CancelFunc 166 167 168 + // taskStats tracks counters for auxiliary operations done by tasks. It does 169 + // not include the CUE operations done by the Controller on behalf of tasks, 170 + // which is likely going to tbe the bulk of the operations. 171 + taskStats stats.Counts 172 + 167 173 mut *sync.Mutex 168 174 done bool 169 175 ··· 179 185 nodes map[*adt.Vertex]*Task 180 186 181 187 errs errors.Error 188 + } 189 + 190 + // Stats reports statistics on the total number of CUE operations used. 191 + // 192 + // This is an experimental method and the API is likely to change. The 193 + // Counts.String method will likely stay and is the safest way to use this API. 194 + // 195 + // This currently should only be called after completion or within a call to 196 + // UpdateFunc. 197 + func (c *Controller) Stats() (counts stats.Counts) { 198 + counts = *c.opCtx.Stats() 199 + counts.Add(c.taskStats) 200 + return counts 182 201 } 183 202 184 203 // Tasks reports the tasks that are currently registered with the controller. ··· 333 352 err errors.Error 334 353 state State 335 354 depTasks []*Task 355 + 356 + stats stats.Counts 357 + } 358 + 359 + // Stats reports statistics on the number of CUE operations used to complete 360 + // this task. 361 + // 362 + // This is an experimental method and the API is likely to change. 363 + // 364 + // It only shows numbers upon completion. This may change in the future. 365 + func (t *Task) Stats() stats.Counts { 366 + return t.stats 336 367 } 337 368 338 369 // Context reports the Controller's Context.
+34
tools/flow/flow_test.go
··· 28 28 "cuelang.org/go/cue/cuecontext" 29 29 "cuelang.org/go/cue/errors" 30 30 "cuelang.org/go/cue/format" 31 + "cuelang.org/go/cue/stats" 31 32 "cuelang.org/go/internal/cuetest" 32 33 "cuelang.org/go/internal/cuetxtar" 33 34 "cuelang.org/go/tools/flow" ··· 53 54 54 55 seqNum = 0 55 56 57 + var tasksTotal stats.Counts 58 + 56 59 updateFunc := func(c *flow.Controller, task *flow.Task) error { 57 60 str := mermaidGraph(c) 58 61 step := fmt.Sprintf("t%d", seqNum) ··· 65 68 t.Fatal(err) 66 69 } 67 70 fmt.Fprintln(t.Writer(path.Join(step, "value")), string(b)) 71 + 72 + stats := task.Stats() 73 + tasksTotal.Add(stats) 74 + fmt.Fprintln(t.Writer(path.Join(step, "stats")), &stats) 68 75 } 69 76 70 77 incSeqNum() ··· 91 98 ToSlash: true, 92 99 }) 93 100 } 101 + 102 + totals := c.Stats() 103 + if tasksTotal != zeroStats && totals != tasksTotal { 104 + t.Errorf(diffMsg, tasksTotal, totals, tasksTotal.Since(totals)) 105 + } 106 + fmt.Fprintln(t.Writer("stats/totals"), totals) 94 107 }) 95 108 } 109 + 110 + var zeroStats stats.Counts 111 + 112 + const diffMsg = ` 113 + stats: task totals differens from controller: 114 + task totals: 115 + %v 116 + 117 + controller totals: 118 + %v 119 + 120 + task totals - controller totals: 121 + %v` 96 122 97 123 func TestFlowValuePanic(t *testing.T) { 98 124 f := ` ··· 256 282 257 283 c := flow.New(&flow.Config{ 258 284 Root: cue.ParsePath("root"), 285 + UpdateFunc: func(c *flow.Controller, ft *flow.Task) error { 286 + if ft != nil { 287 + t.Errorf("\nTASK:\n%s", ft.Stats()) 288 + } 289 + return nil 290 + }, 259 291 }, v, taskFunc) 260 292 261 293 t.Error(mermaidGraph(c)) ··· 263 295 if err := c.Run(context.Background()); err != nil { 264 296 t.Fatal(errors.Details(err, nil)) 265 297 } 298 + 299 + t.Errorf("\nCONTROLLER:\n%s", c.Stats()) 266 300 }
+8
tools/flow/run.go
··· 94 94 case t := <-c.taskCh: 95 95 t.state = Terminated 96 96 97 + taskStats := *t.ctxt.Stats() 98 + t.stats.Add(taskStats) 99 + c.taskStats.Add(taskStats) 100 + 101 + start := *c.opCtx.Stats() 102 + 97 103 switch t.err { 98 104 case nil: 99 105 c.updateTaskResults(t) ··· 115 121 } 116 122 117 123 c.updateTaskValue(t) 124 + 125 + t.stats.Add(c.opCtx.Stats().Since(start)) 118 126 119 127 c.markReady(t) 120 128 }
+30
tools/flow/testdata/concrete.txtar
··· 44 44 text: "v" 45 45 value: "v" 46 46 } 47 + -- out/run/t1/stats -- 48 + Leaks: 0 49 + Freed: 0 50 + Reused: 0 51 + Allocs: 0 52 + Retain: 0 53 + 54 + Unifications: 0 55 + Conjuncts: 0 56 + Disjuncts: 0 57 + -- out/run/t2/stats -- 58 + Leaks: 0 59 + Freed: 0 60 + Reused: 0 61 + Allocs: 0 62 + Retain: 0 63 + 64 + Unifications: 0 65 + Conjuncts: 0 66 + Disjuncts: 0 67 + -- out/run/stats/totals -- 68 + Leaks: 0 69 + Freed: 0 70 + Reused: 0 71 + Allocs: 0 72 + Retain: 0 73 + 74 + Unifications: 0 75 + Conjuncts: 0 76 + Disjuncts: 0
+10
tools/flow/testdata/cycle.txtar
··· 32 32 t2("root.c [Waiting]") 33 33 t2-->t1 34 34 35 + -- out/run/stats/totals -- 36 + Leaks: 0 37 + Freed: 0 38 + Reused: 0 39 + Allocs: 0 40 + Retain: 0 41 + 42 + Unifications: 0 43 + Conjuncts: 0 44 + Disjuncts: 0
+100
tools/flow/testdata/dep.txtar
··· 342 342 //cue:path: root.indirectTaskRootReference.incomplete 343 343 let INCOMPLETE = _ 344 344 } 345 + -- out/run/t1/stats -- 346 + Leaks: 0 347 + Freed: 0 348 + Reused: 0 349 + Allocs: 0 350 + Retain: 0 351 + 352 + Unifications: 0 353 + Conjuncts: 0 354 + Disjuncts: 0 355 + -- out/run/t2/stats -- 356 + Leaks: 0 357 + Freed: 0 358 + Reused: 0 359 + Allocs: 0 360 + Retain: 0 361 + 362 + Unifications: 0 363 + Conjuncts: 0 364 + Disjuncts: 0 365 + -- out/run/t3/stats -- 366 + Leaks: 0 367 + Freed: 0 368 + Reused: 0 369 + Allocs: 0 370 + Retain: 0 371 + 372 + Unifications: 0 373 + Conjuncts: 0 374 + Disjuncts: 0 375 + -- out/run/t4/stats -- 376 + Leaks: 0 377 + Freed: 0 378 + Reused: 0 379 + Allocs: 0 380 + Retain: 0 381 + 382 + Unifications: 0 383 + Conjuncts: 0 384 + Disjuncts: 0 385 + -- out/run/t5/stats -- 386 + Leaks: 0 387 + Freed: 0 388 + Reused: 0 389 + Allocs: 0 390 + Retain: 0 391 + 392 + Unifications: 0 393 + Conjuncts: 0 394 + Disjuncts: 0 395 + -- out/run/t6/stats -- 396 + Leaks: 0 397 + Freed: 0 398 + Reused: 0 399 + Allocs: 0 400 + Retain: 0 401 + 402 + Unifications: 0 403 + Conjuncts: 0 404 + Disjuncts: 0 405 + -- out/run/t7/stats -- 406 + Leaks: 0 407 + Freed: 0 408 + Reused: 0 409 + Allocs: 0 410 + Retain: 0 411 + 412 + Unifications: 0 413 + Conjuncts: 0 414 + Disjuncts: 0 415 + -- out/run/t8/stats -- 416 + Leaks: 0 417 + Freed: 0 418 + Reused: 0 419 + Allocs: 0 420 + Retain: 0 421 + 422 + Unifications: 0 423 + Conjuncts: 0 424 + Disjuncts: 0 425 + -- out/run/t9/stats -- 426 + Leaks: 0 427 + Freed: 0 428 + Reused: 0 429 + Allocs: 0 430 + Retain: 0 431 + 432 + Unifications: 0 433 + Conjuncts: 0 434 + Disjuncts: 0 435 + -- out/run/stats/totals -- 436 + Leaks: 0 437 + Freed: 3 438 + Reused: 1 439 + Allocs: 2 440 + Retain: 0 441 + 442 + Unifications: 3 443 + Conjuncts: 3 444 + Disjuncts: 3
+50
tools/flow/testdata/dynamic.txtar
··· 104 104 out: "foo2" 105 105 val: "foo2" 106 106 } 107 + -- out/run/t1/stats -- 108 + Leaks: 0 109 + Freed: 24 110 + Reused: 16 111 + Allocs: 8 112 + Retain: 0 113 + 114 + Unifications: 24 115 + Conjuncts: 38 116 + Disjuncts: 24 117 + -- out/run/t2/stats -- 118 + Leaks: 0 119 + Freed: 23 120 + Reused: 23 121 + Allocs: 0 122 + Retain: 0 123 + 124 + Unifications: 23 125 + Conjuncts: 42 126 + Disjuncts: 23 127 + -- out/run/t3/stats -- 128 + Leaks: 0 129 + Freed: 31 130 + Reused: 29 131 + Allocs: 2 132 + Retain: 0 133 + 134 + Unifications: 31 135 + Conjuncts: 58 136 + Disjuncts: 31 137 + -- out/run/t4/stats -- 138 + Leaks: 0 139 + Freed: 29 140 + Reused: 29 141 + Allocs: 0 142 + Retain: 0 143 + 144 + Unifications: 29 145 + Conjuncts: 60 146 + Disjuncts: 29 147 + -- out/run/stats/totals -- 148 + Leaks: 0 149 + Freed: 107 150 + Reused: 97 151 + Allocs: 10 152 + Retain: 0 153 + 154 + Unifications: 107 155 + Conjuncts: 198 156 + Disjuncts: 107
+10
tools/flow/testdata/failure.txtar
··· 20 20 t1("root.b [Waiting]") 21 21 t1-->t0 22 22 23 + -- out/run/stats/totals -- 24 + Leaks: 0 25 + Freed: 0 26 + Reused: 0 27 + Allocs: 0 28 + Retain: 0 29 + 30 + Unifications: 0 31 + Conjuncts: 0 32 + Disjuncts: 0
+40
tools/flow/testdata/hidden.txtar
··· 85 85 $id: "valToOut" 86 86 out: "foobar" 87 87 } 88 + -- out/run/t1/stats -- 89 + Leaks: 0 90 + Freed: 23 91 + Reused: 18 92 + Allocs: 5 93 + Retain: 0 94 + 95 + Unifications: 23 96 + Conjuncts: 39 97 + Disjuncts: 23 98 + -- out/run/t2/stats -- 99 + Leaks: 0 100 + Freed: 23 101 + Reused: 23 102 + Allocs: 0 103 + Retain: 0 104 + 105 + Unifications: 23 106 + Conjuncts: 34 107 + Disjuncts: 23 108 + -- out/run/t3/stats -- 109 + Leaks: 0 110 + Freed: 0 111 + Reused: 0 112 + Allocs: 0 113 + Retain: 0 114 + 115 + Unifications: 0 116 + Conjuncts: 0 117 + Disjuncts: 0 118 + -- out/run/stats/totals -- 119 + Leaks: 0 120 + Freed: 46 121 + Reused: 41 122 + Allocs: 5 123 + Retain: 0 124 + 125 + Unifications: 46 126 + Conjuncts: 73 127 + Disjuncts: 46
+40
tools/flow/testdata/infer.txtar
··· 74 74 $id: string 75 75 }] 76 76 } 77 + -- out/run/t1/stats -- 78 + Leaks: 0 79 + Freed: 0 80 + Reused: 0 81 + Allocs: 0 82 + Retain: 0 83 + 84 + Unifications: 0 85 + Conjuncts: 0 86 + Disjuncts: 0 87 + -- out/run/t2/stats -- 88 + Leaks: 0 89 + Freed: 0 90 + Reused: 0 91 + Allocs: 0 92 + Retain: 0 93 + 94 + Unifications: 0 95 + Conjuncts: 0 96 + Disjuncts: 0 97 + -- out/run/t3/stats -- 98 + Leaks: 0 99 + Freed: 0 100 + Reused: 0 101 + Allocs: 0 102 + Retain: 0 103 + 104 + Unifications: 0 105 + Conjuncts: 0 106 + Disjuncts: 0 107 + -- out/run/stats/totals -- 108 + Leaks: 0 109 + Freed: 0 110 + Reused: 0 111 + Allocs: 0 112 + Retain: 0 113 + 114 + Unifications: 0 115 + Conjuncts: 0 116 + Disjuncts: 0
+50
tools/flow/testdata/par.txtar
··· 100 100 $id: "valToOut" 101 101 out: "foobarbaz" 102 102 } 103 + -- out/run/t1/stats -- 104 + Leaks: 0 105 + Freed: 20 106 + Reused: 16 107 + Allocs: 4 108 + Retain: 0 109 + 110 + Unifications: 20 111 + Conjuncts: 27 112 + Disjuncts: 20 113 + -- out/run/t2/stats -- 114 + Leaks: 0 115 + Freed: 20 116 + Reused: 20 117 + Allocs: 0 118 + Retain: 0 119 + 120 + Unifications: 20 121 + Conjuncts: 31 122 + Disjuncts: 20 123 + -- out/run/t3/stats -- 124 + Leaks: 0 125 + Freed: 20 126 + Reused: 20 127 + Allocs: 0 128 + Retain: 0 129 + 130 + Unifications: 20 131 + Conjuncts: 32 132 + Disjuncts: 20 133 + -- out/run/t4/stats -- 134 + Leaks: 0 135 + Freed: 0 136 + Reused: 0 137 + Allocs: 0 138 + Retain: 0 139 + 140 + Unifications: 0 141 + Conjuncts: 0 142 + Disjuncts: 0 143 + -- out/run/stats/totals -- 144 + Leaks: 0 145 + Freed: 60 146 + Reused: 56 147 + Allocs: 4 148 + Retain: 0 149 + 150 + Unifications: 60 151 + Conjuncts: 90 152 + Disjuncts: 60
+40
tools/flow/testdata/pkg.txtar
··· 83 83 $id: "valToOut" 84 84 out: "foo subbar" 85 85 } 86 + -- out/run/t1/stats -- 87 + Leaks: 0 88 + Freed: 17 89 + Reused: 12 90 + Allocs: 5 91 + Retain: 0 92 + 93 + Unifications: 17 94 + Conjuncts: 27 95 + Disjuncts: 17 96 + -- out/run/t2/stats -- 97 + Leaks: 0 98 + Freed: 17 99 + Reused: 17 100 + Allocs: 0 101 + Retain: 0 102 + 103 + Unifications: 17 104 + Conjuncts: 28 105 + Disjuncts: 17 106 + -- out/run/t3/stats -- 107 + Leaks: 0 108 + Freed: 0 109 + Reused: 0 110 + Allocs: 0 111 + Retain: 0 112 + 113 + Unifications: 0 114 + Conjuncts: 0 115 + Disjuncts: 0 116 + -- out/run/stats/totals -- 117 + Leaks: 0 118 + Freed: 34 119 + Reused: 29 120 + Allocs: 5 121 + Retain: 0 122 + 123 + Unifications: 34 124 + Conjuncts: 55 125 + Disjuncts: 34
+40
tools/flow/testdata/simple.txtar
··· 75 75 $id: "valToOut" 76 76 out: "foobar" 77 77 } 78 + -- out/run/t1/stats -- 79 + Leaks: 0 80 + Freed: 17 81 + Reused: 12 82 + Allocs: 5 83 + Retain: 0 84 + 85 + Unifications: 17 86 + Conjuncts: 27 87 + Disjuncts: 17 88 + -- out/run/t2/stats -- 89 + Leaks: 0 90 + Freed: 17 91 + Reused: 17 92 + Allocs: 0 93 + Retain: 0 94 + 95 + Unifications: 17 96 + Conjuncts: 28 97 + Disjuncts: 17 98 + -- out/run/t3/stats -- 99 + Leaks: 0 100 + Freed: 0 101 + Reused: 0 102 + Allocs: 0 103 + Retain: 0 104 + 105 + Unifications: 0 106 + Conjuncts: 0 107 + Disjuncts: 0 108 + -- out/run/stats/totals -- 109 + Leaks: 0 110 + Freed: 34 111 + Reused: 29 112 + Allocs: 5 113 + Retain: 0 114 + 115 + Unifications: 34 116 + Conjuncts: 55 117 + Disjuncts: 34
+30
tools/flow/testdata/template.txtar
··· 96 96 stdin: (*null | string | bytes) & get.response.body 97 97 success: bool 98 98 } 99 + -- out/run/t1/stats -- 100 + Leaks: 0 101 + Freed: 38 102 + Reused: 31 103 + Allocs: 7 104 + Retain: 0 105 + 106 + Unifications: 24 107 + Conjuncts: 51 108 + Disjuncts: 37 109 + -- out/run/t2/stats -- 110 + Leaks: 0 111 + Freed: 38 112 + Reused: 38 113 + Allocs: 0 114 + Retain: 0 115 + 116 + Unifications: 24 117 + Conjuncts: 55 118 + Disjuncts: 37 119 + -- out/run/stats/totals -- 120 + Leaks: 0 121 + Freed: 76 122 + Reused: 69 123 + Allocs: 7 124 + Retain: 0 125 + 126 + Unifications: 48 127 + Conjuncts: 106 128 + Disjuncts: 74