golang CPU使用率

Posted

技术标签:

【中文标题】golang CPU使用率【英文标题】:golang CPU usage 【发布时间】:2018-06-18 21:44:14 【问题描述】:

我知道[1]。通过几行代码,我只想从CPU使用率最高的前n个进程中提取当前的CPU使用率。 top 的前 5 行或多或少。使用 github.com/shirou/gopsutil/process 这很简单:

// file: gotop.go
package main

import (
  "log"
  "time"
  "sort"

  "github.com/shirou/gopsutil/process"
)


type ProcInfo struct
  Name  string
  Usage float64
 

type ByUsage []ProcInfo

func (a ByUsage) Len() int       return len(a) 
func (a ByUsage) Swap(i, j int)  a[i], a[j] = a[j], a[i] 
func (a ByUsage) Less(i, j int) bool 
  return a[i].Usage > a[j].Usage



func main() 

  for 
    processes, _ := process.Processes()

    var procinfos []ProcInfo
    for _, p := range processes
      a, _ := p.CPUPercent()
      n, _ := p.Name()
      procinfos = append(procinfos, ProcInfon, a)
    
    sort.Sort(ByUsage(procinfos))

    for _, p := range procinfos[:5]
      log.Printf("   %s -> %f", p.Name, p.Usage)
    
    time.Sleep(3 * time.Second)
  

虽然此实现中的刷新率 gotoptop 一样是 3 秒,但 gotop 大约有 3 秒。像 top 那样获得这些值对 CPU 使用率的要求要高 5 倍。有什么技巧可以更有效地读取 5 个最消耗量的进程吗?我还试图找到 top 的实现,看看那里是如何实现的。

psutils 是造成这种减速的原因吗?我发现在 GO 中也实现了 cpustat。但即使是sudo ./cpustat -i 3000 -s 1 似乎也没有top 高效。

主要动机是通过相当少量的计算工作来监控当前机器的使用情况,以便它可以在后台作为服务运行。

看来,连htop都是only reading/proc/stat

编辑 正如 cmets 中提出的,这里是分析时的结果

Showing top 10 nodes out of 46 (cum >= 70ms)
      flat  flat%   sum%        cum   cum%
      40ms 40.00% 40.00%       40ms 40.00%  syscall.Syscall
      10ms 10.00% 50.00%       30ms 30.00%  github.com/shirou/gopsutil/process.(*Process).fillFromStatusWithContext
      10ms 10.00% 60.00%       30ms 30.00%  io/ioutil.ReadFile
      10ms 10.00% 70.00%       10ms 10.00%  runtime.slicebytetostring
      10ms 10.00% 80.00%       20ms 20.00%  strings.FieldsFunc
      10ms 10.00% 90.00%       10ms 10.00%  syscall.Syscall6
      10ms 10.00%   100%       10ms 10.00%  unicode.IsSpace
         0     0%   100%       10ms 10.00%  bytes.(*Buffer).ReadFrom
         0     0%   100%       70ms 70.00%  github.com/shirou/gopsutil/process.(*Process).CPUPercent
         0     0%   100%       70ms 70.00%  github.com/shirou/gopsutil/process.(*Process).CPUPercentWithContext

似乎系统调用需要很长时间。一个树转储在这里: https://gist.github.com/PatWie/4fa528b7d7b1d0b5c1b665c056671477

这会将问题更改为: - 系统调用是问题吗? - top 程序是否有任何 c 源代码?我刚刚找到了htop的实现 - 有简单的解决方法吗?我考虑用 c 写它,然后把它包装起来。

【问题讨论】:

请对其进行分析,以便我们确定哪个部分是瓶颈。 只是一个想法:top 是一个古老的(阅读:一遍又一遍地优化,即使完全重写,iirc)并用 C 编写(没有 GC 等)。与编程语言一样:Go 对 一些 事物非常有用,而不是对所有事物 我添加了分析的结果。我的结论正确吗?另外,我没有找到top的实现。 看来,golang 确实非常低效,或者至少是库github.com/shirou/gopsutil/process对于我的用例。我最终直接在 c 中实现它并通过 cgo 调用它,请参阅github.com/PatWie/cpuinfo 我搜索了“***源代码”,发现:github.com/torvalds/linux/blob/master/tools/perf/builtin-top.c 【参考方案1】:

github.com/shirou/gopsutil/process 使用ioutil.ReadFile 访问文件系统的效率低于顶部。特别是ReadFile

调用Stat,这会增加一个额外的不必要的系统调用。 使用os.Open 而不是unix.Openat + os.NewFile,这会在解析路径时导致额外的内核时间遍历/procos.NewFile 仍然有点低效,因为它总是检查文件描述符是否是非阻塞的。这可以通过直接使用golang.org/x/sys/unixsyscall 包来避免。

在 Linux 下检索进程详细信息通常效率很低(大量文件系统扫描、编组文本数据)。但是,通过修复文件系统访问(如上所述),您可以使用 Go 实现与 top 类似的性能。

【讨论】:

以上是关于golang CPU使用率的主要内容,如果未能解决你的问题,请参考以下文章

如何减少 golang tcp 服务器中的 cpu 使用率?

Golang的pprof的使用心得(CPU,Heap)

golang中如何将一个进程绑定到一组cpu上?

Golang利用第三方包获取本机cpu使用率以及内存使用情况

为golang程序使用pprof远程查看httpserver运行堆栈,cpu耗时等信息

白话 Golang pprof