Add some performance tracing to the scanner

This commit is contained in:
rubyist 2014-10-05 09:35:26 -04:00
parent 084655b60b
commit d68ae591f0
4 changed files with 60 additions and 12 deletions

@ -18,6 +18,10 @@ tracerx.DefaultKey = "FOO"
tracerx.Printf("send message") tracerx.Printf("send message")
tracerx.PrintfKey("BAR", "do a thing") tracerx.PrintfKey("BAR", "do a thing")
t := time.Now()
// Do some stuff
tracerx.PerformanceSince("BAR", "command x", t)
``` ```
This example will send tracing output based on the environment variables `FOO_TRACE` and `BAR_TRACE`. This example will send tracing output based on the environment variables `FOO_TRACE` and `BAR_TRACE`.
@ -31,6 +35,9 @@ absolute path: output will be written to the file
3 - 10: output will be written to that file descriptor 3 - 10: output will be written to that file descriptor
``` ```
If an associated `BAR_TRACE_PERFORMANCE` is set to 1 or "true", the `PerformanceSince` line will
output timing information.
Keys can also be disabled. See the GoDoc for full API documentation. Keys can also be disabled. See the GoDoc for full API documentation.
## Bugs, Issues, Feedback ## Bugs, Issues, Feedback

@ -14,6 +14,9 @@
// By default, messages will be prefixed with "trace: ". This prefix can be // By default, messages will be prefixed with "trace: ". This prefix can be
// modified by setting Prefix. // modified by setting Prefix.
// //
// Each key can have an associated performance key, e.g. TRACERX_TRACE_PERFORMANCE.
// If this key is 1 or "true" performance output will be written to the same output
// as the tracing output.
package tracerx package tracerx
import ( import (
@ -24,6 +27,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time"
) )
var ( var (
@ -34,8 +38,9 @@ var (
) )
type tracer struct { type tracer struct {
enabled bool enabled bool
w io.Writer performance bool
w io.Writer
} }
// Printf writes a trace message for the DefaultKey // Printf writes a trace message for the DefaultKey
@ -45,19 +50,30 @@ func Printf(format string, args ...interface{}) {
// PrintfKey writes a trace message for the given key // PrintfKey writes a trace message for the given key
func PrintfKey(key, format string, args ...interface{}) { func PrintfKey(key, format string, args ...interface{}) {
uppedKey := strings.ToUpper(key) tracer := getTracer(key)
tracer, ok := tracers[uppedKey]
if !ok {
tracer = initializeTracer(uppedKey)
}
if tracer.enabled { if tracer.enabled {
fmt.Fprintf(tracer.w, Prefix+format+"\n", args...) fmt.Fprintf(tracer.w, Prefix+format+"\n", args...)
return return
} }
} }
// PerformanceSince writes out the time since the given time, if
// tracing for the default key is enabled and the performance key is set
func PerformanceSince(what string, t time.Time) {
PerformanceSinceKey(DefaultKey, what, t)
}
// PerformanceSince writes out the time since the given time, if
// tracing for the given key is enabled and the performance key is set
func PerformanceSinceKey(key, what string, t time.Time) {
tracer := getTracer(key)
if tracer.enabled && tracer.performance {
since := time.Since(t)
fmt.Fprintf(tracer.w, "performance %s: %.9f s\n", what, since.Seconds())
}
}
// Disable will disable tracing for the given key, regardless of // Disable will disable tracing for the given key, regardless of
// the environment variable // the environment variable
func Disable(key string) { func Disable(key string) {
@ -76,15 +92,24 @@ func Enable(key string) {
} }
} }
func getTracer(key string) *tracer {
uppedKey := strings.ToUpper(key)
tracer, ok := tracers[uppedKey]
if !ok {
tracer = initializeTracer(uppedKey)
}
return tracer
}
func initializeTracer(key string) *tracer { func initializeTracer(key string) *tracer {
tracerLock.Lock() tracerLock.Lock()
defer tracerLock.Unlock() defer tracerLock.Unlock()
if tracer, ok := tracers[key]; ok { if tracer, ok := tracers[key]; ok {
return tracer return tracer // Someone else initialized while we were blocked
} }
tracer := &tracer{false, os.Stderr} tracer := &tracer{false, false, os.Stderr}
tracers[key] = tracer tracers[key] = tracer
trace := os.Getenv(fmt.Sprintf("%s_TRACE", key)) trace := os.Getenv(fmt.Sprintf("%s_TRACE", key))
@ -92,6 +117,11 @@ func initializeTracer(key string) *tracer {
return tracer return tracer
} }
perf := os.Getenv(fmt.Sprintf("%s_TRACE_PERFORMANCE", key))
if perf == "1" || strings.ToLower(perf) == "true" {
tracer.performance = true
}
fd, err := strconv.Atoi(trace) fd, err := strconv.Atoi(trace)
if err != nil { if err != nil {
// Not a number, it could be a path for a log file // Not a number, it could be a path for a log file

2
Godeps

@ -6,4 +6,4 @@ github.com/olekukonko/ts ecf753e7c962639ab5a1fb46f7da627d4c
github.com/spf13/cobra 864687ae689edc28688c67edef47e3d2ad651a1b github.com/spf13/cobra 864687ae689edc28688c67edef47e3d2ad651a1b
github.com/spf13/pflag 463bdc838f2b35e9307e91d480878bda5fff7232 github.com/spf13/pflag 463bdc838f2b35e9307e91d480878bda5fff7232
github.com/technoweenie/go-contentaddressable 38171def3cd15e3b76eb156219b3d48704643899 github.com/technoweenie/go-contentaddressable 38171def3cd15e3b76eb156219b3d48704643899
github.com/rubyist/tracerx ecd28355a866ec2378f6df7d7cbf231141720e13 github.com/rubyist/tracerx b869498bff1ad54bb2df3b98d11f3b6dcefbddc6

@ -4,7 +4,9 @@ import (
"bytes" "bytes"
"github.com/github/git-media/git" "github.com/github/git-media/git"
"github.com/github/git-media/pointer" "github.com/github/git-media/pointer"
"github.com/rubyist/tracerx"
"strconv" "strconv"
"time"
) )
type ScannedPointer struct { type ScannedPointer struct {
@ -17,14 +19,19 @@ func Scan(ref string) ([]*ScannedPointer, error) {
// Gets all objects git knows about // Gets all objects git knows about
var buf bytes.Buffer var buf bytes.Buffer
t := time.Now()
objects, _ := git.RevListObjects(ref, "", ref == "") objects, _ := git.RevListObjects(ref, "", ref == "")
tracerx.PerformanceSince("rev-list --objects", t)
for _, o := range objects { for _, o := range objects {
fileNameMap[o.Sha1] = o.Name fileNameMap[o.Sha1] = o.Name
buf.WriteString(o.Sha1 + "\n") buf.WriteString(o.Sha1 + "\n")
} }
// Get type and size info for all objects // Get type and size info for all objects
t = time.Now()
objects, _ = git.CatFileBatchCheck(&buf) objects, _ = git.CatFileBatchCheck(&buf)
tracerx.PerformanceSince("cat-file --batch-check", t)
// Pull out git objects that are type blob and size < 200 bytes. // Pull out git objects that are type blob and size < 200 bytes.
// These are the likely git media pointer files // These are the likely git media pointer files
@ -40,11 +47,14 @@ func Scan(ref string) ([]*ScannedPointer, error) {
// <sha1> <type> <size><LF> // <sha1> <type> <size><LF>
// <contents><LF> // <contents><LF>
// This string contains all the data, so we parse it out below // This string contains all the data, so we parse it out below
t = time.Now()
data, _ := git.CatFileBatch(&mediaObjects) data, _ := git.CatFileBatch(&mediaObjects)
tracerx.PerformanceSince("cat-file --batch", t)
r := bytes.NewBufferString(data) r := bytes.NewBufferString(data)
pointers := make([]*ScannedPointer, 0) pointers := make([]*ScannedPointer, 0)
t = time.Now()
for { for {
l, err := r.ReadBytes('\n') l, err := r.ReadBytes('\n')
if err != nil { // Probably check for EOF if err != nil { // Probably check for EOF
@ -73,5 +83,6 @@ func Scan(ref string) ([]*ScannedPointer, error) {
break break
} }
} }
tracerx.PerformanceSince("decode pointers", t)
return pointers, nil return pointers, nil
} }