Linux工具学习

linux内核追踪系统

在这里插入图片描述

在这里插入图片描述

linux内核动态追踪技术:

事件源 (Event Source)

1、 硬件事件

  • 性能监控计数器PMCS

    场景如下:
    (1) 追踪CPU缓存
    (2) 追踪指令周期
    (3) 分支预测等事关硬件性能情况

2、静态探针 (实现在代码中定义好,并编译到应用程序或内核中的探针)

  • 追踪点(tracepoints)

    实现方式:
    (1) printfk – 最经典使用的方式,手动埋点编译内核,debuglevel控制输出
    (2) 内核函数
    (3) 内核trace event等

  • USDT探针(User Statically-Defined Tracing)

    USDT 探针,全称是用户级静态定义跟踪,需要在源码中插入DTRACE_PROBE()代码,并编译到应用程序中。

3、动态探针

  • kprobes
    kprobes主要用来对内核进行调试追踪,属于比较轻量级的机制,本质上是在指定的探测点(比如函数的某行,函数的入口地址和出口地址,或者内核的指定地址处)插入一组处理程序.内核执行到这组处理程序的时候就可以获取到当前正在执行的上下文信息,比如当前的函数名,函数处理的参数以及函数的返回值,也可以获取到寄存器甚至全局数据结构的信息。

    用法:

    (1) kprobes是可以被插入到内核的任何指令位置的探测点
    (2) jprobes则只能被插入到一个内核函数的入口
    (3) kretprobes则是在指定的内核函数返回时才被执行

    实现:

    (1) 通过编写内核模块的方式向内核注册探测点(可插拔方式注入探测点)
    (2) kprobes on ftrace

    场景:

    (1) 某个内核函数是否被调用到?
    (2) 内核函数耗时分析
    (3) 注入BUG修复代码,相当于内核补丁

  • uprobes
    uprobes用来跟踪用户态的函数,包括用于函数调用的uprobe和用于函数返回的 uretprobe。

追踪框架(Tracing Frameworks)

在这里插入图片描述

  • ftrace
    可消费事件源:

    tracepoints, kprobes, and uprobes;
    依赖debugfs;
    依赖debugfs;

    前端工具:

    /sys/kernel/debug/tracing
    trace-cmd(上面的简化版)
    perf-tools(perf-tools是ftrace和perf_event的包装器)

  • perf(perf_event)
    可消费事件源:

    tracepoints, kprobes, and uprobes等;可以完成ftrace的大部分功能。
    但是不能做函数遍历(函数调用的层级),比ftrace更安全,支持采样;支持自定义动态事件;

    场景:

    (1) 寻找热点函数,定位性能瓶颈
    (2) perf可以用来分析CPU cache、CPU迁移、分支预测、指令周期等各种硬件事件
    (3) perf 也可以只对感兴趣的事件进行动态追踪

    工具用法:

    –event: 在perf的各个子命令中添加- -event选项,设置追踪感兴趣的事件。
    perf list: 查询支持的事件,类似/sys/kernel/debug/tracing/available_events的输出实测发现,perf支持的事件要比ftrace多一倍左右。

  • eBPF
    eBPF是一个内核虚拟机,可在events上高效地运行programs;支持常用的事件追踪;

    eBPF允许在Linux上执行自定义分析程序来处理事件,包括dynamic tracing, static tracing, and profiling events

    前端工具:

    bcc工具包 (核心开发语言C,前端为python和lua)
    bpftrace(与上面相比,不需要写代码,通过配置就能实现)

  • SystemTap
    最强大的追踪程序;自己写脚本,由stap编译为驱动并插入内核,几乎可做任何事情,但不太安全;

  • sysdig
    使用类似tcpdump的语法和lua后处理操作系统调用事件;
    还可以通过eBPF来进行扩展,所以,也可以用来追踪内核中的各种函数和事件。

一、linux下性能调优工具OProfile和perf

OProfile 已经存在了几十年,有一段时间是在基于 Linux的系统上进行性能分析的主力军,今天也可以发挥同样的作用。但是,OProfile 不包含在 Red Hat Enterprise Linux (RHEL) 8 beta 中,因此 OProfile 用户开始考虑替代工具可能是谨慎的。在功能、易用性和社区活力方面与OProfile 相比非常有利的类似项目如perf命令。

OProfile 和perf当前在 Linux 内核中使用相同的基本机制来启用事件跟踪:perf_events 基础结构。虽然它主要是一个用户空间工具,perf但从开发的角度来看,该命令是 Linux 内核的一部分,作为 Linux 内核的一部分有优点也有缺点。一个可能的优势是代码更容易维护,因为代码库不会随着时间的推移而分崩离析。一个缺点是版本perf在很大程度上与 Linux 内核的版本有内在联系:获得新功能perf通常意味着获得新内核。

1.1 OProfile

1.1.1 OProfile介绍

OProfile是用于Linux的若干种评测和性能监控工具中的一种,它可以工作在不同的体系结构上,包括MIPS、ARM、IA32、IA64和AMD。
同时OProfile是Linux平台上的一个功能强大的性能分析工具,支持两种采样(sampling)方式:基于事件的采样(eventbased)和基于时间的采样(timebased)。

基于事件的采样是OProfile只记录特定事件(比如L2 cache miss)的发生次数,当达到用户设定的定值时OProfile就记录一下(采一个样)。这种方式需要CPU内部有性能计数器(performace counter)。

基于时间的采样是oProfile借助OS时钟中断的机制,每个时钟中断OProfile都会记录一次(采一次样),引入此种采样方式的目的在于提供对没有性能计数器的CPU的支持,其精度相对于基于事件的采样要低。因为要借助OS时钟中断的支持,对禁用中断的代码OProfile不能对其进行分析。

oProfile在Linux上分两部分,一个是内核模块(oprofile.ko),一个为用户空间的守护进程(oprofiled)。前者负责访问性能计数器或者注册基于时间采样的函数(使用register_timer_hook注册之,使时钟中断处理程序最后执行profile_tick时可以访问之),并采样置于内核的缓冲区内。后者在后台运行,负责从内核空间收集数据,写入文件。

1.1.2 安装OProfile

http://oprofile.sourceforge.net/download/

./configure make & sudo make install
  • ERROR1:configure:error:popt library not found

    下载popt-1.16,下载地址:https://www.linuxfromscratch.org/blfs/view/svn/general/popt.html

    ./configure make & sudo make install
    
  • ERROR2:configure:error: liberty library not found
    下载binutils-2.25,下载地址:http://ftp.gnu.org/gnu/binutils/?C=M;O=D

    ./configure make & sudo make install
    

1.3 使用OProfile

(1) OProfile使用流程
1. opcontrol --init
2. opcontrol --no-vmlinux
3. opcontrol --start
4. ./your_app
5. opcontrol --dump
6. opcontrol --stop
7. opreport -l ./your_app
(2) oprofile初始化
opcontrol --init

该命令会加载oprofile.ko模块,mount oprofilefs。成功后会在/dev/oprofile/目录下导出
一些文件和目录如: cpu_type, dump, enable, pointer_size, stats/

(3) 配置

主要设置计数事件和样本计数,以及计数的CPU模式(用户态、核心态)

opcontrol --vmlinux=/boot/vmlinux-`uname -r` # 监控内核及驱动模块
opcontrol --no-vmlinux # 不监控内核及驱动模块

设置计数事件为CYCLES,即对处理器时钟周期进行计数样本计数为1000,即每1000个时钟周期,oprofile 取样一次。处理器运行于核心态则不计数,运行于用户态则计数。

opcontrol --setup --event=CYCLES:1000::0:1
(4) 清除会话中的数据
opcontrol --reset # 清除当前会话中的数据
(5) oprofile启动监控
opcontrol --start
opcontrol --start-daemon;opcontrol --start # 轻量级,减少启动守护进程对测试结果的影响
(6) 运行测试程序
./test
(7) oprofile停止监控

运行完成后,停止oprofile数据的收集。

opcontrol --stop # 停止监控
opcontrol --shutdown # 停止监控,并结束监控进程(监控的数据默认保存在/var/lib/oprofile/samples)
(8) 查看报告
opreport -l # 如果需要保存信息,可以重定向到文件中,比如opreport -l > 1.txt
(9) 卸载模块
opcontrol --deinit  # 卸载模块

1.2 perf

1.2.1 perf介绍

Perf是Linux内核自带的系统性能优化工具,原理是:CPU的PMU registers(性能监控单元寄存器)中Get/Set performance counters来获得诸如instructions executed, cache-missed suffered, branches mispredicted(预测失准的分枝)等信息。

通过Perf,应用程序可以利用 PMU,tracepoint 和内核中的特殊计数器来进行性能统计。使用 perf可以分析程序运行期间发生的硬件事件,比如 cache miss等;也可以分析软件事件,比如 page fault 和进程切换。

1)PMU:性能监控单元(Performance Monitor Unit), CPU提供的一个性能监视单元,用于统计CPU性能数据;
2)Tracepoint:散落在内核源代码中的一些 hook,它们可以在特定的代码被运行到时被触发,这一特性可以被各种 trace/debug 工具所使用。
3)内核运行状态计数,例如: 1) 进程切换 2) Page fault 3) 中断计数

Perf的基本原理就是对被监测对象进行采样,在采样点里判断程序当时的上下文。假如一个程序 90% 的时间都花费在函数 foo() 上,那么 90% 的采样点都应该落在函数 foo() 的上下文中。运气不可捉摸,但若想只要采样频率足够高,采样时间足够长,那么以上推论就比较可靠。因此,通过 TIck 触发采样,我们便可以了解程序中哪些地方最耗时间,从而重点分析。

Perf是运行在用户态,它通过RingBuffer数据结构(覆盖方式)与内核态进行交互,每次woken up的时候就是在读RingBuffer中的数据

Perf的使用流程和OProfile很像。所以如果你会用OProfile的话,用Perf就很简单。

1.2.2 安装perf

sudo apt install linux-tools-common

在这里插入图片描述

sudo apt install linux-tools-5.4.0-58-generic
sudo apt install linux-cloud-tools-5.4.0-58-generic

1.2.3 使用perf

(1) Perf事件处理常用的参数:

record : 记录到文件perf.data
report: 读取perf.data并以CUI方式展示
stat :统计事件个数
script:脚本自定义处理
trace : live输出事件(strace) ==> (比ptrace更高效的机制)
probe :自定义软件事件
top:类似top命令
list :列出事件
perf record后会将数据保存到perf.data中

perf stat 不会收集数据,只是展示出来通用事件

(2) 实例代码

#include<stdio.h>

 void longa() 
 { 
   int i,j; 
   for(i = 0; i < 1000000; i++) 
   j=i; //am I silly or crazy? I feel boring and desperate. 
 } 
 
 void foo2() 
 { 
   int i; 
   for(i=0 ; i < 10; i++) 
        longa(); 
 } 
 
 void foo1() 
 { 
   int i; 
   for(i = 0; i< 100; i++) 
      longa(); 
 } 
 
 int main(void) 
 { 
   foo1(); 
   foo2(); 
   return 0;
 }
(3) record 记录到perf.data文件
gcc -o test -g test.c 

带上-g选项,加入调试和符号表信息。

sudo perf record -e cycles ./test

带上-e cycles可以不加默认是给我们加上的
在这里插入图片描述
perf唤醒内核1次去写(通过信号),与内核交互的ringbuffer交互次数为1次。

perf report

在这里插入图片描述
进入可以看到函数的用时占比

在这里插入图片描述

(4) stat统计事件个数
sudo perf stat ./test

将通用的事件展示出来

Performance counter stats for './test':

            403.33 msec task-clock                #    0.985 CPUs utilized          
                20      context-switches          #    0.050 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                45      page-faults               #    0.112 K/sec                  
   <not supported>      cycles                                                      
   <not supported>      instructions                                                
   <not supported>      branches                                                    
   <not supported>      branch-misses                                               

       0.409406795 seconds time elapsed

       0.380006000 seconds user
       0.024000000 seconds sys

(5) probe自定义软件事件

在test中加入一个probe,在longa函数上。可以统计调用longa调用的次数

sudo perf probe -x ./test longa

在这里插入图片描述

sudo perf record -e probe_test:longa ./test

此时的事件-e就不是cycles了,指定的是probe_test

sudo perf report

可以看到有110个事件
在这里插入图片描述

也可以通过-d参数删除事件

sudo perf probe -d longa # 删除这个事件,才能再次运行

在这里插入图片描述

(6) script 查看调用详细的次数
sudo perf script # 可以看到调用输出的次数

可以看到函数调用的次数。
在这里插入图片描述

sudo perf stat -e probe_test:longa ./test

在使用前面用的stat命令,可以看到直接输出了调用次数
在这里插入图片描述

二、/proc/cpuinfo文件使用

2.1 /proc/cpuinfo涉及的内容介绍

在linux系统中,提供了/proc目录下文件,显示系统的软硬件信息。如果想了解系统中CPU的提供商和相关配置信息,则可以查/proc/cpuinfo。但是此文件输出项较多,不易理解。例如我们想获取,有多少颗物理CPU,每个物理cpu核心数,以及超线程是否开启等信息。

使用cat /proc/cpuinfo可以查看到cpu的信息:

processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 61
model name	: Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz
stepping	: 4
microcode	: 0x2d
cpu MHz		: 2196.822
cache size	: 3072 KB
physical id	: 0
siblings	: 2
core id		: 0
cpu cores	: 2
apicid		: 0
initial apicid	: 0
fpu		: yes
fpu_exception	: yes
cpuid level	: 20
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single pti ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap xsaveopt arat md_clear flush_l1d arch_capabilities
bugs		: cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit srbds
bogomips	: 4393.64
clflush size	: 64
cache_alignment	: 64
address sizes	: 43 bits physical, 48 bits virtual
power management:

其中关键字表示的意思如下:

processor :系统中逻辑处理核心数的编号,从0开始排序。

vendor_id :CPU制造商

cpu family :CPU产品系列代号

model   :CPU属于其系列中的哪一代的代号

model name:CPU属于的名字及其编号、标称主频

stepping  :CPU属于制作更新版本

cpu MHz  :CPU的实际使用主频

cache size :CPU二级缓存大小

physical id :单个物理CPU的标号

siblings :单个物理CPU的逻辑CPU数。siblings=cpu cores [*2]。

core id :当前物理核在其所处CPU中的编号,这个编号不一定连续。

cpu cores :该逻辑核所处CPU的物理核数。比如此处cpu cores 是4个,那么对应core id 可能是 1、3、4、5。

apicid :用来区分不同逻辑核的编号,系统中每个逻辑核的此编号必然不同,此编号不一定连续

fpu :是否具有浮点运算单元(Floating Point Unit)

fpu_exception :是否支持浮点计算异常

cpuid level :执行cpuid指令前,eax寄存器中的值,根据不同的值cpuid指令会返回不同的内容

wp :表明当前CPU是否在内核态支持对用户空间的写保护(Write Protection)

flags :当前CPU支持的功能

bogomips:在系统内核启动时粗略测算的CPU速度(Million Instructions Per Second

clflush size :每次刷新缓存的大小单位

cache_alignment :缓存地址对齐单位

address sizes :可访问地址空间位数

power management :对能源管理的支持

2.2 快速的查看具体的内容

  • 查询系统有几颗物理CPU:

    cat  /proc/cpuinfo | grep "physical id" |sort |uniq
    
  • 查询系统每颗物理CPU的核心数

    cat /proc/cpuinfo | grep "cpu cores" | uniq
    
  • 查询系统的每颗物理CPU核心是否启用超线程技术。

    如果启用此技术那么,每个物理核心又可分为两个逻辑处理器。

    cat /proc/cpuinfo | grep -e "cpu cores"  -e "siblings" | sort | uniq
    

    如果cpu cores数量和siblings数量一致,则没有启用超线程,否则超线程被启用。
    在这里插入图片描述

  • 查询系统具有多少个逻辑CPU

    cat /proc/cpuinfo | grep "processor" | wc -l
    

三、Top工具使用

3.1 top命令介绍

top 命令是 Linux 系统下常用的系统监控工具,通过 top 命令我们可以获取到系统动态运行的信息,包括内存使用情况,系统负载情况,进程的运行情况等等。

3.2 top命令用法

使用top命令后,可以在界面进行交互操作,参数h可以看到帮助命令
在这里插入图片描述
-d:number代表秒数,表示top命令显示的页面更新一次的间隔。默认是5秒。要手动刷新,用户可以输入回车或者空格

-b:以批次的方式执行top。
-n:与-b配合使用,表示需要进行几次top命令的输出结果,到达指定次数后 top 退出

top 命令的批处理模式(Batch-mode)可以区别于正常使用的交互模式(Interactive-mode),在批处理模式下top 只会不断打印系统状态,无法接受其他交互模式下的命令。如果配合-n 选项指定刷新次数的话,可以通过批处理模式将系统状态不断打印到日志中,实现实时监控的效果。

-p:指定特定的pid进程号进行观察。

-u: user 只显示指定用户启动的进程
示例: top -u root(只显示以root用户启动的进程)

-B:重要内容加粗

-H:切换到线程状态

-k:结束指定进程

-m:切换内存使用量的显示样式

-e:调整内存的计量单位

F:命令指定字段过滤
在这里插入图片描述
通过选中MEM字段右移调序到CPU上面后,优先以MEM排序;
通过空格可以选择是否显示该字段

-c:切换是否显示进程启动时的完整路径和程序名。

-o:命令执行过滤
命令的格式如下:

<!> <字段名称> <操作符> <包含值/排除值>

支持>,<,=这三类操作符

例子:显示PID>100的可以使用PID>100或者!PID<100
通过COMMAND=top,可以查看到top进程
在这里插入图片描述

使用 Ctrl+o 显示当前生效的过滤器
使用 =重置当前窗口的过滤器
使用 +重置全部窗口的过滤器

3.3 top界面参数说明

3.3.1 top前五行信息说明

top - 22:33:04 up 2 min,  1 users,  load average: 0.85, 0.62, 0.25
Tasks: 155 total,   2 running, 153 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3.4 us,  1.4 sy,  0.0 ni, 95.2 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  2967536 total,  2249804 free,   303732 used,   414000 buff/cache
KiB Swap:  4194300 total,  4194300 free,        0 used.  2509432 avail Mem 

前五行是系统整体的统计信息。
第一行是任务队列信息,同 uptime 命令的执行结果。含义如下:

22:39:11当前时间
up 8 min系统运行时间
1 user当前登录用户数
load average: 0.00, 0.17, 0.16系统负载,即任务队列的平均长度。 三个数值分别为 1分钟、5分钟、15分钟前到现在的平均值。top - 22:33:04 up 2 min, 2 users, load average: 0.85, 0.62, 0.25

第二、三行为进程和CPU的信息。当有多个CPU时,这些内容可能会超过两行。
第二行内容及含义如下:

Tasks: 155 total,   2 running, 153 sleeping,   0 stopped,   0 zombie
内容含义
total进程总数
running正在运行的进程数
sleeping睡眠的进程数
stopped停止的进程数
zombie僵尸进程数

第三行内容及含义如下:(可以按1查看所有CPU的信息)

%Cpu(s):  3.4 us,  1.4 sy,  0.0 ni, 95.2 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
内容含义
us用户空间占用CPU百分比
sy内核空间占用CPU百分比
ni用户进程空间内改变过优先级的进程占用CPU百分比
id空闲CPU百分比
wa等待输入输出的CPU时间百分比
hi硬中断(Hardware IRQ)占用CPU的百分比
si软中断(Software Interrupts)占用CPU的百分比
st(Steal time) 是当 hypervisor 服务另一个虚拟处理器的时候,虚拟 CPU 等待实际 CPU 的时间的百分比。

最后两行为内存信息。
第四行的内容及含义如下:

KiB Mem :  2967536 total,  2249804 free,   303732 used,   414000 buff/cache
内容含义
KiB Mem使用的物理内存总量
used使用的内存总量
buff/cache用作内核缓存的内存量

第五行的内容及含义如下:

KiB Swap:  4194300 total,  4194300 free,        0 used.  2509432 avail Mem
内容含义
KiB Swap交换区总量
avail Mem代表可用于进程下一次分配的物理内存数量

上表中的缓冲交换区总量含义为:内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖,该数值即为这些内容已存在于内存中的交换区的大小。相应的内存再次被换出时可不必再对交换区写入

3.3.2 进程信息说明

列名含义
PID进程id
PPID父进程id
RUSERReal user name
UID进程所有者的用户id
USER进程所有者的用户名
GROUP进程所有者的组名
TTY启动进程的终端名。不是从终端启动的进程则显示为 ?
PR优先级
NInice值,负值表示高优先级,正值表示低优先级
P最后使用的CPU,仅在多CPU环境下有意义
%CPU上次更新到现在的CPU时间占用百分比
TIME进程使用的CPU时间总计,单位秒
TIME+进程使用的CPU时间总计,单位1/100秒
%MEN进程使用的物理内存百分比
VIRT进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
SWAP进程使用的虚拟内存中,被换出的大小,单位kb
RES进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
CODE可执行代码占用的物理内存大小,单位kb
DATA可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb
SHR共享内存大小,单位kb
nFLT页面错误次数
nDRT最后一次写入到现在,被修改过的页面数。
S进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
COMMAND命令名/命令行
WCHAN若该进程在睡眠,则显示睡眠中的系统函数名
Flags任务标志

四、vmstat使用

4.1 vmstat介绍

vmstat是Virtual Meomory Statistics(虚拟内存统计)的缩写,可对操作系统的虚拟内存、进程、CPU活动进行监控。

vmstat是对系统的整体情况进行统计,相比于top命令是无法对某个进程进行深入分析。

vmstat 工具提供了一种低开销的系统性能观察方式。因为 vmstat 本身就是低开销工具,在非常高负荷的服务器上,你需要查看并监控系统的健康情况,在控制窗口还是能够使用vmstat 输出结果

4.2 命令参数介绍

(1) vmstat [options] [delay [count]]

其中不带options只有delay一集count则如下:
vmstat 1 3 代表1s收集一次,收集三次,没有count则一直按照delay收集。
在这里插入图片描述
常用的OPTIONS如下:

(2) -a: 查看内存的active和inactive

vmstat -a

(3) -f: 查看系统已经fork了多少次

vmstat -f

这个数据是从/proc/stat中的processes字段里取得的

(4) -s: 查看内存使用的详细信息

vmstat -s

2006960 K total memory
      1066488 K used memory
       586192 K active memory
       811164 K inactive memory
        82216 K free memory
       236672 K buffer memory
       621584 K swap cache

      8787964 K total swap
       279268 K used swap
      8508696 K free swap
        65379 non-nice user cpu ticks
       794744 nice user cpu ticks
       240195 system cpu ticks
      3190159 idle cpu ticks
         3553 IO-wait cpu ticks
            0 IRQ cpu ticks
         6492 softirq cpu ticks
            0 stolen cpu ticks
      3888549 pages paged in
      1053420 pages paged out
         7942 pages swapped in
        78605 pages swapped out
      4567257 interrupts
      2767542 CPU context switches
   1655110598 boot time
         4533 forks

这些信息的分别来自于/proc/meminfo,/proc/stat和/proc/vmstat

(5) -d: 查看内存的读写

vmstat -d
在这里插入图片描述

merged:表示一次来自于合并的写/读请求,一般系统会把多个连接/邻近的读/写请求合并到一起来操作

(6) -p: 查看具体磁盘的读/写

vmstat -p /dev/sda1
在这里插入图片描述

reads:来自于这个分区的读的次数.
read sectors:来自于这个分区的读扇区的次数.
writes:来自于这个分区的写的次数.
requested writes:来自于这个分区的写请求次数.

与-d命令一样,这些信息来自:/proc/diskstats。

(7) -S: 指定单位显示

-S:使用指定单位显示。参数有 k 、K 、m 、M ,分别代表1000、1024、1000000、1048576字节(byte)。默认单位为K(1024 bytes)
在这里插入图片描述

(8) -m: 显示slabinfo

在这里插入图片描述
来自 /proc/slabinfo

(9) -n: 只在开始显示一次字段名称

4.3 参数含义介绍

FIELD DESCRIPTION FOR VM MODE
   Procs # 进程
       r: The number of runnable processes (running or waiting for run time). 
       # r:等待执行的任务数 含义:展示了正在执行和等待cpu资源的任务个数。当这个值超过了cpu个数,就会出现cpu瓶颈。
       b: The number of processes in uninterruptible sleep.
       # b:等待IO的进程数量

   Memory
       swpd: the amount of virtual memory used.
       # swpd:正在使用虚拟的内存大小,单位k
       free: the amount of idle memory.
       # free:空闲内存大小
       buff: the amount of memory used as buffers.
       # buff:已用的buff大小,对块设备的读写进行缓冲
       cache: the amount of memory used as cache.
       # cache:已用的cache大小,文件系统的cache
       inact: the amount of inactive memory.  (-a option)
       # 非活跃内存大小,即被标明可回收的内存,区别于free和active(当使用-a选项时显示)
       active: the amount of active memory.  (-a option)
       # active:活跃的内存大小(当使用-a选项时显示)
   Swap
       si: Amount of memory swapped in from disk (/s).
       # si:每秒从交换区写入内存的大小(单位:kb/s)
       so: Amount of memory swapped to disk (/s).
       # so:每秒从内存写到交换区的大小
   IO
       bi: Blocks received from a block device (blocks/s).
       # bi:每秒读取的块数(读磁盘)
       bo: Blocks sent to a block device (blocks/s).
       # bo:每秒写入的块数(写磁盘)

   System
       in: The number of interrupts per second, including the clock.
       # in:每秒中断数,包括时钟中断
       cs: The number of context switches per second.
	   # cs:每秒上下文切换数;秒上下文切换次数,例如我们调用系统函数,
	   # 就要进行上下文切换线程的切换,也要进程上下文切换,这个值要越
	   # 小越好,太大了,要考虑调低线程或者进程的数目。
   # in和cs这两个值越大,会看到由内核消耗的cpu时间sy会越多
   
   CPU
       These are percentages of total CPU time.
       us: Time spent running non-kernel code.  (user time, including nice time)
       # us:用户进程执行消耗cpu时间(user time);us的值比较高时,说
       # 明用户进程消耗的cpu时间多,但是如果长期超过50%的使用,那么我
       # 们就该考虑优化程序算法或其他措施了
       sy: Time spent running kernel code.  (system time)
       # sy:系统进程消耗cpu时间(system time),sys的值过高时,说明系统
       # 内核消耗的cpu资源多,这个不是良性的表现,我们应该检查原因。这里
       # us + sy的参考值为80%,如果us+sy 大于 80%说明可能存在CPU不足
       id: Time spent idle.  Prior to Linux 2.5.41, this includes IO-wait time.
       # id:空闲时间(包括IO等待时间),一般来说 us+sy+id=100
       wa: Time spent waiting for IO.  Prior to Linux 2.5.41, included in idle.
       # wa:等待IO时间,wa过高时,说明io等待比较严重,这可能是由于磁盘大
       # 量随机访问造成的,也有可能是磁盘的带宽出现瓶颈。
       st: Time stolen from a virtual machine.  Prior to Linux 2.6.11, unknown.
       # st:代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间

五、free工具使用

5.1 free介绍

查看内存是否存在瓶颈,使用top指令看比较麻烦,而free命令更为直观。free命令可以显示Linux系统中空闲的、已用的物理内存及swap内存,及被内核使用的buffer。
在这里插入图片描述

在这里插入图片描述
其中参数与top一样

total:总内存大小。
used:已经使用的内存大小(这里面包含cached和buffers和shared部分)。
free:空闲的内存大小。
shared:进程间共享内存(一般不会用,可以忽略)。
buffers:内存中写完的东西缓存起来,这样快速响应请求,后面数据再定期刷到磁盘上。
cached:内存中读完缓存起来内容占的大小(这部分是为了下次查询时快速返回)。

5.2 命令参数介绍

-b: 以Byte为单位显示内存使用情况。
-k: 以KB为单位显示内存使用情况。
-m: 以MB为单位显示内存使用情况。
-g: 以GB为单位显示内存使用情况。
-h: 根据内存大小自动选择合适的单位显示
-o: 不显示缓冲区调节列。
-s: <间隔秒数>  持续观察内存使用状况。
-c: <显示次数> 和-s配合使用
-t: 显示内存总和列。

六、/cpu/meminfo

6.1 /cpu/meminfo介绍

/proc/meminfo是了解Linux系统内存使用状况的主要接口,我们最常用的”free”、”vmstat”等命令就是通过它获取数据的 ,/proc/meminfo所包含的信息比”free”等命令要丰富得多

负责输出/proc/meminfo的源代码是:
fs/proc/meminfo.c : meminfo_proc_show()

cat /proc/meminfo得到:

MemTotal:        2006960 kB
MemFree:          163468 kB
MemAvailable:     713260 kB
Buffers:          212512 kB
Cached:           432348 kB
SwapCached:         6644 kB
Active:           603872 kB
Inactive:         691688 kB
Active(anon):     323396 kB
Inactive(anon):   341636 kB
Active(file):     280476 kB
Inactive(file):   350052 kB
Unevictable:          16 kB
Mlocked:              16 kB
SwapTotal:       8787964 kB
SwapFree:        8509208 kB
Dirty:               208 kB
Writeback:             0 kB
AnonPages:        645072 kB
Mapped:           172928 kB
Shmem:             15500 kB
KReclaimable:     101472 kB
Slab:             183640 kB
SReclaimable:     101472 kB
SUnreclaim:        82168 kB
KernelStack:       12768 kB
PageTables:        42388 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     9791444 kB
Committed_AS:    4707140 kB
VmallocTotal:   34359738367 kB
VmallocUsed:       30348 kB
VmallocChunk:          0 kB
Percpu:            46080 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
FileHugePages:         0 kB
FilePmdMapped:         0 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
DirectMap4k:      288640 kB
DirectMap2M:     1808384 kB
DirectMap1G:           0 kB

6.2 /cpu/meminfo得到的参数含义

  • MemTotal: 所有内存(RAM)大小,减去一些预留空间和内核的大小。
    系统从加电开始到引导完成,firmware/BIOS要保留一些内存,kernel本身要占用一些内存,最后剩下可供kernel支配的内存就是MemTotal。这个值在系统运行期间一般是固定不变的。
    在这里插入图片描述
    内核所用内存的静态部分,比如内核代码、页描述符等数据在引导阶段就分配掉了,并不计入MemTotal里,而是算作reserved因此total-reserved = 2096628-138012=1958616

  • MemFree: 完全没有用到的物理内存,lowFree+highFree

  • MemAvailable: 在不使用交换空间的情况下,启动一个新的应用最大可用内存的大小
    有些应用程序会根据系统的可用内存大小自动调整内存申请的多少,所以需要一个记录当前可用内存数量的统计值,MemFree并不适用,因为MemFree不能代表全部可用的内存,系统中有些内存虽然已被使用但是可以回收的,比如cache/buffer、slab都有一部分可以回收,所以这部分可回收的内存加上MemFree才是系统可用的内存,即MemAvailable。计算方式:MemFree+Active(file)+Inactive(file)-(watermark+min(watermark,Active(file)+Inactive(file)/2)),这个值是一个估计值。

  • Buffers: 块设备所占用的缓存页,包括:直接读写块设备以及文件系统元数据(metadata),比如superblock使用的缓存页。它与“Cached”的区别在于,”Cached”表示普通文件所占用的缓存页。FREE命令显示的BUFFERS与CACHED的区别

  • Cached: 表示普通文件数据所占用的缓存页。
    Page Cache里包括所有file-backed pages,统计在/proc/meminfo的”Cached”中。
    “Cached”和”SwapCached”两个统计值是互不重叠的,Shared memory和tmpfs在不发生swap-out的时候属于”Cached”,而在swap-out/swap-in的过程中会被加进swap cache中、属于”SwapCached”,一旦进了”SwapCached”,就不再属于”Cached”了。

  • SwapCached: swap cache中包含的是被确定要swapping换页,但是尚未写入物理交换区的匿名内存页。那些匿名内存页,比如用户进程malloc申请的内存页是没有关联任何文件的,如果发生swapping换页,这类内存会被写入到交换区。

    匿名页(anonymous pages)要用到交换区,而shared memory和tmpfs虽然未统计在AnonPages里,但它们背后没有硬盘文件,所以也是需要交换区的。也就是说需要用到交换区的内存包括:”AnonPages”和”Shmem”

  • Active: active包含active anon和active file

  • Inactive: inactive包含inactive anon和inactive file

  • Active(anon): anonymous pages(匿名页),用户进程的内存页分为两种:
    (1) 与文件关联的内存页(比如程序文件,数据文件对应的内存页);
    (2) 与内存无关的内存页(比如进程的堆栈,用malloc申请的内存;
    其中,(1)称为file pages或mappedpages,(2)称为匿名页。

  • Inactive(anon): 见上

  • Active(file): 见上

  • Inactive(file): 见上

  • Unevictable:不能被释放的内存页

  • Mlocked:系统调用 mlock

  • SwapTotal: 可用的swap空间的总的大小(swap分区在物理内存不够的情况下,把硬盘空间的一部分释放出来,以供当前程序使用)

  • SwapFree: 当前剩余的swap的大小

  • Dirty: 需要写入磁盘的内存去的大小

  • Writeback: 正在被写回的内存区的大小

  • AnonPages: 未映射页的内存的大小Mapped: 设备和文件等映射的大小
    前面提到用户进程的内存页分为两种:file-backed pages(与文件对应的内存页),和anonymous pages(匿名页)

  • Mapped:用户进程的file-backed pages就对应着/proc/meminfo中的”Mapped”
    Page cache中(“Cached”)包含了文件的缓存页,其中有些文件当前已不在使用,page cache仍然可能保留着它们的缓存页面;而另一些文件正被用户进程关联,比如shared libraries、可执行程序的文件、mmap的文件等,这些文件的缓存页就称为mapped。

  • Shmem:
    Shmem统计的内容包括:shared memory与tmpfs
    其中shared memory又包括:
    SysV shared memory [shmget etc.]
    POSIX shared memory [shm_open etc.]
    shared anonymous mmap [ mmap(…MAP_ANONYMOUS|MAP_SHARED…)]

    因为shared memory在内核中都是基于tmpfs实现的,也就是说它们被视为基于tmpfs文件系统的内存页,既然基于文件系统,就不算匿名页,所以不被计入/proc/meminfo中的AnonPages,而是被统计进了:
    Cached (i.e. page cache)
    Mapped (当shmem被attached时候)
    然而它们背后并不存在真正的硬盘文件,一旦内存不足的时候,它们是需要交换区才能swap-out的,所以在LRU lists里,它们被放在:Inactive(anon) 或 Active(anon)
    注:虽然它们在LRU中被放进了anon list,但是不会被计入 AnonPages。

  • Slab: 内核数据结构slab的大小
    通过slab分配的内存被统计在以下三个值中:

    SReclaimable: slab中可回收的部分。调用kmem_getpages()时加上SLAB_RECLAIM_ACCOUNT标记,表明是可回收的,计入SReclaimable,否则计入SUnreclaim。
    SUnreclaim: slab中不可回收的部分。
    slab中所有的内存,等于以上两者之和

  • SReclaimable: 可回收的slab的大小

  • SUnreclaim: 不可回收的slab的大小

  • KernelStack:内核栈
    每一个用户线程都会分配一个kernel stack(内核栈),内核栈虽然属于线程,但用户态的代码不能访问,只有通过系统调用(syscall)、自陷(trap)或异常(exception)进入内核态的时候才会用到,也就是说内核栈是给kernel code使用的。

    Kernel stack(内核栈)是常驻内存的,既不包括在LRU lists里,也不包括在进程的RSS(实际使用物理内存,包含共享库占用的内存)/PSS(实际使用的物理内存,比例分配共享库占用的内存)内存里,所以我们认为它是kernel消耗的内存。
    另外还有USS(进程独自占用的物理内存) 以及VSS(虚拟耗用内存,包含共享库占用的内存)。与RSS相比,PSS会更准确一些,它将共享内存的大小进行平均后,再分摊到各进程上去。USS则是PSS中自己的部分,它只计算了进程独自占用的内存大小,不包含任何共享的部分。
    通常VSS >= RSS >= PSS >= USS。

  • PageTables(页表): 管理内存页页面的大小
    page table(页表)是操作系统上的虚拟内存系统的数据结构模型,用于存储虚拟地址与物理地址的对应关系,随着内存地址分配得越来越多,Page Table会增大。。当我们访问内存时,首先访问”page table“,然后Linux在通过“page table”的mapping来访问真实物理内存(ram+swap)

    物理内存的最小单位是page frame,每个物理页对应一个描述符(struct page),在内核的引导阶段就会分配好、保存在mem_map[]数组中,mem_map[]所占用的内存被统计在dmesg显示的reserved中,/proc/meminfo的MemTotal是不包含它们的。

  • NFS_Unstable: 不稳定页表的大小

  • Bounce:在低端内存中分配一个临时buffer作为跳转,把位于高端内存的缓存数据复制到此处消耗的内存
    有些老设备只能访问低端内存,比如16M以下的内存,当应用程序发出一个I/O 请求,DMA的目的地址却是高端内存时(比如在16M以上),内核将在低端内存中分配一个临时buffer作为跳转,把位于高端内存的缓存数据复制到此处。这种额外的数据拷贝被称为“bounce buffering”,会降低I/O 性能。大量分配的bounce buffers 也会占用额外的内存。

  • WritebackTmp:FUSE用于临时写回缓冲区的内存

  • CommitLimit:系统实际可分配内存

  • Committed_AS:系统当前已分配的内存

  • VmallocTotal: Vmalloc内存区的大小,预留的虚拟内存总量

  • VmallocUsed: 已用Vmalloc内存区的大小,已经被使用的虚拟内存
    通过vmalloc分配的内存都统计在/proc/meminfo的 VmallocUsed 值中,但是要注意这个值不止包括了分配的物理内存,还统计了VM_IOREMAP、VM_MAP等操作的值,譬如VM_IOREMAP是把IO地址映射到内核空间、并未消耗物理内存,所以我们要把它们排除在外。从物理内存分配的角度,我们只关心VM_ALLOC操作,这可以从/proc/vmallocinfo中的vmalloc记录看到。

  • VmallocChunk: vmalloc区可分配的最大的逻辑连续的虚拟内存

  • HardwareCorrupted:表示“中毒页面”中的内存量
    当系统检测到内存的硬件故障时,会把有问题的页面删除掉,不再使用,/proc/meminfo中的HardwareCorrupted统计了删除掉的内存页的总大小。相应的代码参见 mm/memory-failure.c: memory_failure()

  • HugePages_Total:
    hugepage是在Linux2.6内核被引入的,主要提供4k的page和比较大的page的选择。

    HugePages_Total 对应内核参数 vm.nr_hugepages,也可以在运行中的系统上直接修改 /proc/sys/vm/nr_hugepages,修改的结果会立即影响空闲内存 MemFree的大小,因为HugePages在内核中独立管理,只要一经定义,无论是否被使用,都不再属于free memory。

    在Linux中,内存都是以页的形式划分的,默认情况下每页是4K,这就意味着如果物理内存很大,则映射表的条目将会非常多,会影响CPU的检索效率。因为内存大小是固定的,为了减少映射表的条目,可采取的办法只有增加页的尺寸。
    Hugepage可以有效的减少PageTable的大小,节约系统内存,降低TLB的搜索开销。另外由于Hugepage是不能swap的,因此把共享内存放入Hugepage在系统内存出现换页的时候不用担心共享内存被换页。

    用户程序在申请Hugepages的时候,其实是reserve了一块内存,并未真正使用,此时/proc/meminfo中的 HugePages_Rsvd 会增加,而 HugePages_Free 不会减少。

  • HugePages_Free: 0 //池中尚未分配的HugePages 数量, 真正空闲的页数等于HugePages_Free - HugePages_Rsvd

  • HugePages_Rsvd: 0 //表示池中已经被应用程序分配但尚未使用的 HugePages 数量

  • HugePages_Surp: 0 //这个值得意思是当开始配置了20个大页,现在修改配置为16,那么这个参数就会显示为4,一般不修改配置,这个值都是0

  • Hugepagesize: 2048 kB //大内存页的size

  • AnonHugePages
    AnonHugePages统计的是Transparent HugePages (THP,透明大页),THP与Hugepages不是一回事,区别很大。
    为什么使用transparent HugePages存在风险
    Huge pages (标准大页)和 Transparent Huge pages(透明大页)

  • CmaTotal: 0 kB //连续内存区管理总量

  • CmaFree: 0 kB //连续内存区管理空闲量

  • ShmemHugePages: 0 kB //用于共享内存的大页

  • ShmemPmdMapped: 0 kB

七、sar工具学习

7.1 sar介绍

sar(System Activity Reporter)作为Linux上最为全面的系统性能分析工具之一,可以从多方面对系统的活动进行报告,包括:文件的读写情况、系统调用的使用情况、磁盘I/O、CPU效率、内存使用状况、进程活动及IPC有关的活动等。

7.2 安装sar

apt-get install sysstat

修改配置文件将false改为true
修改配置文件:vi /etc/default/sysstat在这里插入图片描述
重启服务

service sysstat restart

在这里插入图片描述

7.3 sar命令参数

常用参数格式:
sar [options] [-o file] t [n]

(1) -u 统计CPU的使用情况

1 3代表t [n] ,1s刷新一次统计3次
在这里插入图片描述

%user 用户空间的CPU使用
%nice 改变过优先级的进程的CPU使用率
%system 内核空间的CPU使用率
%iowait CPU等待IO的百分比
%steal 虚拟机的虚拟机CPU使用的CPU
%idle 空闲的CPU

(2) -P 查看每一个CPU的使用情况

在这里插入图片描述

想要查看某一个核的信息:

sar -P CPU_NUM 1 1  

(3) -r 查看内存使用情况

在这里插入图片描述

kbmemfree 空闲的物理内存大小
kbmemused 使用中的物理内存大小
memused 物理内存使用率
kbbuffers 内核中作为缓冲区使用的物理内存大小
kbbuffers和kbcached:这两个值就是free命令中的buffer和cache.
kbcommit 保证当前系统正常运行所需要的最小内存,即为了确保内存不溢出而需要的最少内存(物理内存+Swap分区)
%commit 这个值是kbcommit与内存总量(物理内存+swap分区)的一个百分比的值

(4) -q 查看平均负载

在这里插入图片描述

runq-sz 运行队列的长度(等待运行的进程数,每核的CP不能超过3个)
plist-sz 进程列表中的进程(processes)和线程数(threads)的数量
ldavg-1 最后1分钟的CPU平均负载,即将多核CPU过去一分钟的负载相加再除以核心数得出的平均值,5分钟和15分钟以此类推
ldavg-5 最后5分钟的CPU平均负载
ldavg-15 最后15分钟的CPU平均负载

(5) -W 查看交换区统计信息

-W

pswpin/pswpout是指虚拟内存中,从块设备swap区中读入/读出的页数

(6) -v inode、文件和其他内核表监控

在这里插入图片描述

dentunusd:目录高速缓存中未被使用的条目数量
file-nr:文件句柄(file handle)的使用数量
inode-nr:索引节点句柄(inode handle)的使用数量
pty-nr:使用的pty数量

(7) -B 内存分页监控

在这里插入图片描述

pgpgin/s:表示每秒从磁盘或SWAP置换到内存的字节数(KB)
pgpgout/s:表示每秒从内存置换到磁盘或SWAP的字节数(KB)
fault/s:每秒钟系统产生的缺页数,即主缺页与次缺页之和(major + minor)
majflt/s:每秒钟产生的主缺页数.
pgfree/s:每秒被放入空闲队列中的页个数
pgscank/s:每秒被kswapd扫描的页个数
pgscand/s:每秒直接被扫描的页个数
pgsteal/s:每秒钟从cache中被清除来满足内存需要的页个数
%vmeff:每秒清除的页(pgsteal)占总扫描页(pgscank+pgscand)的百分比

(8) -b I/O和传送速率监控

在这里插入图片描述

tps:每秒钟物理设备的 I/O 传输总量
rtps:每秒钟从物理设备读入的数据总量
wtps:每秒钟向物理设备写入的数据总量
bread/s:每秒钟从物理设备读入的数据量,单位为 块/s
bwrtn/s:每秒钟向物理设备写入的数据量,单位为 块/s

(9) -d 磁盘使用情况

在这里插入图片描述

DEV 磁盘设备名称
tps:每秒I/O的传输总数,每秒从物理磁盘I/O的次数。多个逻辑请求会被合并为一个I/O磁盘请求,一次传输的大小是不确定的。
rkB/s:每秒读总数量(KB单位)
wkB/s:每秒写总数量(KB单位)
areq-sz:平均每次I/O操作的数据大小(KB单位)
aqu-sz:磁盘请求队列的平均长度
await 从请求磁盘操作到系统完成处理,每次请求的平均消耗时间,包括请求队列等待时间,单位是毫秒(1秒=1000毫秒)。
svctm:系统处理每次请求的平均时间,不包括在请求队列中消耗的时间。
%util:I/O请求占用的CPU时间百分比,当%util的值接近 100% 时,表示设备带宽已经占满

还可以加上参数-p可以打印出sda,hdc等磁盘设备名称,如果不用参数-p,设备节点则有可能是dev7-0,dev8-0
在这里插入图片描述

(10) -n 统计网络信息

sar -n { DEV | EDEV | NFS | NFSD | SOCK | ALL } 
  • -DEV
    在这里插入图片描述

    IFACE 本地网卡接口的名称
    rxpck/s 每秒钟接受的数据包
    txpck/s 每秒钟发送的数据包
    rxkB/s 每秒钟接受的数据包大小,单位为KB
    txkB/s 每秒钟发送的数据包大小,单位为KB
    rxcmp/s 每秒钟接受的压缩数据包
    txcmp/s 每秒钟发送的压缩包
    rxmcst/s 每秒钟接收的多播数据包

  • -SOCK
    在这里插入图片描述

    totsck 当前被使用的socket总数
    tcpsck 当前被使用的TCP socket总数
    udpsck 当前被使用的UDP socket总数
    rawsck 当前处于RWA状态的socket总数
    ip-frag 当前ip分配的数目
    tcp-tw TCP套接字中处于TIME_WAIT状态的连接总数

(11) -o、-f 保存到文件以及从文件中读取

在这里插入图片描述

(12) 使用参数总结

怀疑CPU存在瓶颈,可用 sar -u 和 sar -q 等来查看
怀疑内存存在瓶颈,可用 sar -B、sar -r 和 sar -W 等来查看
怀疑I/O存在瓶颈,可用 sar -b、sar -u 和 sar -d 等来查看

八、iotop命令

8.1 iotop介绍

iotop 是一个类似 top 的工具,用来显示实时的磁盘活动。Linux下的IO统计工具如iostat,nmon等大多数是只能统计到per设备的读写情况。iotop 监控 Linux 内核输出的 I/O 使用信息,并且显示一个系统中进程或线程的当前 I/O 使用情况。它显示每个进程/线程读写 I/O 带宽。它同样显示当等待换入和等待 I/O 的线程/进程花费的时间的百分比。

在这里插入图片描述

Total DISK READ 和 Total DISK WRITE
的值一方面表示了进程和内核线程之间的总的读写带宽,另一方面也表示内核块设备子系统的。
Actual DISK READ 和 Actual DISK WRITE 的值表示在内核块设备子系统和下面硬件(HDD、SSD
等等)对应的实际磁盘 I/O 带宽。

8.2 iotop命令参数

-o, --only只显示正在产生I/O的进程或线程。除了传参,可以在运行过程中按o生效。
-b, --batch非交互模式,一般用来记录日志。
-n NUM, --iter=NUM设置监测的次数,默认无限。在非交互模式下很有用。
-d SEC, --delay=SEC设置每次监测的间隔,默认1秒,接受非整形数据例如1.1。
-p PID, --pid=PID指定监测的进程/线程。
-u USER, --user=USER指定监测某个用户产生的I/O。
-P, --processes仅显示进程,默认iotop显示所有线程。
-a, --accumulated显示累积的I/O,而不是带宽。
-k, --kilobytes使用kB单位,而不是对人友好的单位。在非交互模式下,脚本编程有用。
-t, --time 加上时间戳,非交互非模式。
-q, --quiet 禁止头几行,非交互模式。有三种指定方式:
(1) -q 只在第一次监测时显示列名
(2) -qq 永远不显示列名。
(3) -qqq 永远不显示I/O汇总。

(1) 交互按键

左右键:改变排序方式
在这里插入图片描述
r:反向排序。
o:切换至选项–only。
p:切换至–processes选项。
a:切换至–accumulated选项。
i:改变线程的优先级。
q:退出。

(2) -o 检查某些正在做I/O的进程

iotop -o (iotop --only): 检查某些正在做I/O的进程。(仅显示正在读写的进程服务,会实时变化。)

(3) -d 1 -n 1 间隔1秒输出3次

(4) -botq -p xxx(进程号)

非交互式下,输出pid为xxx的进程信息
在这里插入图片描述

九、iostat命令

9.1 iostat介绍

iostat主要用于监控系统设备的IO负载情况,根据这个可以看出当前系统的写入量和读取量,CPU负载和磁盘负载
在这里插入图片描述

avg-cpu段:
%user: 在用户级别运行所使用的CPU的百分比.
%nice: nice操作所使用的CPU的百分比.
%sys: 在系统级别(kernel)运行所使用CPU的百分比.
%iowait: CPU等待硬件I/O时,所占用CPU百分比.
%idle: CPU空闲时间的百分比.
Device段:
tps: 每秒钟发送到的I/O请求数.
Blk_read /s: 每秒读取的block数.
Blk_wrtn/s: 每秒写入的block数.
Blk_read: 读入的block总数.
Blk_wrtn: 写入的block总数.

9.2 iostat命令参数

(1) 参数格式

iostat [选项] [<时间间隔>] [<次数>]

选项:

-c: 显示CPU使用情况
-d: 显示磁盘使用情况
-N: 显示磁盘阵列(LVM) 信息
-n: 显示NFS 使用情况
-k: 以 KB 为单位显示
-m: 以 M 为单位显示
-t: 报告每秒向终端读取和写入的字符数和CPU的信息
-V: 显示版本信息
-x: 显示详细信息

(2) -m 以M为单位显示所有信息

在这里插入图片描述

(3) -d 显示(指定)硬盘信息

在这里插入图片描述

(4) 查看设备使用率(%util)、响应时间(await)

在这里插入图片描述

rrqm/s: 每秒进行 merge 的读操作数目。即 rmerge/s
wrqm/s: 每秒进行 merge 的写操作数目。即 wmerge/s
r/s: 每秒完成的读 I/O 设备次数。即 rio/s
w/s: 每秒完成的写 I/O 设备次数。即 wio/s
rkB/s: 每秒读K字节数。是 rsect/s 的一半,因为每扇区大小为512字节。
wkB/s: 每秒写K字节数。是 wsect/s 的一半。
avgrq-sz: 平均每次设备I/O操作的数据大小 (扇区)。
avgqu-sz: 平均I/O队列长度。
rsec/s: 每秒读扇区数。即 rsect/s
wsec/s: 每秒写扇区数。即 wsect/s
r_await:每个读操作平均所需的时间
不仅包括硬盘设备读操作的时间,还包括了在kernel队列中等待的时间。
w_await:每个写操作平均所需的时间
不仅包括硬盘设备写操作的时间,还包括了在kernel队列中等待的时间。
await: 平均每次设备I/O操作的等待时间 (毫秒)。
svctm: 平均每次设备I/O操作的服务时间 (毫秒)。
%util: 一秒中有百分之多少的时间用于 I/O 操作,即被io消耗的cpu百分比

如果 %util 接近 100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘可能存在瓶颈。

如果 svctm 比较接近 await,说明 I/O 几乎没有等待时间;如果 await 远大于 svctm,说明I/O 队列太长,io响应太慢,则需要进行必要优化。

如果avgqu-sz比较大,也表示有当量io在等待。

十、Blktrace原理与使用

10.1 Blktrace介绍

一般来说,想检查磁盘I/O情况,可以使用iostat、iotop、sar等,但这些命令只能做一个整体的了解,没法具体到某一次io的详细情况,而blktrace就可以深入到Linux I/O栈的方方面面。

Blktrace是一个用户态的工具,用来收集磁盘IO信息中当IO进行到块设备层(block层,所以叫blk trace)时的详细信息(如IO请求提交,入队,合并,完成等等一些列的信息)。

10.2 Linux内核I/O栈

Linux内核I/O栈如下:
在这里插入图片描述
主要分为如下几层:

  • 文件系统层
    提供了open、read、write等文件操作的系统调用给应用程序使用,并且Linux提供了文件系统的统一抽象vfs,使得Linux中可适配各种类型的文件系统,如ext4、btrfs、zfs、fat32、ntfs等,而我们常说的磁盘格式化,实际上就是在安装文件系统,重新写入相关文件系统的初始元数据信息到磁盘。
  • 卷管理层
    比如我们常听到的Device Mapper、LVM、soft raid就属于这一层,用于将多个磁盘合为一个,或将一个磁盘拆分为多个。
  • 块存储层
    这一层主要实现io调度逻辑,比如将一个大io请求拆分为多个小的io请求,将相邻的io请求合并,实现各种io调度算法等,常见io调度算法有CFQ、NOOP、Deadline、AS。
  • 存储驱动层
    每一个硬件都需要驱动程序,硬盘也不例外,如常听到的SCSI、ACHI、NVME等,且如/dev/sda这样的设备抽象文件,也由这一层实现。
  • 硬件层
    硬件层就是具体的硬盘实物了,但我们经常听到ATA、SATA、SCSI、PCIe、SAS等这样的名词,这是不同的硬盘接口规范,就像手机充电线有Type-A、Type-B、Type-C一样。

一个I/O请求进入block layer之后,可能会经历下面的过程:

  • Remap: 可能被DM(Device Mapper)或MD(Multiple Device, Software RAID) remap到其它设备
  • Split: 可能会因为I/O请求与扇区边界未对齐、或者size太大而被分拆(split)成多个物理I/O
  • Merge: 可能会因为与其它I/O请求的物理位置相邻而合并(merge)成一个I/O
  • 被IO Scheduler依照调度策略发送给driver
  • 被driver提交给硬件,经过HBA、电缆(光纤、网线等)、交换机(SAN或网络)、最后到达存储设备,设备完成IO请求之后再把结果发回。

10.3 Blktrace相关概念

blktrace跟踪在块存储层(包括卷管理层),得到的结果含义如下:

blktrace -d /dev/sdb -o – | blkparse -i –

在这里插入图片描述

第一个字段:8,0 这个字段是设备号 major device ID 和 minor device ID。
第二个字段:3 表示 CPU
第三个字段:11 序列号
第四个字段:0.009507758 Time Stamp 是时间偏移
第五个字段:PID 本次 I/O 对应的进程 ID
第六个字段:Event,这个字段非常重要,反映了 I/O 进行到了哪一步
第七个字段:R 表示 Read, W 是 Write,D 表示 block,B 表示 Barrier Operation
第八个字段:223490+56,表示的是起始 block number 和 number of blocks,即我们常说的Offset 和 Size
第九个字段:进程名

其中第六个字段表示I/O事件,它代表了 I/O 请求进行到了哪一阶段,有如下这些事件:

  • A : remap 对于栈式设备,进来的 I/O 将被重新映射到 I/O 栈中的具体设备。

  • X : split 对于做了 Raid 或进行了 device mapper(dm) 的设备,进来的 I/O可能需要切割,然后发送给不同的设备。

  • Q : queued I/O 进入 block layer,将要被 request 代码处理(即将生成 I/O 请求)。

  • G : get request I/O 请求(request)生成,为 I/O 分配一个 request 结构体。

  • M : back merge 之前已经存在的 I/O request 的终止 block 号,和该 I/O 的起始 block号一致,就会合并,也就是向后合并。

  • F : front merge 之前已经存在的 I/O request 的起始 block 号,和该 I/O 的终止 block号一致,就会合并,也就是向前合并。

  • I : inserted I/O 请求被插入到 I/O scheduler 队列。

  • S : sleep 没有可用的 request 结构体,也就是 I/O 满了,只能等待有 request 结构体完成释放。

  • P : plug 当一个 I/O 入队一个空队列时,Linux 会锁住这个队列,不处理该 I/O,这样做是为了等待一会,看有没有新的 I/O进来,可以合并。

  • U : unplug 当队列中已经有 I/O request 时,会放开这个队列,准备向磁盘驱动发送该I/O。这个动作的触发条件是:超时(plug 的时候,会设置超时时间);或者是有一些 I/O 在队列中(多于 1 个 I/O)。

  • D : issued I/O 将会被传送给磁盘驱动程序处理。

  • C : complete I/O 处理被磁盘处理完成。

这些Event中常见的出现顺序如下:

Q – 即将生成 I/O 请求  
|
G – I/O 请求生成
|
I – I/O 请求进入 I/O Scheduler 队列
|
D – I/O 请求进入 Driver
|
C – I/O 请求执行完毕

由于每个Event都有出现的时间戳,根据这个时间戳就可以计算出 I/O 请求在每个阶段所消耗的时间,比如从Q事件到C事件的时间叫Q2C,那么常见阶段称呼如下:

 Q------------>G----------------->I----------------------------------->D----------------------------------->C
 |-Q time(Q2G)-|-Insert time(G2I)-|------schduler wait time(I2D)-------|--------driver,disk time(D2C)-------|
 |------------------------------- await time in iostat output(Q2C) -----------------------------------------|
  • Q2G – 生成 I/O 请求所消耗的时间,包括 remap 和 split 的时间;
  • G2I – I/O 请求进入 I/O Scheduler 所消耗的时间,包括 merge 的时间;
  • I2D – I/O 请求在 I/O Scheduler 中等待的时间,可以作为 I/O Scheduler 性能的指标;
  • D2C – I/O 请求在 Driver 和硬件上所消耗的时间,可以作为硬件性能的指标;
  • Q2C – 整个 I/O 请求所消耗的时间(Q2I + G2I + I2D + D2C = Q2C),相当于 iostat 的 await。
  • Q2Q – 2个 I/O 请求的间隔时间。

10.4 Blktrace命令

(1) 安装blktrace

# 安装blktrace包
$ sudo apt install blktrace
# blktrace依赖debugfs,需要挂载它
$ sudo mount -t debugfs debugfs /sys/kernel/debug

blktrace包安装后有blktrace、blkparse、btt、blkiomon这4个命令,其中blktrace负责采集I/O事件数据,blkparse负责将每一个I/O事件数据解析为纯文本方便阅读,btt、blkiomon负责统计分析。

(2) 先采集后分析

# 采集io事件数据
$ sudo blktrace -d /dev/sda
^C=== sda ===
  CPU  0:                  477 events,       23 KiB data
  CPU  1:                 1089 events,       52 KiB data
  CPU  2:                  216 events,       11 KiB data
  CPU  3:                  122 events,        6 KiB data
  Total:                  1904 events (dropped 0),       90 KiB data

# 数据保存在sda.blktrace.<cpu>中,每个cpu一个文件
$ ls -l *blktrace*
-rw-r--r-- 1 root root 22928 2022-02-12 16:11:37 sda.blktrace.0
-rw-r--r-- 1 root root 52304 2022-02-12 16:11:37 sda.blktrace.1
-rw-r--r-- 1 root root 10408 2022-02-12 16:11:37 sda.blktrace.2
-rw-r--r-- 1 root root  5864 2022-02-12 16:11:37 sda.blktrace.3

# 查看I/O事件
$ blkparse -i sda 
  8,0    3        1     0.000000000 3064475  A   W 367809144 + 8 <- (8,1) 367807096
  8,0    3        2     0.000001498 3064475  Q   W 367809144 + 8 [kworker/u256:3]
  8,0    3        3     0.000013880 3064475  G   W 367809144 + 8 [kworker/u256:3]
  8,0    3        4     0.000016012 3064475  P   N [kworker/u256:3]
  8,0    3        5     0.000025289 3064475  A   W 367809136 + 8 <- (8,1) 367807088
  8,0    3        6     0.000025867 3064475  Q   W 367809136 + 8 [kworker/u256:3]
...
Total (sda):
 Reads Queued:          14,      220KiB  Writes Queued:         299,     1556KiB
 Read Dispatches:       14,      220KiB  Write Dispatches:      213,     1556KiB
 Reads Requeued:         0               Writes Requeued:         0
 Reads Completed:       14,      220KiB  Writes Completed:      213,     1556KiB
 Read Merges:            0,        0KiB  Write Merges:           86,      348KiB
 IO unplugs:            34               Timer unplugs:          39

Throughput (R/W): 4KiB/s / 30KiB/s
Events (sda): 1766 entries
Skips: 0 forward (0 -   0.0%)

由于I/O事件通常很多,一个个的分析并不容易,因此一般使用btt来进行统计分析。

(3) btt

1、首先需要使用blkparse将blktrace采集到的多个文件合并为一个,如下:

 # 先合并为一个文件
$ blkparse -i sda -d sda.blktrace.bin
$ ll sda.blktrace.bin
-rw-rw-r-- 1 work work 90K 2022-02-12 16:12:56 sda.blktrace.bin

2、然后使用btt分析sda.blktrace.bin,如下:

$ btt -i sda.blktrace.bin
==================== All Devices ====================

            ALL           MIN           AVG           MAX           N
--------------- ------------- ------------- ------------- -----------

Q2Q               0.000000410   0.165743313   5.193234517         312
Q2G               0.000000297   0.000169175   0.004261675         227
G2I               0.000000341   0.000023664   0.000284838         225
Q2M               0.000000108   0.000000336   0.000002798          86
I2D               0.000000716   0.000708445   0.003329311         227
M2D               0.000004063   0.000106955   0.000737934          84
D2C               0.000111877   0.000718769   0.004067916         313
Q2C               0.000134521   0.001402772   0.008234969         313

==================== Device Overhead ====================

       DEV |       Q2G       G2I       Q2M       I2D       D2C
---------- | --------- --------- --------- --------- ---------
 (  8,  0) |   8.7464%   1.2126%   0.0066%  36.6269%  51.2391%
---------- | --------- --------- --------- --------- ---------
   Overall |   8.7464%   1.2126%   0.0066%  36.6269%  51.2391%

==================== Device Merge Information ====================

       DEV |       #Q       #D   Ratio |   BLKmin   BLKavg   BLKmax    Total
---------- | -------- -------- ------- | -------- -------- -------- --------
 (  8,  0) |      313      227     1.4 |        8       15      200     3552

==================== Device Q2Q Seek Information ====================

       DEV |          NSEEKS            MEAN          MEDIAN | MODE
---------- | --------------- --------------- --------------- | ---------------
 (  8,  0) |             313      24620107.8               0 | 0(94)
---------- | --------------- --------------- --------------- | ---------------
   Overall |          NSEEKS            MEAN          MEDIAN | MODE
   Average |             313      24620107.8               0 | 0(94)

==================== Device D2D Seek Information ====================

       DEV |          NSEEKS            MEAN          MEDIAN | MODE
---------- | --------------- --------------- --------------- | ---------------
 (  8,  0) |             227      35300234.0               0 | 0(10) 8
---------- | --------------- --------------- --------------- | ---------------
   Overall |          NSEEKS            MEAN          MEDIAN | MODE
   Average |             227      35300234.0               0 | 0(10)
                                                               ...(more)

注意这里面的D2C与Q2C,D2C代表硬盘实际处理时间,不包含在I/O队列中的等待时间,而Q2C代表整个I/O在块层的处理时间。

可以看到上面Q2C(IO处理时间)平均耗时1.402ms,最大8.234ms,D2C(硬盘处理时间)平均耗时0.718ms,最大4.076ms,而旋转磁盘耗时一般在几毫秒到十几毫秒,所以这个磁盘表现正常,但如果D2C经常到100ms以上,则可能磁盘损坏了,需要尽快更换磁盘。

(4) blkiomon

blkiomon也能分析I/O事件,对设备/dev/sda的io监控120秒,每2秒显示一次,如下:

$ sudo blktrace /dev/sda -a issue -a complete -w 120 -o - | blkiomon  -I 2 -h -
time: Sat Feb 12 16:37:25 2022
device: 8,0
sizes read (bytes): num 0, min -1, max 0, sum 0, squ 0, avg 0.0, var 0.0
sizes write (bytes): num 2, min 4096, max 24576, sum 28672, squ 620756992, avg 14336.0, var 104857600.0
d2c read (usec): num 0, min -1, max 0, sum 0, squ 0, avg 0.0, var 0.0
d2c write (usec): num 2, min 659, max 731, sum 1390, squ 968642, avg 695.0, var 1296.0
throughput read (bytes/msec): num 0, min -1, max 0, sum 0, squ 0, avg 0.0, var 0.0
throughput write (bytes/msec): num 2, min 6215, max 33619, sum 39834, squ 1168863386, avg 19917.0, var 187744804.0
sizes histogram (bytes):
            0:     0         1024:     0         2048:     0         4096:     1
         8192:     0        16384:     0        32768:     1        65536:     0
       131072:     0       262144:     0       524288:     0      1048576:     0
      2097152:     0      4194304:     0      8388608:     0    > 8388608:     0
d2c histogram (usec):
            0:     0            8:     0           16:     0           32:     0
           64:     0          128:     0          256:     0          512:     0
         1024:     2         2048:     0         4096:     0         8192:     0
        16384:     0        32768:     0        65536:     0       131072:     0
       262144:     0       524288:     0      1048576:     0      2097152:     0
      4194304:     0      8388608:     0     16777216:     0     33554432:     0
    >33554432:     0
bidirectional requests: 0

十一、ftrace使用

11.1 ftrace介绍

11.1.1 介绍

内核遇到性能瓶颈时,先通过perf找到热点函数,在通过ftrace对这些热点函数进行定量分析,对热点函数中具体函数调用其他函数的过程以及这些函数调用的时间打印出来

11.1.2 可消费事件源:

tracepoints, kprobes, and uprobes;
依赖debugfs;
依赖debugfs;

11.2 前端工具

11.2.1 /sys/kernel/debug/tracing

通过debugfs来进行调试,通过配置文件的内容,来干锅内容读取调试跟踪信息on

1、进入debugfs目录
cd /sys/kernel/debug/tracing

在这里插入图片描述

如果找不到目录,执行下列命令挂载debugfs:

mount -t debugfs nodev /sys / kernel/debug
2、查询支持的追踪器
cat available_tracers

在这里插入图片描述
常用的有两种:
function 表示跟踪函数的执行;
function_graph 则是跟踪函数的调用关系;

3、查看支持追踪的内核函数和事件

其中函数就是内核中的函数名,而事件,则是内核源码中预先定义的跟踪点。

# 查看内核函数
cat available_filter_functions
#查看事件
cat available_events
4、设置追踪函数:
echo do_sys_open > set_graph_function
5、设置追踪器
# 将function_graph写入current_tracer,表示对函数调用进行追踪
echo function_graph > current_tracer
echo funcgraph-proc > trace_options
6、开启追踪
echo 1 > tracing_on

此时ftrace开始工作

7、执行一个ls命令后,再关闭跟踪
ls # 我们追踪的是do_sys_open,ls会打开文件,会触发追踪函数
echo 0 > tracing_on # 停止追踪

在这里插入图片描述

8、最后一步,查看跟踪结果
cat trace

在这里插入图片描述
输出结果可以看到哪一个CPU、哪一个进程执行、每一个函数执行的时间花费多少。
在这里插入图片描述

11.2.2 trace-cmd(11.2.1的简化版)

1、安装trace-cmd及trace-cmd介绍

安装trace-cmd以及trace-cmd介绍。

sudo apt-get install trace-cmd
2、列出可用的追踪器

当使用 ftrace 时,你必须查看文件的内容以了解有哪些追踪器可用。但使用 trace-cmd,你可以通过以下方式获得这些信息:
在这里插入图片描述

3、启用函数追踪器—function

用 function 启用你的第一个追踪器:

trace-cmd start -p function

在这里插入图片描述

4、查看追踪输出

一旦追踪器被启用,你可以通过使用 show 参数来查看输出。这只显示了前 20 行
在这里插入图片描述

5、停止追踪并清除缓冲区

追踪将会在后台继续运行,你可以继续用 show 查看输出。

要停止追踪,请运行带有 stop 参数的 trace-cmd 命令

trace-cmd stop

要清除缓冲区,用 clear 参数运行:

trace-cmd clear
6、启用函数调用图追踪器
trace-cmd record -p function_graph -g do_sys_open -O funcgraph-proc ls
root@yj:/home/book/ftrace# trace-cmd record -p function_graph -g do_sys_open -O funcgraph-proc ls  plugin 'function_graph'
trace.dat.cpu0	trace.dat.cpu1
Kernel buffer statistics:
  Note: "entries" are the entries left in the kernel ring buffer and are not
        recorded in the trace data. They should all be zero.

CPU: 0
entries: 0
overrun: 0
commit overrun: 0
bytes: 2016
oldest event ts: 27156.202077
now ts: 27156.208151
dropped events: 0
read events: 620

CPU: 1
entries: 0
overrun: 0
commit overrun: 0
bytes: 240
oldest event ts: 27156.205517
now ts: 27156.208197
dropped events: 0
read events: 2606

CPU0 data recorded at offset=0x4ca000
    24576 bytes in size
CPU1 data recorded at offset=0x4d0000
    98304 bytes in size

通过查看生成的trace.dat文件

trace-cmd report

得到与11.2.1节中通过文件查看的结果一致。
在这里插入图片描述

11.2.3 perf-tools(perf-tools是ftrace和perf_event的包装器)

perf-tools

十二、strace使用

12.1 strace介绍

strace是一个可用于诊断、调试和教学的Linux用户空间跟踪器。我们用它来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。

strace底层使用内核的ptrace特性来实现其功能。

12.2 strace的使用

strace有两种运行模式:

  • 一种是通过它启动要跟踪的进程。
    用法很简单,在原本的命令前加上strace即可。比如我们要跟踪 “ls -lh /var/log/messages” 这个命令的执行,可以这样:
  • 另外一种运行模式,是跟踪已经在运行的进程。
    在不中断进程执行的情况下,给strace传递个-p pid 选项即可。

strace ls -lh

在这里插入图片描述

strace常用选项:

-tt 在每行输出的前面,显示毫秒级别的时间
-T 显示每次系统调用所花费的时间
-v 对于某些相关调用,把完整的环境变量,文件stat结构等打出来。
-f 跟踪目标进程,以及目标进程创建的所有子进程
-e 控制要跟踪的事件和跟踪行为,比如指定要跟踪的系统调用名称
-o 把strace的输出单独写到指定的文件
-s 当系统调用的某个参数是字符串时,最多输出指定长度的内容,默认是32个字节
-p 指定要跟踪的进程pid, 要同时跟踪多个pid, 重复多次-p选项即可。

其中-e trace=跟踪指定的系统,选项如下:

-e trace=file 只跟踪有关文件操作的系统调用.
-e trace=process 只跟踪有关进程控制的系统调用.
-e trace=network 跟踪与网络有关的所有系统调用.
-e strace=signal 跟踪所有与系统信号有关的 系统调用
-e trace=ipc 跟踪所有与进程通讯有关的系统调用

例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all

十三、Systemtap的使用

13.1 Systemtap介绍

SystemTap是一个Linux非常有用的调试(跟踪/探测)工具,常用于Linux 内核或者应用程序的信息采集,比如:获取一个函数里面运行时的变量、调用堆栈,甚至可以直接修改变量的值,对诊断性能或功能问题非常有帮助。

SystemTap提供非常简单的命令行接口和很简洁的脚本语言,以及非常丰富的tapset和例子。

systemtap 是利用Kprobe 提供的API来实现动态地监控和跟踪运行中的Linux内核的工具,相比Kprobe,systemtap更加简单,提供给用户简单的命令行接口,以及编写内核指令的脚本语言。

kprobe介绍:Linux内核调试利器kprobe的使用,从这几点入手!

开发人员在内核或者模块的调试过程中,往往会需要要知道其中的一些函数有无被调用、何时被调用、执行是否正确以及函数的入参和返回值是什么等等。比较简单的做法是在内核代码对应的函数中添加日志打印信息,但这种方式往往需要重新编译内核或模块,重新启动设备之类的,操作较为复杂甚至可能会破坏原有的代码执行过程。

而利用kprobe技术,用户可以定义自己的回调函数,然后在内核或者模块中几乎所有的函数中(有些函数是不可探测的,例如kprobes自身的相关实现函数,后文会有详细说明)动态的插入探测点,当内核执行流程执行到指定的探测函数时,会调用该回调函数,用户即可收集所需的信息了,同时内核最后还会回到原本的正常执行流程。如果用户已经收集足够的信息,不再需要继续探测,则同样可以动态地移除探测点。因此kprobes技术具有对内核执行流程影响小和操作方便的优点。

应用场景:

定位(内核)函数位置
查看函数被调用时的调用堆栈、局部变量、参数
查看函数指针变量实际指的是哪个函数
查看代码的执行轨迹(哪些行被执行了)
查看内核或者进程的执行流程
调试内存泄露或者内存重复释放
统计函数调用次数

13.2 systemtap的使用

systemtap 的核心思想是定义一个事件(event),以及给出处理该事件的句柄(Handler)。当一个特定的事件发生时,内核运行该处理句柄,就像快速调用一个子函数一样,处理完之后恢复到内核原始状态。这里有两个概念:

事件(Event):systemtap 定义了很多种事件,例如进入或退出某个内核函数、定时器时间到、整个systemtap会话启动或退出等等。

句柄(Handler):就是一些脚本语句,描述了当事件发生时要完成的工作,通常是从事件的上下文提取数据,将它们存入内部变量中,或者打印出来。

参考链接:

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值