如何测量golang中函数的执行时间,不包括等待时间

时间:2019-05-05 08:16:19

标签: performance go profile goroutine

我需要衡量go中插件的执行时间(cpu成本),我们可以将插件视为函数,可能同时运行许多goroutine。更准确地说,执行时间应排除空闲时间(goroutine等待时间),仅应cpu获取时间(当前goroutine的时间)。 就像:

go func(){
    // this func is a plugin
    ** start to record cpu acquire time of current func/plugin/goroutine **
    ** run code **
    ** stop to record cpu acquire time of current func/plugin/goroutine **
    log.Debugf("This function is buzy for %d millisecs.", cpuAcquireTime)
    ** report cpuAcquirTime to monitor **
}()

在我的情况下,很难进行单元测试来测量功能,很难去耦代码。

我在搜索google和stackoverflow时没有发现任何线索,有什么解决方案可以满足我的需求,并且是否需要太多资源?

2 个答案:

答案 0 :(得分:1)

对于后来像我一样偶然发现此问题的人,您实际上可以使用内置的syscall.Getrusage而不是Cgo。一个例子看起来像

func GetCPU() int64 {
    usage := new(syscall.Rusage)
    syscall.Getrusage(syscall.RUSAGE_SELF, usage)
    return usage.Utime.Nano() + usage.Stime.Nano()
}

我将调用进程(RUSAGE_SELF)的Utime(用户CPU时间)和Stime(系统CPU时间)都转换为纳秒后相加。 man 2 getrusage对此系统调用有更多信息。

syscall.Timeval的文档建议Nano()返回自Unix纪元以来的时间(以纳秒为单位),但是在我的测试和实施中,它看起来实际上仅返回CPU时间(以纳秒为单位),而不是自从Unix时代。

答案 1 :(得分:0)

Go中没有内置的方法来测量CPU时间,但是您可以通过特定于平台的方法来进行测量。

例如,在POSIX系统(例如Linux)上,将 clock_gettime CLOCK_THREAD_CPUTIME_ID 用作参数。

类似地,您可以使用CLOCK_PROCESS_CPUTIME_ID来测量进程CPU时间,并使用CLOCK_MONOTONIC来计算经过时间。

示例:

package main

/*
#include <pthread.h>
#include <time.h>
#include <stdio.h>

static long long getThreadCpuTimeNs() {
    struct timespec t;
    if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t)) {
        perror("clock_gettime");
        return 0;
    }
    return t.tv_sec * 1000000000LL + t.tv_nsec;
}
*/
import "C"
import "fmt"
import "time"

func main() {
    cputime1 := C.getThreadCpuTimeNs()
    doWork()
    cputime2 := C.getThreadCpuTimeNs()
    fmt.Printf("CPU time = %d ns\n", (cputime2 - cputime1))
}

func doWork() {
    x := 1
    for i := 0; i < 100000000; i++ {
        x *= 11111
    }
    time.Sleep(time.Second)
}

输出:

CPU time = 31250000 ns

请注意输出以纳秒为单位。因此,这里的CPU时间为0.03秒。