diff options
author | Fumitoshi Ukai <fumitoshi.ukai@gmail.com> | 2015-06-11 15:16:29 +0900 |
---|---|---|
committer | Fumitoshi Ukai <fumitoshi.ukai@gmail.com> | 2015-06-11 15:19:23 +0900 |
commit | 432a242562d1802f3f2a182f42df86b1e4696271 (patch) | |
tree | a9d496fc398b363755ca48dd4ffa9b6e7919f6e1 | |
parent | 0daac1fbbb82ced82786bbdee2e716a38a16762b (diff) | |
download | kati-432a242562d1802f3f2a182f42df86b1e4696271.tar.gz |
add -kati_trace_event=<json filename>
if this option is given, it outputs trace json file
for chrome://tracing for makefile include traces.
-rw-r--r-- | eval.go | 5 | ||||
-rw-r--r-- | expr.go | 19 | ||||
-rw-r--r-- | func.go | 16 | ||||
-rw-r--r-- | main.go | 10 | ||||
-rw-r--r-- | stats.go | 76 |
5 files changed, 103 insertions, 23 deletions
@@ -21,7 +21,6 @@ import ( "io/ioutil" "path/filepath" "strings" - "time" ) type FileState int @@ -264,9 +263,9 @@ func (ev *Evaluator) EvaluateVar(name string) string { } func (ev *Evaluator) evalIncludeFile(fname string, c []byte) error { - t := time.Now() + te := traceEvent.begin("include", literal(fname)) defer func() { - addStats("include", literal(fname), t) + traceEvent.end(te) }() mk, ok, err := LookupMakefileCache(fname) if !ok { @@ -22,7 +22,6 @@ import ( "strconv" "strings" "sync" - "time" ) var ( @@ -150,13 +149,13 @@ func (v varref) String() string { } func (v varref) Eval(w io.Writer, ev *Evaluator) { - t := time.Now() + te := traceEvent.begin("var", v) buf := newBuf() v.varname.Eval(buf, ev) vv := ev.LookupVar(buf.String()) freeBuf(buf) vv.Eval(w, ev) - addStats("var", v, t) + traceEvent.end(te) } func (v varref) Serialize() SerializableVar { @@ -178,7 +177,7 @@ func (p paramref) String() string { } func (p paramref) Eval(w io.Writer, ev *Evaluator) { - t := time.Now() + te := traceEvent.begin("param", p) n := int(p) if n < len(ev.paramVars) { ev.paramVars[n].Eval(w, ev) @@ -186,7 +185,7 @@ func (p paramref) Eval(w io.Writer, ev *Evaluator) { // out of range? // panic(fmt.Sprintf("out of range %d: %d", n, len(ev.paramVars))) } - addStats("param", p, t) + traceEvent.end(te) } func (p paramref) Serialize() SerializableVar { @@ -210,7 +209,7 @@ func (v varsubst) String() string { } func (v varsubst) Eval(w io.Writer, ev *Evaluator) { - t := time.Now() + te := traceEvent.begin("varsubst", v) buf := newBuf() params := ev.args(buf, v.varname, v.pat, v.subst) vname := string(params[0]) @@ -229,7 +228,7 @@ func (v varsubst) Eval(w io.Writer, ev *Evaluator) { io.WriteString(w, substRef(pat, subst, val)) space = true } - addStats("varsubst", v, t) + traceEvent.end(te) } func (v varsubst) Serialize() SerializableVar { @@ -565,7 +564,7 @@ func parseFunc(f Func, in []byte, s int, term []byte, funcName string) (Value, i if compactor, ok := f.(Compactor); ok { fv = compactor.Compact() } - if katiEvalStatsFlag { + if katiEvalStatsFlag || traceEvent.enabled() { fv = funcstats{fv} } return fv, i, nil @@ -580,8 +579,8 @@ type funcstats struct { } func (f funcstats) Eval(w io.Writer, ev *Evaluator) { - t := time.Now() + te := traceEvent.begin("func", f) f.Value.Eval(w, ev) // TODO(ukai): per functype? - addStats("func", f, t) + traceEvent.end(te) } @@ -447,13 +447,13 @@ func (f *funcWildcard) Eval(w io.Writer, ev *Evaluator) { assertArity("wildcard", 1, len(f.args)) abuf := newBuf() f.args[1].Eval(abuf, ev) - t := time.Now() + te := traceEvent.begin("wildcard", tmpval(abuf.Bytes())) if ev.avoidIO && !useWildcardCache { ev.hasIO = true w.Write([]byte("$(/bin/ls -d ")) w.Write(abuf.Bytes()) w.Write([]byte(" 2> /dev/null)")) - addStats("wildcard", tmpval(abuf.Bytes()), t) + traceEvent.end(te) freeBuf(abuf) return } @@ -463,7 +463,7 @@ func (f *funcWildcard) Eval(w io.Writer, ev *Evaluator) { pat := string(ws.Bytes()) wildcard(&sw, pat) } - addStats("wildcard", tmpval(abuf.Bytes()), t) + traceEvent.end(te) freeBuf(abuf) } @@ -721,12 +721,12 @@ func (f *funcShell) Eval(w io.Writer, ev *Evaluator) { abuf := newBuf() f.args[1].Eval(abuf, ev) if ev.avoidIO && !hasNoIoInShellScript(abuf.Bytes()) { - t := time.Now() + te := traceEvent.begin("shell", tmpval(abuf.Bytes())) ev.hasIO = true w.Write([]byte("$(")) w.Write(abuf.Bytes()) w.Write([]byte{')'}) - addStats("shell", tmpval(abuf.Bytes()), t) + traceEvent.end(te) freeBuf(abuf) return } @@ -740,15 +740,15 @@ func (f *funcShell) Eval(w io.Writer, ev *Evaluator) { Args: cmdline, Stderr: os.Stderr, } - t := time.Now() + te := traceEvent.begin("shell", literal(arg)) out, err := cmd.Output() - shellFuncTime += time.Since(t) + shellFuncTime += time.Since(te.t) shellFuncCount++ if err != nil { Logf("$(shell %q) failed: %q", arg, err) } w.Write(formatCommandOutput(out)) - addStats("shell", literal(arg), t) + traceEvent.end(te) } func (f *funcShell) Compact() Value { @@ -37,6 +37,7 @@ var ( cpuprofile string heapprofile string memstats string + traceEventFile string katiStatsFlag bool katiPeriodicStatsFlag bool katiEvalStatsFlag bool @@ -84,6 +85,7 @@ func parseFlags() { flag.StringVar(&cpuprofile, "kati_cpuprofile", "", "write cpu profile to `file`") flag.StringVar(&heapprofile, "kati_heapprofile", "", "write heap profile to `file`") flag.StringVar(&memstats, "kati_memstats", "", "Show memstats with given templates") + flag.StringVar(&traceEventFile, "kati_trace_event", "", "write trace event to `file`") flag.BoolVar(&katiStatsFlag, "kati_stats", false, "Show a bunch of statistics") flag.BoolVar(&katiPeriodicStatsFlag, "kati_periodic_stats", false, "Show a bunch of periodic statistics") flag.BoolVar(&katiEvalStatsFlag, "kati_eval_stats", false, "Show eval statistics") @@ -308,6 +310,14 @@ func main() { fmt.Println(buf.String()) }() } + if traceEventFile != "" { + f, err := os.Create(traceEventFile) + if err != nil { + panic(err) + } + traceEvent.start(f) + defer traceEvent.stop() + } if findCachePrunes != "" { useFindCache = true @@ -16,10 +16,82 @@ package main import ( "fmt" + "io" + "os" "sort" "time" ) +type traceEventT struct { + f io.WriteCloser + t0 time.Time + pid int +} + +var traceEvent traceEventT + +func (t *traceEventT) start(f io.WriteCloser) { + t.f = f + t.t0 = time.Now() + fmt.Fprint(t.f, "[ ") +} + +func (t *traceEventT) enabled() bool { + return t.f != nil +} + +func (t *traceEventT) stop() { + fmt.Fprint(t.f, "\n]\n") + t.f.Close() +} + +type event struct { + name, v string + t time.Time +} + +func (t *traceEventT) begin(name string, v Value) event { + var e event + e.t = time.Now() + if t.f != nil { + emit := name == "include" + if t.pid == 0 { + t.pid = os.Getpid() + } else if emit { + fmt.Fprint(t.f, ",\n") + } + e.name = name + e.v = v.String() + if emit { + ts := e.t.Sub(t.t0) + fmt.Fprintf(t.f, `{"pid":%d,"tid":1,"ts":%d,"ph":"B","cat":%q,"name":%q,"args":{}}`, + t.pid, + ts.Nanoseconds()/1e3, + e.name, + e.v, + ) + } + } + return e +} + +func (t *traceEventT) end(e event) { + if t.f != nil { + now := time.Now() + ts := now.Sub(t.t0) + if e.name == "include" { + fmt.Fprint(t.f, ",\n") + fmt.Fprintf(t.f, `{"pid":%d,"tid":1,"ts":%d,"ph":"E","cat":%q,"name":%q}`, + t.pid, + ts.Nanoseconds()/1e3, + e.name, + e.v, + ) + } + } + addStats(e.name, e.v, e.t) +} + type statsData struct { Name string Count int @@ -29,12 +101,12 @@ type statsData struct { var stats = map[string]statsData{} -func addStats(name string, v Value, t time.Time) { +func addStats(name, v string, t time.Time) { if !katiEvalStatsFlag { return } d := time.Since(t) - key := fmt.Sprintf("%s:%s", name, v.String()) + key := fmt.Sprintf("%s:%s", name, v) s := stats[key] if d > s.Longest { s.Longest = d |