sched_yield 标记为顶级热点

sched_yield flagged as top hotspot

在使用 Vtune 分析程序时,我发现 libc 函数 sched_yield 被标记为重要热点。

现在看到这个函数大概是负责上下文切换的;我说粗略是因为我是第一次遇到这个函数,所以我的理解是它运行在 OS 调度程序内部,以提供对更改活动线程的支持。

sched_yield 作为主要热点对我的程序意味着什么?这是否意味着我创建的线程比我应该创建的多,并且 OS 正在尝试兼顾连续的上下文切换?

对于这种情况,有什么补救措施?也许求助于更集中的线程池来避免过度生成线程?

接下来我应该分析什么?在这种情况下是否有“典型”的后续步骤? Vtune 已经建议 运行 对“线程”的分析。

What does having sched_yield as a major hotspot, mean for my program?

在Linux上,sched_yield不一定切换到另一个线程执行。如果在同一个 CPU 上没有准备好 运行 的线程,内核不会取消调度调用线程。最后一部分很重要,因为内核不会在调用时在 CPU 秒之间重新安排一个准备就绪的 运行 线程。这是一个设计权衡,因为 sched_yield 应该是对内核的低成本提示。

由于 sched_yield 可能会立即 return 而不做任何事情,您的代码可能会围绕此调用进行繁忙循环,这在您的配置文件中看起来像是一个热点。您的代码只是围绕 sched_yield 循环了很多,而没有做太多其他事情。这样的旋转会消耗大量 CPU 周期,这些周期本可以用于系统上的其他线程和应用程序 运行。

What would be a remedy for this situation?

这在很大程度上取决于您的用例。当您愿意浪费一些 CPU 周期来换取更好的延迟时,使用 sched_yield 可能是可以接受的。你必须意识到这个决定,即便如此,我还是建议对不同的解决方案进行基准测试,并使用适当的线程阻塞。 Linux 线程调度程序非常高效,因此阻塞和唤醒线程并不像其他系统那样昂贵。

通常 sched_yield 用于自定义自旋锁算法。我建议用 pthread 组件替换它们,特别是 pthread_cond_t,它允许正确地阻塞和唤醒线程。如果您使用的是 C++,则标准库中有等效项(例如 std::condition_variable). In other cases it may be worth exploring other blocking APIs, such as select and epoll。确切的解决方案取决于您的用例。