Perf stat以什么方式计算上下文切换?



perf stat显示了一些有趣的统计数据,这些数据可以通过检查硬件和软件计数器收集到。在我的研究中,我找不到任何关于perf stat中什么算是上下文切换的可靠信息。尽管我很努力,我还是无法完全理解内核代码。假设我的ib网络应用程序在事件模式下调用阻塞read系统调用2000次,perf stat计数1,241个上下文切换。上下文切换指的是计划入进程或计划出进程,还是两者都指?

__schedule()函数(kernel/sched/core.c)将switch_count计数器加1,每当prev != nextperf stats的上下文切换似乎包括非自愿切换和自愿切换。

在我看来,只有当当前上下文运行调度代码并增加task_struct中的nvcswnivcsw计数器时,才会计算取消调度事件。

perf stat -- my_application输出:

1,241      context-switches                            

同时,如果我只计算sched:sched_switch事件,输出将接近预期的数字。

perf stat -e sched:sched_switch -- my_application的输出:

2,168      sched:sched_switch                                          

context-switchessched_switch-事件有区别吗?

我认为只有当一个不同的任务实际运行在一个正在运行你的一个线程的核心上时,你才能得到context-switches的计数。如果read()阻塞,但在任何其他任务的用户空间代码在核心上运行之前恢复,则可能不会计数。

仅仅为了系统调用而进入内核显然是不算数的;对于我来说,perf stat ls只计算较大目录中的一个上下文切换,如果我将ls用于较小的目录(如/),则为零。我得到了更高的计数,比如我最近没有访问过的目录的递归ls711。因此,它花费了大量时间等待I/O,并且可能运行下半段中断处理程序。

计数可以是奇数,这意味着它不会分别计算取消调度和重新调度;由于我正在查看最终退出的单线程进程的计数,如果它同时计数两个进程,则计数必须是偶数。

我期望计数完成时,schedule()决定current应该改变指向一个新的任务,而不是这个。(current是Linux内核的每核变量,指向当前任务的task_struct,例如用户空间线程。)因此,每当进程中的线程发生这种情况时,您将获得1个计数。

的确,OP帮助我们找到了源代码;在__schedulekernel/sched/core.c中。例如在Linux 6.1

static void __sched notrace __schedule(unsigned int sched_mode)
{
struct task_struct *prev, *next;
unsigned long *switch_count;
// and some other declarations I omitted
...
cpu = smp_processor_id();
rq = cpu_rq(cpu);   // stands for run queue
prev = rq->curr;
...
switch_count = &prev->nivcsw;        // either Num InVoluntary CSWs I think
...
if (!(sched_mode & SM_MASK_PREEMPT) && prev_state) {
...
switch_count = &prev->nvcsw;     // or     Num Voluntary CSWs
}
next = pick_next_task(rq, prev, &rf);
...
if (likely(prev != next)) {
...
++*switch_count;        //// INCREMENT THE SELECTED COUNTER
...
trace_sched_switch(sched_mode & SM_MASK_PREEMPT, prev, next, prev_state);
// then make some function calls to actually do the context switch 
...
}

我猜context-switchesperf事件汇总了线程的非自愿和自愿切换。(假设这就是nvniv的含义)

相关内容

  • 没有找到相关文章

最新更新