Added initial support for -t flag to show timings (#428)

* Added initial support for -t flag to show timings

Shows very basic timing data for the Dial stage (TLS setup and
BlockingDial) and InvokeRPC method as well as the total time.

* Made timing data part of the very verbose functionality

* cleanup

* fix

---------

Co-authored-by: Scott Blum <dragonsinth@gmail.com>
This commit is contained in:
KaibutsuX 2024-01-23 19:04:51 -05:00 committed by GitHub
parent 334e3f56de
commit 24b80dfed8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 56 additions and 1 deletions

View File

@ -155,7 +155,7 @@ var (
verbose = flags.Bool("v", false, prettify(` verbose = flags.Bool("v", false, prettify(`
Enable verbose output.`)) Enable verbose output.`))
veryVerbose = flags.Bool("vv", false, prettify(` veryVerbose = flags.Bool("vv", false, prettify(`
Enable very verbose output.`)) Enable very verbose output (includes timing data).`))
serverName = flags.String("servername", "", prettify(` serverName = flags.String("servername", "", prettify(`
Override server name when validating TLS certificate. This flag is Override server name when validating TLS certificate. This flag is
ignored if -plaintext or -insecure is used. ignored if -plaintext or -insecure is used.
@ -276,6 +276,32 @@ func (cs compositeSource) AllExtensionsForType(typeName string) ([]*desc.FieldDe
return exts, nil return exts, nil
} }
type timingData struct {
Title string
Start time.Time
Value time.Duration
Parent *timingData
Sub []*timingData
}
func (d *timingData) Child(title string) *timingData {
if d == nil {
return nil
}
child := &timingData{Title: title, Start: time.Now()}
d.Sub = append(d.Sub, child)
return child
}
func (d *timingData) Done() {
if d == nil {
return
}
if d.Value == 0 {
d.Value = time.Since(d.Start)
}
}
func main() { func main() {
flags.Usage = usage flags.Usage = usage
flags.Parse(os.Args[1:]) flags.Parse(os.Args[1:])
@ -361,8 +387,16 @@ func main() {
if *verbose { if *verbose {
verbosityLevel = 1 verbosityLevel = 1
} }
var rootTiming *timingData
if *veryVerbose { if *veryVerbose {
verbosityLevel = 2 verbosityLevel = 2
rootTiming = &timingData{Title: "Timing Data", Start: time.Now()}
defer func() {
rootTiming.Done()
dumpTiming(rootTiming, 0)
}()
} }
var symbol string var symbol string
@ -421,6 +455,8 @@ func main() {
} }
dial := func() *grpc.ClientConn { dial := func() *grpc.ClientConn {
dialTiming := rootTiming.Child("Dial")
defer dialTiming.Done()
dialTime := 10 * time.Second dialTime := 10 * time.Second
if *connectTimeout > 0 { if *connectTimeout > 0 {
dialTime = time.Duration(*connectTimeout * float64(time.Second)) dialTime = time.Duration(*connectTimeout * float64(time.Second))
@ -453,6 +489,9 @@ func main() {
} }
creds = alts.NewClientCreds(clientOptions) creds = alts.NewClientCreds(clientOptions)
} else if usetls { } else if usetls {
tlsTiming := dialTiming.Child("TLS Setup")
defer tlsTiming.Done()
tlsConf, err := grpcurl.ClientTLSConfig(*insecure, *cacert, *cert, *key) tlsConf, err := grpcurl.ClientTLSConfig(*insecure, *cacert, *cert, *key)
if err != nil { if err != nil {
fail(err, "Failed to create TLS config") fail(err, "Failed to create TLS config")
@ -485,6 +524,7 @@ func main() {
if overrideName != "" { if overrideName != "" {
opts = append(opts, grpc.WithAuthority(overrideName)) opts = append(opts, grpc.WithAuthority(overrideName))
} }
tlsTiming.Done()
} else { } else {
panic("Should have defaulted to use TLS.") panic("Should have defaulted to use TLS.")
} }
@ -502,6 +542,8 @@ func main() {
if isUnixSocket != nil && isUnixSocket() { if isUnixSocket != nil && isUnixSocket() {
network = "unix" network = "unix"
} }
blockingDialTiming := dialTiming.Child("BlockingDial")
defer blockingDialTiming.Done()
cc, err := grpcurl.BlockingDial(ctx, network, target, creds, opts...) cc, err := grpcurl.BlockingDial(ctx, network, target, creds, opts...)
if err != nil { if err != nil {
fail(err, "Failed to dial target host %q", target) fail(err, "Failed to dial target host %q", target)
@ -749,7 +791,9 @@ func main() {
VerbosityLevel: verbosityLevel, VerbosityLevel: verbosityLevel,
} }
invokeTiming := rootTiming.Child("InvokeRPC")
err = grpcurl.InvokeRPC(ctx, descSource, cc, symbol, append(addlHeaders, rpcHeaders...), h, rf.Next) err = grpcurl.InvokeRPC(ctx, descSource, cc, symbol, append(addlHeaders, rpcHeaders...), h, rf.Next)
invokeTiming.Done()
if err != nil { if err != nil {
if errStatus, ok := status.FromError(err); ok && *formatError { if errStatus, ok := status.FromError(err); ok && *formatError {
h.Status = errStatus h.Status = errStatus
@ -780,6 +824,17 @@ func main() {
} }
} }
func dumpTiming(td *timingData, lvl int) {
ind := ""
for x := 0; x < lvl; x++ {
ind += " "
}
fmt.Printf("%s%s: %s\n", ind, td.Title, td.Value)
for _, sd := range td.Sub {
dumpTiming(sd, lvl+1)
}
}
func usage() { func usage() {
fmt.Fprintf(os.Stderr, `Usage: fmt.Fprintf(os.Stderr, `Usage:
%s [flags] [address] [list|describe] [symbol] %s [flags] [address] [list|describe] [symbol]