我在 Google 云机器上有一个 Centos7 系统,运行一个多线程数据库服务器,该服务器在 70 秒内(正负 1 秒)执行一组特定的查询。我想知道服务器在运行此工作负载时进行了多少次上下文切换。
服务器 pid 是 11850。
我使用了 3 种不同的计数方法:
方法一:
开始
perf -e context-switches -p 11850
在一个窗口中,然后立即在另一个窗口中运行数据库客户端。然后在客户端完成后立即终止 perf。
输出结果为
Performance counter stats for process id '11850':
5,831,206 context-switches # 0.004 M/sec
70.607962486 seconds time elapsed
方法 2
开始
pidstat -tw -p 11850 70 1 >pidstat.out
在一个窗口中并立即在另一个窗口中运行客户端。
pidstat 和客户端将在一秒钟内完成。当这种情况发生时,将 pidstat.out 中的所有 cswch/s 和 nvcswch/s 值相加,并将结果乘以 70。
这给出与方法 1 几乎相同的结果。
方法 3
在一个窗口中运行包含以下命令的脚本
vmstat -s|grep "CPU context switches"
sleep 70
vmstat -s|grep "CPU context switches"
然后立即在另一个窗口中运行客户端。客户端和第二个 vmstat 将在一秒钟内完成。
vmstat 输出如下
439394923 CPU context switches
450457926 CPU context switches
用第二个数字减去第一个数字得出的结果为 11,063,003,几乎是其他两种方法结果的两倍。
由于系统上没有运行其他任何程序,并且空闲系统上的上下文切换的正常速率约为 100/秒,因此 vmstat 方法似乎对上下文切换进行了双重计算。
这是一个错误,还是我遗漏了什么?
答案1
需要检查的是,只有被检查的 PID 才能进行上下文切换这一假设。
检查所有 CPU 上的上下文切换,例如perf top -e context-switches -a
。您可能会看到其他任务(包括其他数据库线程和内核任务)在 CPU 上跳转和退出。
比上下文切换计数器更有用每周期指令数等统计数据。获得那些perf stat
。好的 IPC 大于 1。当然,对于 CPU 受限的工作负载。缓慢的存储意味着 CPU 永远等待。
答案2
如果你想获取进程内的上下文切换次数,你可以查看GetRUsage 系统调用。
例如,在 Golang 中:
var usage syscall.Rusage
if err := syscall.Getrusage(syscall.RUSAGE_SELF, &usage); err != nil {
fmt.Printf("Error: unable to gather resource usage data: %v\n", err)
}