40

How do you time a function in Go and return its runtime in milliseconds?

peterSO
  • 158,998
  • 31
  • 281
  • 276
The Puma
  • 1,352
  • 2
  • 14
  • 27

5 Answers5

38

Go's defer makes this trivial.

In Go 1.x, define the following functions:

func trace(s string) (string, time.Time) {
    log.Println("START:", s)
    return s, time.Now()
}

func un(s string, startTime time.Time) {
    endTime := time.Now()
    log.Println("  END:", s, "ElapsedTime in seconds:", endTime.Sub(startTime))
}

After that, you get Squeaky Clean one line elapsed time log messages:

func someFunction() {
    defer un(trace("SOME_ARBITRARY_STRING_SO_YOU_CAN_KEEP_TRACK"))

    //do a bunch of stuff here...
}

The clever magic is that the trace() is called at the beginning of the function, but the un() is deferred to the end. It's not atomic-clock accurate, due to the log statements, but if you need more accuracy, this kind of pattern is one of Go's marshmallowy good strengths.

EDIT:

This answer originally used legacy time package API. Reproduced here for historical value only:

For use w/ Go versions prior to 12-01-2011 weekly:

func trace(s string) (string, int64) {
    log.Println("START:", s)
    return s, time.Nanoseconds()
}

func un(s string, startTime int64) {
    endTime := time.Nanoseconds()
    log.Println("  END:", s, "ElapsedTime in seconds:", float32(endTime-startTime)/1E9)
}
amattn
  • 10,045
  • 1
  • 36
  • 33
  • 1
    Hat Tip to Noah Heldman for suggesting an edit. Not sure why it was rejected, but will edit shortly. – amattn Jun 07 '13 at 20:50
31

Use the Go testing package to benchmark the function. For example,

package main

import (
    "fmt"
    "testing"
)

// the function to be benchmarked
func Function(n int) int64 {
    n64 := int64(n)
    return n64 * n64
}

func BenchmarkFunction(b *testing.B) {
    n := 42
    for i := 0; i < b.N; i++ {
        _ = Function(n)
    }
}

func main() {
    br := testing.Benchmark(BenchmarkFunction)
    fmt.Println(br)
}

Output:

500000000            4.22 ns/op

You can also use the Go gotest command to run benchmarks.

peterSO
  • 158,998
  • 31
  • 281
  • 276
17

Another easy way can be:

import (
    "fmt"
    "time"
)

start := time.Now()
// some computation
elapsed := time.Since(start)
fmt.Println(elapsed)

which will output something like 359.684612ms

Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
12

Perhaps you can also use a Duration (elapsed) for this...looks a little bit nicer.

func trace(s string) (string, time.Time) {
    log.Printf("trace start: %s\n", s)
    return s, time.Now()
}

func un(s string, startTime time.Time) {
    elapsed := time.Since(startTime)
    log.Printf("trace end: %s, elapsed %f secs\n", s, elapsed.Seconds())
}
Lian
  • 307
  • 3
  • 3
1

There are several options for timestamping and timers in the time package. See the documentation here: http://golang.org/pkg/time/

TJD
  • 11,800
  • 1
  • 26
  • 34
  • I've seen that documentation, but there are no examples with it used. Would I just go `timer := timer.Time() then timer.Stop()`? That doesn't seem to work. And how do I access the time in milliseconds? – The Puma Dec 02 '11 at 02:04