系统诊断小技巧(12):如何确定线程是否因CPU资源波动

简介:

引子

线程可能因为CPU资源不足或者因为--比如等待网络数据--而波动。这在监控上来看,就是业务波动了。但是确定这一点并不容易。

第一个难点是现场难抓。如果是CPU打满或者负载很高,现场复现了,但是可能捕捉数据的线程没有机会执行。如何解决这个问题我们在另一个小技巧中讨论了,这里略过。

第二个难点是使用什么数据来确定线程因为CPU资源波动了。下面我们展开讨论下。

vruntime

Linux 2.6.33引入了CFS调度器task_strcut也因之加了sched_entity结构。sched_entity结构有一个字段是我们感兴趣的:vruntime

struct sched_entity {
    /* For load-balancing: */
    struct load_weight        load;
    unsigned long            runnable_weight;
    struct rb_node            run_node;
    struct list_head        group_node;
    unsigned int            on_rq;

    u64                exec_start;
    u64                sum_exec_runtime;
    u64                vruntime; // 我们要使用的字段
    u64                prev_sum_exec_runtime;

    u64                nr_migrations;

    struct sched_statistics        statistics;

#ifdef CONFIG_FAIR_GROUP_SCHED
    int                depth;
    struct sched_entity        *parent;
    /* rq on which this entity is (to be) queued: */
    struct cfs_rq            *cfs_rq;
    /* rq "owned" by this entity/group: */
    struct cfs_rq            *my_q;
#endif

#ifdef CONFIG_SMP
    /*
     * Per entity load average tracking.
     *
     * Put into separate cache line so it does not
     * collide with read-mostly values above.
     */
    struct sched_avg        avg;
#endif
};

vruntime代表的是什么呢?内核文档是这么说的

In CFS the virtual runtime is expressed and tracked via the per-task
p->se.vruntime (nanosec-unit) value. This way, it's possible to accurately

timestamp and measure the "expected CPU time" a task should have gotten.

[ small detail: on "ideal" hardware, at any time all tasks would have the same

p->se.vruntime value --- i.e., tasks would execute simultaneously and no task
would ever get "out of balance" from the "ideal" share of CPU time. ]

CFS's task picking logic is based on this p->se.vruntime value and it is thus

very simple: it always tries to run the task with the smallest p->se.vruntime
value (i.e., the task which executed least so far). CFS always tries to split
up CPU time between runnable tasks as close to "ideal multitasking hardware" as
possible.

Most of the rest of CFS's design just falls out of this really simple concept,

with a few add-on embellishments like nice levels, multiprocessing and various
algorithm variants to recognize sleepers.

简单说,vruntime代表了线程已经消耗的处理器时间。在理想的硬件上,线程应该有相同的vruntime

这就是我们的依据。

简单实验

测试脚本和压力工具

我们直接让测试脚本打印 vruntime信息。压力工具则是使用perf工具。

测试脚本如下

#!/bin/bash

export LANG=C

for ((i=0;i<10;i++));do
    cat /proc/$$/sched
    sleep 1
done

压力工具用法如下

root@pusf:~ perf bench sched messaging -l 10000

综合起来,我们的测试方法如下

./demo > log/1.log; perf bench sched messaging -l 10000 & sleep 1;./demo > log/2.log

结果分析

我们看下得到的结果

nerd@pusf:/tmp$ egrep vruntime log/{1.log,2.log}
log/1.log:se.vruntime                                  :         22075.635863
log/1.log:se.vruntime                                  :         22076.476482
log/1.log:se.vruntime                                  :         22077.746821
log/1.log:se.vruntime                                  :         22080.537902
log/1.log:se.vruntime                                  :         22084.183713
log/1.log:se.vruntime                                  :         22087.243075
log/1.log:se.vruntime                                  :         22098.180655
log/1.log:se.vruntime                                  :         22099.594014
log/1.log:se.vruntime                                  :         22104.294012
log/1.log:se.vruntime                                  :         22108.701587
log/2.log:se.vruntime                                  :         82731.373434
log/2.log:se.vruntime                                  :         83382.975477
log/2.log:se.vruntime                                  :         78933.644191
log/2.log:se.vruntime                                  :         88235.425663
log/2.log:se.vruntime                                  :         93117.891657
log/2.log:se.vruntime                                  :        101234.834622
log/2.log:se.vruntime                                  :         95899.749367
log/2.log:se.vruntime                                  :        115403.719751
log/2.log:se.vruntime                                  :        124388.997744
log/2.log:se.vruntime                                  :        126752.972070
nerd@pusf:/tmp$

可见,vruntime的区别是显著的。

相关文章
|
1月前
线程CPU异常定位分析
【10月更文挑战第3天】 开发过程中会出现一些CPU异常升高的问题,想要定位到具体的位置就需要一系列的分析,记录一些分析手段。
53 0
|
3月前
|
监控 Java 测试技术
Java并发编程最佳实践:设计高性能的多线程系统
Java并发编程最佳实践:设计高性能的多线程系统
62 1
|
3月前
|
缓存 监控 Linux
在Linux中,如何看当前系统有几颗物理CPU和每颗CPU的核数?
在Linux中,如何看当前系统有几颗物理CPU和每颗CPU的核数?
|
25天前
|
监控 安全 算法
线程死循环确实是多线程编程中的一个常见问题,它可能导致应用程序性能下降,甚至使整个系统变得不稳定。
线程死循环是多线程编程中常见的问题,可能导致性能下降或系统不稳定。通过代码审查、静态分析、日志监控、设置超时、使用锁机制、测试、选择线程安全的数据结构、限制线程数、使用现代并发库及培训,可有效预防和解决死循环问题。
42 1
|
30天前
|
监控 安全 算法
线程死循环是多线程编程中的常见问题,可能导致应用性能下降甚至系统不稳定。
【10月更文挑战第6天】线程死循环是多线程编程中的常见问题,可能导致应用性能下降甚至系统不稳定。为了解决这一问题,可以通过代码审查、静态分析、添加日志监控、设置超时机制、使用锁和同步机制、进行全面测试、选用线程安全的数据结构、限制线程数量、利用现代并发库,并对团队进行培训等方法来预防和减少死循环的发生。尽管如此,多线程编程的复杂性仍需要持续监控和维护以确保系统稳定。
49 3
|
21天前
|
运维 JavaScript Linux
容器内的Nodejs应用如何获取宿主机的基础信息-系统、内存、cpu、启动时间,以及一个df -h的坑
本文介绍了如何在Docker容器内的Node.js应用中获取宿主机的基础信息,包括系统信息、内存使用情况、磁盘空间和启动时间等。核心思路是将宿主机的根目录挂载到容器,但需注意权限和安全问题。文章还提到了使用`df -P`替代`df -h`以获得一致性输出,避免解析错误。
|
3月前
|
监控 Java Linux
CPU被打满/CPU 100%:高效诊断与优化策略
【8月更文挑战第28天】在日常的工作与学习中,遇到CPU使用率飙升至100%的情况时,往往意味着系统性能受到严重影响,甚至可能导致程序响应缓慢或系统崩溃。本文将围绕这一主题,分享一系列高效诊断与优化CPU使用的技术干货,帮助大家快速定位问题并恢复系统性能。
184 1
|
3月前
|
监控 Linux
性能分析之 Linux 系统中 ps&top 中 CPU 百分比不一致?
【8月更文挑战第18天】性能分析之 Linux 系统中 ps&top 中 CPU 百分比不一致?
150 4
|
3月前
|
数据安全/隐私保护 异构计算 Windows
【Azure 环境】 介绍两种常规的方法来监视Window系统的CPU高时的进程信息: Performance Monitor 和 Powershell Get-Counter
【Azure 环境】 介绍两种常规的方法来监视Window系统的CPU高时的进程信息: Performance Monitor 和 Powershell Get-Counter
|
1天前
|
弹性计算 Kubernetes Perl
k8s 设置pod 的cpu 和内存
在 Kubernetes (k8s) 中,设置 Pod 的 CPU 和内存资源限制和请求是非常重要的,因为这有助于确保集群资源的合理分配和有效利用。你可以通过定义 Pod 的 `resources` 字段来设置这些限制。 以下是一个示例 YAML 文件,展示了如何为一个 Pod 设置 CPU 和内存资源请求(requests)和限制(limits): ```yaml apiVersion: v1 kind: Pod metadata: name: example-pod spec: containers: - name: example-container image: