Is there an efficient way to calculate execution time in golang?

I'm looking for the best way to calculate execution time in go.

func main() {
    start := time.Now()

    time.Sleep(time.Second * 2)

    //something doing here

    elapsed := time.Since(start)
    fmt.Printf("page took %s", elapsed)
}

The code above works fine.

But when I use templates, I have to write it again for each template function.

Is there an efficient way of calculating execution time, including with templates?

Upvotes: 73

Views: 79399

Answers (5)

monkrus
monkrus

Reputation: 1690

Use this as a side reference for an average computation time in Golang (for 10,100,1000 elements accordingly).

  • Accessing an element within an array (1/1/1 sec)
  • Binary/dictionary search (1/2/3 sec)
  • Simple loop/linear search (10/100/1,000 sec)
  • Quick Sort/Merge Sort/Heap Sort/Tim Sort (10/200/3,000 sec)
  • Bubble Sort/Insertion Sort/Selection Sort (100/10,000/1,000,000 sec)

Upvotes: 0

Mohsin Aljiwala
Mohsin Aljiwala

Reputation: 2627

The solution provided by Cerise Limón is perfect.


In addition, if you don't want to pass function name explicitly, you could accomplish it like this:

func SomeFunction(list *[]string) {
    defer TimeTrack(time.Now())
    // Do whatever you want.
}

func TimeTrack(start time.Time) {
    elapsed := time.Since(start)

    // Skip this function, and fetch the PC and file for its parent.
    pc, _, _, _ := runtime.Caller(1)

    // Retrieve a function object this functions parent.
    funcObj := runtime.FuncForPC(pc)

    // Regex to extract just the function name (and not the module path).
    runtimeFunc := regexp.MustCompile(`^.*\.(.*)$`)
    name := runtimeFunc.ReplaceAllString(funcObj.Name(), "$1")

    log.Println(fmt.Sprintf("%s took %s", name, elapsed))
}

As a result, you would get:

SomeFunction took 15.483µs


For more information, Refer this article: Go Function Tracing

Share the knowledge. :)

Upvotes: 34

Thundercat
Thundercat

Reputation: 121119

If you are timing an entire function, then you can use defer to eliminate some of the repetitive code.

// timer returns a function that prints the name argument and 
// the elapsed time between the call to timer and the call to
// the returned function. The returned function is intended to
// be used in a defer statement:
//
//   defer timer("sum")()
func timer(name string) func() {
    start := time.Now()
    return func() {
        fmt.Printf("%s took %v\n", name, time.Since(start))
    }
}

func main() {
    defer timer("main")()  // <-- The trailing () is the deferred call
    time.Sleep(time.Second * 2)
}   // prints: main took 2s

Run the example on the playground.

The specification says this about deferred calls:

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns,

The function value timer("main") is evaluated at the defer statement. The timer function records the current time and returns an anonymous function. The returned anonymous function is invoked immediately before the surrounding function returns. The anonymous function computes and prints the elapsed time.


Use runtime.Callers and runtime.CallersFrames to automatically get the name of the calling function.

// callerName returns the name of the function skip frames up the call stack.
func callerName(skip int) string {
    const unknown = "unknown"
    pcs := make([]uintptr, 1)
    n := runtime.Callers(skip+2, pcs)
    if n < 1 {
        return unknown
    }
    frame, _ := runtime.CallersFrames(pcs).Next()
    if frame.Function == "" {
        return unknown
    }
    return frame.Function
}

// timer returns a function that prints the name of the calling
// function and the elapsed time between the call to timer and
// the call to the returned function. The returned function is
// intended to be used in a defer statement:
//
//   defer timer()()
func timer() func() {
    name := callerName(1)
    start := time.Now()
    return func() {
        fmt.Printf("%s took %v\n", name, time.Since(start))
    }
}

func main() {
    defer timer()()
    time.Sleep(time.Second * 2)
}   // prints: main.main took 2s

Note that there is a runtime cost for getting the function name compared to using a string literal as in the first part of this answer. To avoid measuring the cost of getting the function name, timer gets the name before recording the start time.

Run the example on the playground.

Upvotes: 161

ASHWIN RAJEEV
ASHWIN RAJEEV

Reputation: 2891

Efficient way to calculate execution time in golang

You can easily get the execution time on your console using a defer function

defer functions execute even if the code get an error so you always get the execution time.

time package is used to get the time difference.

func main() {
    now := time.Now()
    defer func() {
        fmt.Println(time.Now().Sub(now))
    }()
        
    // Here you can do whatever you want
}

Or you can use this code

func main() {
        now := time.Now()
        defer func() {
            fmt.Println(time.Since(now))
        }()
            
        // Here you can do whatever you want
    }

check the code in Playground for more. I added some functionality to recover from an error at the same time print the execution time, even if in the case of a panic error.

Upvotes: 4

Uday Hiwarale
Uday Hiwarale

Reputation: 4167

Use init function

package main

import (
    "fmt"
    "time"
)

var start time.Time

func init() {
    start = time.Now()
}

func getChars(s string) {
    for _, c := range s {
        fmt.Printf("%c at time %v\n", c, time.Since(start))
        time.Sleep(10 * time.Millisecond)
    }
}

func main() {
    fmt.Println("main execution started at time", time.Since(start))

    getChars("Hello")

    fmt.Println("\nmain execution stopped at time", time.Since(start))
}

Upvotes: 5

Related Questions