diff options
Diffstat (limited to 'golang/kati/stats.go')
| -rw-r--r-- | golang/kati/stats.go | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/golang/kati/stats.go b/golang/kati/stats.go new file mode 100644 index 0000000..a8ea461 --- /dev/null +++ b/golang/kati/stats.go @@ -0,0 +1,200 @@ +// Copyright 2015 Google Inc. All rights reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package kati + +import ( + "fmt" + "io" + "os" + "sort" + "sync" + "time" +) + +type traceEventT struct { + mu sync.Mutex + f io.WriteCloser + t0 time.Time + pid int +} + +const ( + traceEventMain = iota + 1 + // add new ones to use new goroutine. +) + +var traceEvent traceEventT + +// TraceEventStart starts trace event. +func TraceEventStart(f io.WriteCloser) { + traceEvent.start(f) +} + +// TraceEventStop stops trace event. +func TraceEventStop() { + traceEvent.stop() +} + +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 + tid int + t time.Time + emit bool +} + +func (t *traceEventT) begin(name string, v Value, tid int) event { + var e event + e.tid = tid + e.t = time.Now() + if t.f != nil || EvalStatsFlag { + e.name = name + e.v = v.String() + } + if t.f != nil { + e.emit = name == "include" || name == "shell" + if e.emit { + t.emit("B", e, e.t.Sub(t.t0)) + } + } + return e +} + +func (t *traceEventT) emit(ph string, e event, ts time.Duration) { + t.mu.Lock() + defer t.mu.Unlock() + + if t.pid == 0 { + t.pid = os.Getpid() + } else { + fmt.Fprintf(t.f, ",\n") + } + fmt.Fprintf(t.f, `{"pid":%d,"tid":%d,"ts":%d,"ph":%q,"cat":%q,"name":%q,"args":{}}`, + t.pid, + e.tid, + ts.Nanoseconds()/1e3, + ph, + e.name, + e.v, + ) +} + +func (t *traceEventT) end(e event) { + if t.f != nil { + if e.emit { + t.emit("E", e, time.Since(t.t0)) + } + } + stats.add(e.name, e.v, e.t) +} + +type statsData struct { + Name string + Count int + Longest time.Duration + Total time.Duration +} + +type statsT struct { + mu sync.Mutex + data map[string]statsData +} + +var stats = &statsT{ + data: make(map[string]statsData), +} + +func (s *statsT) add(name, v string, t time.Time) { + if !EvalStatsFlag { + return + } + d := time.Since(t) + key := fmt.Sprintf("%s:%s", name, v) + s.mu.Lock() + sd := s.data[key] + if d > sd.Longest { + sd.Longest = d + } + sd.Total += d + sd.Count++ + s.data[key] = sd + s.mu.Unlock() +} + +// DumpStats dumps statistics collected if EvalStatsFlag is set. +func DumpStats() { + if !EvalStatsFlag { + return + } + var sv byTotalTime + for k, v := range stats.data { + v.Name = k + sv = append(sv, v) + } + sort.Sort(sv) + fmt.Println("count,longest(ns),total(ns),longest,total,name") + for _, s := range sv { + fmt.Printf("%d,%d,%d,%v,%v,%s\n", s.Count, s.Longest, s.Total, s.Longest, s.Total, s.Name) + } +} + +type byTotalTime []statsData + +func (b byTotalTime) Len() int { return len(b) } +func (b byTotalTime) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byTotalTime) Less(i, j int) bool { + return b[i].Total > b[j].Total +} + +type shellStatsT struct { + mu sync.Mutex + duration time.Duration + count int +} + +var shellStats = &shellStatsT{} + +func (s *shellStatsT) add(d time.Duration) { + s.mu.Lock() + s.duration += d + s.count++ + s.mu.Unlock() +} + +func (s *shellStatsT) Duration() time.Duration { + s.mu.Lock() + defer s.mu.Unlock() + return s.duration +} + +func (s *shellStatsT) Count() int { + s.mu.Lock() + defer s.mu.Unlock() + return s.count +} |
