linux memcpy性能优化_linux性能优化

性能优化有两大指标:延时吞吐。

linux优化思维导图:

86ca716eae893d3fb72ef96a4d696dc9.png

平均负载

[root@node200 ~]# uptime
 20:45:44 up 11:24,  2 users,  load average: 0.00, 0.01, 0.05
当前时间  启动运行时长 当前正在登陆的用户 1、5、15分钟系统的平均负载

平均负载是指单位时间内,系统处于可运行状态(runnable)和不可中断(uninterruptable)的平均进程数,也就是平均活跃进程数,它和CPU使用率没有直接关系。可以简单理解为,平均负载其实就是平均活跃进程数。

进程状态一共有如下5种

  1. R(运行):进程正在运行或在运行队列中等待。
  2. T(停止):进程收到停止信号后停止运行。
  3. Z(僵死):进程已经终止,但进程描述符依然存在, 直到父进程调用wait4()系统函数后将进程释放。
  4. S(中断):进程处于休眠中,当某个条件形成后或者接收到信号时,则脱离该状态。
  5. D(不可中断):进程不响应系统异步信号,即便用kill命令也不能将其中断。

比如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,他是不能被其他进程或者中断打断,这个时候的进程就区域不可中断的状态。如果此时的进程被打断了,就容易出现磁盘数据与进程数据不一致的问题。因此,不可中断状态实际上是系统对进程和硬件设备的一种保护机制。

最理想的状态,就是每个CPU上都刚好运行着一个进程,这样每个CPU都得到充分利用。例如,当平均负载为2时,

  • 在只有2个CPU的系统上,意味着所有的CPU都刚好被完全占用,是最理想的状态
  • 在有4个CPU的系统上,意味着CPU有50%的空闲。
  • 在只有1个CPU的系统上,意味着有一半的进程竞争不到CPU。

因此,在评判平均负载的高低前,首先你要知道系统有几个CPU。可以通过top(按1)、lscpu或者查看/proc/cpuinfo获取本机cpu的个数。

[root@node200 ~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                8
On-line CPU(s) list:   0-7
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             8
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 61
Model name:            Intel Core Processor (Broadwell)
Stepping:              2
CPU MHz:               2099.998
BogoMIPS:              4199.99
Hypervisor vendor:     KVM
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              4096K
NUMA node0 CPU(s):     0-7
[root@node200 ~]# grep "model name" /proc/cpuinfo |wc -l
8

当平均负载高于CPU数量的70%的时候,你就应该分析排查负载高的问题了。

平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包括了正在使用CPU的进程数,还包括等待CPU和等待I/O的进程数。

而CPU使用率,是根据单位时间内CPU的繁忙情况进行统计,和平均负载并一定完全一致。例如,

  • CPU密集型进程,大量使用CPU会导致负载升高,此时CPU使用率和平均负载是一致的。
  • I/O密集型进程,等待I/O也会导致平均负载升高,但是CPU的使用率并不一定会很高。
  • 大量等待CPU的进程调度也会导致平均负载升高,此时的CPU使用率也会比较高。

stress是一个Linux系统压力测试工具。

sysstat包含了常用的Linux性能工具,用来监控和分析系统的性能。以下案例使用mpstat和pidstat两个命令。

mpstat是一个常用的多核CPU性能分析工具,用来实时查看每个CPU的性能指标以及所有CPU的平均指标。

pidstat是一个常用的进程性能分析工具,用来实时查看进程的CPU、内存、I/O以及上下文切换等性能指标。

[root@node200 ~]#  yum install -y epel-release
[root@node200 ~]# yum install sysstat stress -y
[root@node200 ~]# cat /proc/cpuinfo|grep "model name" |wc -l
2

场景一:CPU密集型

第一个终端运行压力测试

[root@node200 ~]# stress -c 2 --timeout 600

第二个终端通过uptime实时查看平均负载

[root@node200 ~]# watch -d uptime
Every 2.0s: uptime                                                                                                                Sat May 16 21:53:46 2020
 21:53:46 up 5 min,  4 users,  load average: 2.04, 0.96, 0.38

第三个终端使用mpstat查看cpu变化情况:

## -P ALL表示监控所有的CPU,5表示每间隔5秒后输出一组数据
[root@node200 ~]# mpstat -P ALL 5
Linux 3.10.0-1062.18.1.el7.x86_64 (node200.com) 	05/16/2020 	_x86_64_	(2 CPU)

09:56:07 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
09:56:12 PM  all   99.70    0.00    0.30    0.00    0.00    0.00    0.00    0.00    0.00    0.00
09:56:12 PM    0   99.60    0.00    0.40    0.00    0.00    0.00    0.00    0.00    0.00    0.00
09:56:12 PM    1   99.80    0.00    0.20    0.00    0.00    0.00    0.00    0.00    0.00    0.00

第四个终端使用pidstat查看进程信息

## 每隔3秒后输出一组数据,总共输出5次
[root@node200 ~]# pidstat -u 3 5
Linux 3.10.0-1062.18.1.el7.x86_64 (node200.com) 	05/16/2020 	_x86_64_	(2 CPU)

09:58:11 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
09:58:14 PM     0      1693   99.67    0.00    0.00   99.67     0  stress
09:58:14 PM     0      1694   99.34    0.00    0.00   99.34     1  stress
09:58:14 PM     0      2043    0.00    0.33    0.00    0.33     1  pidstat

09:58:14 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
09:58:17 PM     0      1693   99.67    0.00    0.00   99.67     0  stress
09:58:17 PM     0      1694   99.33    0.00    0.00   99.33     1  stress
09:58:17 PM     0      1735    0.00    0.33    0.00    0.33     1  watch

场景二:I/O密集型

[root@node200 ~]# stress -i 4 --timeout 600s

然后也是通过uptime、mpstat和pidstat查看系统的负载情况,也可以通过top查看此时CPU使用率并不高,而平均负载却高达4。

场景三:大量进程情形(即大量进程处于可运行状态)

[root@node200 ~]# stress -c 8 --timeout 600s

8远大于2(cpu个数),此时CPU负载也是很高的。

小结:

  1. 平均负载高有可能是cpu密集型进程导致的,也有可能是I/O密集型进程导致的,也有可能是大量进程处于等待CPU调度的情况导致的
  2. 平均负载高并不意味着CPU使用率高,参见实验情景二。
  3. 平均负载高的时候,使用mpstat、pidstat、top、uptime等工具进行分析。

cpu上下文切换

进程在竞争CPU的时候并没有真正运行,是CPU上下文切换导致平均负载升高。在每个任务运行前,CPU都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮他设置好CPU寄存器程序计数器

cpu寄存器是CPU内置的容量小、但速度极快的内存。而程序计数器,则是 用来存储CPU正在执行的指令位置、或者即将执行的下一条指令位置。他们都是CPU在运行任何任务前,必须的依赖环境,因此也被叫做CPU上下文

CPU上下文切换,就是先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。而这些保存下来的上下文,会存储在系统内核中,并在任务重新调度之行时候再次加载进来,这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。

根据任务的不同,cpu的上在问切换可以分为几个不同的场景,也就是进程上下文切换、线程上下文切换、中断上下文切换。

Linux按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应下图中的Ring 0和Ring 3。

内核空间(Ring 0)具有最高权限,可以直接访问所有资源。

用户空间(Ring 3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源。

b0761dc2a8a21d9bb9f2e56f29511861.png

也就是说,进程既可以在用户空间运行,又可以在内核空间中运行。进程在用户空间运行时候,被称为进程 的用户态,而陷入内核空间的时候,被称为进程的内核态。

从用户态到内核态的转变,需要通过系统调用来完成。例如,当我们查看文件内容时候,就需要多次系统调用来完成:首先调用open()打开文件,然后调用read()读取文件内容,并调用write()将内容写出到标准输出,最后再调用close()关闭文件。系统调用的过程也需要CPU进行上下文切换。

CPU寄存器里原来用户态的指令位置,需要先保存起来。接着,为了执行内核状态代码,cpu寄存器需要更新为内核态指令的新位置,最后才是跳转到内核态运行内核任务。系统调用结束后,CPU寄存器需要恢复原来保存的用户态,然后再切换到用户空间,继续运行进程。所以,一次系统调用的过程,其实时发生了两次CPU上下文切换。

不过,需要注意的是,系统调用过程中,并不会涉及到虚拟内存等用户态的资源切换,也不会切换进程,这和我们通常所说的进程上下文切换是不一样的:

  • 进程上下文切换,是指从一个进程切换到另一个进程中。
  • 而系统调用的过程一直是同一个进程在运行,只是用户空间与内核空间进行切换,分别执行相应权限的指令。

所以,系统调用过程通常称为特权模式切换,而不是上下文切换。

进程是由内核来管理和调度的,晋城的切换只能发生在内核态。所以,进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。因此,进程的上下文且换比系统调用时候多了一步:在保存当前进程的内核状态和CPU寄存器之前,需要把改进承诺的虚拟内存、栈等保存下来,而加载了下一进程的内核态后,还需要刷新晋城的虚拟内存和用户栈。

每次上下文切换都需要几十纳秒到数微秒的CPU时间。在进程上下文切换次数较多的情况下,很容易导致CPU将大量的时间耗费在寄存器、内核堆以及虚拟内存等资源的保存和回复上,进而大大缩短了真正运行进程的时间,从而导致平均负载升高。

另外,Linux通过TLB来管理虚拟内存到五力内存的映射,当虚拟内存更新后,TLB也需要刷新,内存的访问也会随之变慢。特别是在多处理器的系统上,缓存是被多个处理器共享的,刷新缓存不仅会影响当前处理器的进程,还会影响共享缓存的其他处理器的进程。

只有在进程调度切换时候,才需要切换上下文,linux为每一个cpu都维护了一个就绪队列,将活跃进程(即正在运行和正在等待CPU的进程)按照优先级和等待CPU的时间顺序,然后选择最需要CPU的进程,也就是优先级最高和等待CPU时间最长的进程来运行。

有如下场景会促发进程调度:

  1. 进程执行完终止了,它之前使用的CPU会释放出来,这时候会从就绪队列里,拿一个新的进程来运行
  2. 为了保证所有进程得到公平调度,CPU时间被划分成一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其他正在等待CPU的进程运行。
  3. 进程在系统资源不足(比如内存不足)时,要等大哦资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行。
  4. 当进程通过睡眠函数sleep这样的方法将自己主动挂起时,自然也会重新调度。
  5. 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程也会被挂起,由高优先级进程来运行。
  6. 发生硬件中断时,CPU上的进程会被中断挂起,转而执行内核中的中断服务程序。

线程上下文切换

线程与进程的最大区别在于线程是调度的基本单位,而进程是资源拥有的基本单位。

  • 当进程只有一个线程时候,可以认为进程就等于线程。
  • 当晋城拥有多个线程时候,这些县城会共享相同的虚拟内存和全局变量等资源。这些资源在线程上下文切换时候不需要修改。
  • 线程也有自己的私有数据,比如栈和寄存器,这些在线程上下文切换是后也需要保存切换。

线程上下文切换分为两种情况:

前后两个线程数与不同进程,此时,因为资源不贡献,所以切换过程就和进程上下文切换是一致的。

前后两个线程同属于一个进程。此时,虚拟内存和圈局变量等资源是共享的,所以在切换时候,这些资源就保持不懂,只需要切换线程私有数据、寄存器等不共享的数据。

正因为同一进程内的不同线程切换的代价校园多进程间的上下文切换,因此,通常采用多线程来取代多进程。

中断上下文切换

除了上面两种上下文切换,还有一个场景也会切换CPU上下文,那就是中断。

为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程任然可以从原来的状态恢复运行。

跟进程上下文不同,中断上下文切换并不涉及到进程的用户态。所以,即便中断打断了一个正在处于用户态的进程,也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。中断上下文,其中只包括内核态中断服务程序执行必须的状态,包括CPU寄存器、内核堆栈、硬件中断参数等。

对于同哦一个CPU来说,中断处理比进程拥有更高的优先级,所以终端上下文切换并不会与进程上下文切换同时发生。同样道理,由于中断会打断正常进程的调度和执行,所以大部分中断处理程序都短小精悍,以便尽可能快的执行结束。

另外,跟进程上下文切换一样,中断上下文切换需要消耗cpu,切换次数过多也会耗费大量的CPU,甚至严重降低系统的整体性能。

小结

  1. cpu上下文切换,是保证linux正常工作的核心功能之一,一般情况下不需要我们特别关注。
  2. 但过多的上下文切换,回报cpu时间消耗在寄存器,内核栈以及虚拟内存等数据的保存和恢复上,从而缩短进程真正运行的时间,导致系统的整体性能大幅下降。

vmstat是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析CPU上下文切换和中断的次数。

## 每隔3秒输出一组数据,输出一次
[root@node200 ~]# vmstat 3 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 7619244   2080 367984    0    0     2     3  177   26  2  1 98  0  0

cs(context switch):每秒上下文切换的次数。

in(interrupt):每秒中断的次数。

r(running or runnable)就是就绪队列的长度,也就是正在运行和等待CPU的进程数。

b(blocked)处于不可中断睡眠状态的进程数。

vmstat只给出了系统总体的上下文切换情况,想要查看每隔进程的详细情况,可以使用pidstat。

[root@node200 ~]# pidstat  -w 5
Linux 3.10.0-1062.18.1.el7.x86_64 (node200.com) 	05/17/2020 	_x86_64_	(2 CPU)

08:38:57 PM   UID       PID   cswch/s nvcswch/s  Command
08:39:02 PM     0         1      2.59      0.00  systemd
08:39:02 PM     0         6      0.20      0.00  ksoftirqd/0
08:39:02 PM     0         7      0.20      0.00  migration/0
08:39:02 PM     0         9     10.58      0.00  rcu_sched
08:39:02 PM     0        11      0.20      0.00  watchdog/0
08:39:02 PM     0        12      0.20      0.00  watchdog/1
08:39:02 PM     0        13      0.20      0.00  migration/1
08:39:02 PM     0        14      0.60      0.00  ksoftirqd/1
08:39:02 PM     0        37      0.20      0.00  khugepaged
08:39:02 PM     0       102      1.00      0.00  kauditd
08:39:02 PM     0       382      1.00      0.00  kworker/1:1H
08:39:02 PM     0       394      2.20      0.00  kworker/0:1H
08:39:02 PM     0       493      1.20      0.00  systemd-journal
08:39:02 PM     0       902      1.20      0.00  auditd
08:39:02 PM     0       925      0.40      0.00  abrt-watch-log
08:39:02 PM   999       930      1.80      0.00  polkitd
08:39:02 PM     0       933      2.59      0.00  systemd-logind
08:39:02 PM    81       934      5.39      0.00  dbus-daemon
08:39:02 PM    70       939      0.80      0.00  avahi-daemon
08:39:02 PM     0       951      0.40      0.00  crond
08:39:02 PM     0       961      0.80      0.00  firewalld
08:39:02 PM     0       976      1.40      0.00  NetworkManager
08:39:02 PM    26      1402      0.20      0.00  postmaster
08:39:02 PM     0      1488      1.20      0.00  master
08:39:02 PM    89      1522      0.80      0.00  qmgr
08:39:02 PM     0      2739      0.40      0.00  kworker/u4:2
08:39:02 PM     0     14102      3.79      0.00  kworker/0:1
08:39:02 PM    89     16370      1.40      0.00  cleanup
08:39:02 PM     0     16373      1.20      0.00  local
08:39:02 PM    89     16765      0.60      0.00  pickup
08:39:02 PM    89     16771      0.40      0.00  trivial-rewrite
08:39:02 PM     0     16926      1.20      0.00  kworker/1:0
08:39:02 PM     0     16970      0.40      0.00  kworker/0:2
08:39:02 PM     0     16971      0.20      0.20  pidstat

cswch表示每秒资源上下文切换(voluntary context switches)的次数

nvcswch表示每秒非自愿上下文切换(non voluntary context switches)的次数。

所谓自愿上下文切换,是指进程无法获取所需资源,导致的上下文切换。比如,I/O、内存等系统资源不足时,就会发生自愿上下文切换。

而非资源上下文切换,是指进程由于时间片已到等原因,被系统强制调度,进程发生的上下文切换。比如说,大量进程都在争抢CPU时候,就容易发生非自愿上下文切换。

实验

sysbench是一个多线程的基准测试工具,一般用来评估不同系统参数下的数据库负载情况。当然,在本次案例中,我们只把它当成一个异常进程来看,作用是模拟上下文切换过多的问题。

root@fzlinwenw-KVM:~# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b 交换 空闲 缓冲 缓存   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 4453964  52164 3245532    0    0     9    40  152  301  2  1 96  0  0
 0  0      0 4453956  52164 3245532    0    0     0     0   41   48  0  0 100  0  0
 0  0      0 4453956  52164 3245532    0    0     0     0   36   49  0  0 100  0  0
 0  0      0 4453956  52164 3245532    0    0     0     0   32   44  0  0 100  0  0

可以看出,在压测之前,系统的us(user)用户cpu使用率、sy(system)系统cpu使用率、cs、in、r、b指标都是比较低的。

root@fzlinwenw-KVM:~# sysbench --threads=10 --max-time=600 threads run
root@fzlinwenw-KVM:~# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b 交换 空闲 缓冲 缓存   si   so    bi    bo   in   cs us sy id wa st
 8  0      0 4451664  52196 3245548    0    0     9    40  166  133  2  1 96  0  0
 8  0      0 4451632  52196 3245548    0    0     0     0 78520 833560 19 79  3  0  0
 7  0      0 4451632  52196 3245548    0    0     0     0 72674 842205 21 78  1  0  0
 8  0      0 4451632  52196 3245548    0    0     0     0 72225 862825 21 77  2  0  0
 6  0      0 4451632  52196 3245548    0    0     0     0 76753 904941 21 79  1  0  0

可以看出,在压测之后,系统的us(user)用户cpu使用率、sy(system)系统cpu使用率、cs、in、r、b指标都迅速上升。

r:running/runnable队列的长度已经到达8了,远超过系统cpu的个数2,所以肯定会有大量的cpu竞争。

us和sy这两列的cpu使用率加起来达到100%左右了,其中系统的cpu使用率,也就是sy高达84%,说明cpu主要是被内核占用了。

in中断次数也是直线上升。

root@fzlinwenw-KVM:~# pidstat -wu 3
10时49分22秒   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
10时49分25秒     0     18748    0.00    0.33    0.00    0.00    0.33     0  kworker/u4:0-events_freezable_power_
10时49分25秒     0     18802   41.67  100.00    0.00    0.00  100.00     0  sysbench
10时49分25秒     0     18813    0.33    0.00    0.00    0.00    0.33     1  pidstat

10时49分22秒   UID       PID   cswch/s nvcswch/s  Command
10时49分25秒     0         9      0.33      0.00  ksoftirqd/0
10时49分25秒     0        10      5.67      0.00  rcu_sched
10时49分25秒     0        11      0.33      0.00  migration/0
10时49分25秒     0        17      0.33      0.00  migration/1
10时49分25秒     0        18      1.67      0.00  ksoftirqd/1
10时49分25秒     0       180      0.33      0.00  kworker/1:1H-kblockd
10时49分25秒     0       485      0.33      0.00  irqbalance
10时49分25秒     0       919      0.67      4.33  sshd
10时49分25秒   121      1165      1.00      0.00  gsd-color
10时49分25秒     0      1325      2.00      0.00  sshd
10时49分25秒     0     18315      4.67      0.00  kworker/1:1-events
10时49分25秒     0     18748      9.67      0.33  kworker/u4:0-events_freezable_power_
10时49分25秒     0     18756      6.67      0.00  kworker/u4:2-events_unbound
10时49分25秒     0     18790      1.00      2.00  vmstat
10时49分25秒     0     18813      0.33      0.67  pidstat
10时49分25秒     0     19252      4.67      0.00  kworker/0:3-ata_sff

可以看出,cpu使用率上升是由于sysbench导致的,他的CPU使用率达到了100%。上下文切换来自其他进程,包括非自愿上下文切换频率最高的sshd以及费最远上下文切换频率最高的kworker。但是此处不同进程间的上下文切换也就几十次,比vmstat的几十万磁明显小太多了,因此此处pidstat查看出来的上下文切换是忽略掉线程的数据的,可以加一个-t参数查看线程间上下文切换的详细情况,可以看到__sysbench的线程产生了大量的上下文切换。

root@fzlinwenw-KVM:~# pidstat -wt 3
Linux 5.3.0-28-generic (fzlinwenw-KVM) 	2020年05月20日 	_x86_64_	(2 CPU)
平均时间:   UID      TGID       TID   cswch/s nvcswch/s  Command
平均时间:     0        10         -      8.52      0.00  rcu_sched
平均时间:     0         -        10      8.52      0.00  |__rcu_sched
平均时间:     0        11         -      0.33      0.00  migration/0
平均时间:     0         -        11      0.33      0.00  |__migration/0
平均时间:     0        17         -      0.33      0.00  migration/1
平均时间:     0         -        17      0.33      0.00  |__migration/1
平均时间:     0        18         -      1.64      0.00  ksoftirqd/1
平均时间:     0         -        18      1.64      0.00  |__ksoftirqd/1
平均时间:     0         -       583      0.33      0.00  |__gmain
平均时间:     0         -       558      0.33      0.00  |__gmain
平均时间:   121      1165         -      0.98      0.00  gsd-color
平均时间:   121         -      1165      0.98      0.00  |__gsd-color
平均时间:     0      1325         -      1.97      0.00  sshd
平均时间:     0         -      1325      1.97      0.00  |__sshd
平均时间:     0      3235         -      0.33      0.00  sshd
平均时间:     0         -      3235      0.33      0.00  |__sshd
平均时间:     0     18315         -      4.26      0.00  kworker/1:1-events
平均时间:     0         -     18315      4.26      0.00  |__kworker/1:1-events
平均时间:     0     18790         -      0.98      1.97  vmstat
平均时间:     0         -     18790      0.98      1.97  |__vmstat
平均时间:     0     18796         -      2.30      0.33  kworker/u4:1-events_unbound
平均时间:     0         -     18796      2.30      0.33  |__kworker/u4:1-events_unbound
平均时间:     0         -     18803  13103.28  70691.80  |__sysbench
平均时间:     0         -     18804  12831.80  66949.18  |__sysbench
平均时间:     0         -     18805  13769.84  64950.49  |__sysbench
平均时间:     0         -     18806  10572.79  74155.41  |__sysbench
平均时间:     0         -     18807  12378.69  77803.28  |__sysbench
平均时间:     0         -     18808  12265.90  70099.02  |__sysbench
平均时间:     0         -     18809  10985.90  72320.00  |__sysbench
平均时间:     0         -     18810  11994.10  66074.43  |__sysbench
平均时间:     0         -     18811  13417.70  69490.82  |__sysbench
平均时间:     0         -     18812  12335.41  69239.67  |__sysbench
平均时间:     0     18816         -      0.33      6.23  pidstat
平均时间:     0         -     18816      0.33      6.23  |__pidstat
平均时间:     0     19252         -      5.25      0.00  kworker/0:3-events
平均时间:     0         -     19252      5.25      0.00  |__kworker/0:3-events

中断详情查看:

root@fzlinwenw-KVM:~# watch -d cat /proc/interrupts
        CPU0       CPU1
  0:          4          0   IO-APIC   2-edge      timer
  1:          0          9   IO-APIC   1-edge      i8042
  6:          0          3   IO-APIC   6-edge      floppy
  8:          0          0   IO-APIC   8-edge      rtc0
  9:          0          0   IO-APIC   9-fasteoi   acpi
 10:         24          0   IO-APIC  10-fasteoi   virtio3, ehci_hcd:usb1, uhci_hcd:usb2
 11:          0         72   IO-APIC  11-fasteoi   uhci_hcd:usb3, uhci_hcd:usb4, qxl
 12:         15          0   IO-APIC  12-edge      i8042
 14:      62011       1219   IO-APIC  14-edge      ata_piix
 15:          0          0   IO-APIC  15-edge      ata_piix
 24:          0          0   PCI-MSI 98304-edge      virtio1-config
 25:         35          0   PCI-MSI 98305-edge      virtio1-virtqueues
 26:          0          0   PCI-MSI 114688-edge      virtio2-config
 27:          0     134237   PCI-MSI 114689-edge      virtio2-req.0
 28:          0          0   PCI-MSI 49152-edge      virtio0-config
 29:      39099     270567   PCI-MSI 49153-edge      virtio0-input.0
 30:     147242      51517   PCI-MSI 49154-edge      virtio0-output.0
 31:        564          0   PCI-MSI 65536-edge      snd_hda_intel:card0
NMI:          0          0   Non-maskable interrupts
LOC:    1536267    1587458   Local timer interrupts
SPU:          0          0   Spurious interrupts
PMI:          0          0   Performance monitoring interrupts
IWI:          0          0   IRQ work interrupts
RTR:          0          0   APIC ICR read retries
RES:   70568928   69478828   Rescheduling interrupts
CAL:      99581      63530   Function call interrupts
TLB:       5505       5158   TLB shootdowns
TRM:          0          0   Thermal event interrupts
THR:          0          0   Threshold APIC interrupts
DFR:          0          0   Deferred Error APIC interrupts
MCE:          0          0   Machine check exceptions
MCP:        205        205   Machine check polls
HYP:          0          0   Hypervisor callback interrupts
HRE:          0          0   Hyper-V reenlightenment interrupts
HVS:          0          0   Hyper-V stimer0 interrupts
ERR:          0
MIS:          0
PIN:          0          0   Posted-interrupt notification event
NPI:          0          0   Nested posted-interrupt event
PIW:          0          0   Posted-interrupt wakeup event

/proc实际上是linux的一个虚拟文件系统,用于内核空间与用户空间的通信。/proc/interrupts就是这种通信机制的一部门,通过了一个只读的中断使用情况。观察一段时间,可以发现刷新最快的是Rescheduling interrupts(重调度中断),这个终端类型表示,唤醒空闲的CPU来调度新的任务运行。这是多处理器系统中,调度器用来分散任务到不同CPU的机制,也称为处理期间中断。所以,这里的中断升高还是因为过、过多任务的调度问题。

每秒多少次上下文切换才算正常?这个数值其实取决于系统本身的CPU性能。如果系统的上下文切换次数比较稳定,那么从数百到一万以内,应该都算正常。但当上下文切换超过一万或者切换次数出现数量级的增长,就很有可能出现了性能问题了。

小结:

  • 资源上下文切换变多了,说明进程都在等待资源,有可能发生了I/O等其他问题
  • 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢CPU。说明cpu是瓶颈。
  • 中断次数变多了,说明cpu被中断处理程序占用,需要通过查看/proc/interrupts文件来分析具体的终端类型

CPU使用率

linux是一个多任务操作系统,将每个CPU的时间划分为很短的时间片,在通过调度器轮流分配给各个任务使用。为了维护CPU时间,linux通过事先定义的节拍率(内核中表示为HZ),触发时间中断,并使用全局变量Jiffies记录了开机以来的节拍数,没发生一次时间中断,Jiffies的值就会加一。

节拍率HZ是内核的可配选项,可以设置为100/250/1000等,不同的系统可能设置不同的数值,可以通过/boot/config内核选项来查看他的配置值。下图节拍率设置为250,也就是每秒钟触发250次时间中断

root@fzlinwenw-KVM:~# grep 'CONFIG_HZ=' /boot/config-$(uname -r)
CONFIG_HZ=250
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: memcpy是一个常用的内存复制函数,它的性能对于系统的性能有着重要的影响。为了提升memcpy函数的性能,我们可以采取以下几种优化措施。 第一,通过使用SIMD指令集进行优化。SIMD指令集可以同时处理多个数据元素,从而提高数据复制的速度。一些常见的SIMD指令集如SSE(Streaming SIMD Extensions)和AVX(Advanced Vector Extensions)。使用SIMD指令集需要将数据按照指令集的要求进行对齐,以获得最佳的性能提升。 第二,使用软件指令级并行优化。将memcpy函数的复制操作拆分成多个并行任务,可以通过优化算法和数据结构来最大程度地利用处理器的并行性能。例如,可以将复制操作分成多个子任务,每个子任务复制一部分数据,然后使用多线程或者并行计算框架进行并行处理。 第三,使用缓存优化。在进行大量数据复制时,利用处理器的缓存可以显著提高性能。一种常见的优化方法是将大块数据分成适当大小的块,并按照一定的顺序进行复制,以最大限度地减少缓存失效。此外,还可以使用特定的数据结构,如缓存对齐数据结构,以提高数据复制的效率。 第四,使用硬件加速。一些现代处理器提供了硬件加速的功能,可以通过特定的指令来加速数据复制。例如,Intel的QuickPath Interconnect(QPI)和Advanced Micro Devices的HyperTransport技术可以提供高速数据传输,进一步提升memcpy函数的性能。 综上所述,通过使用SIMD指令集、软件指令级并行优化、缓存优化和硬件加速等方法,可以有效地提升memcpy函数的性能。但是需要注意的是,优化memcpy函数时应该综合考虑数据规模、处理器架构等因素,并进行适当的测试和评估,以确保优化结果的有效性。 ### 回答2: memcpy是一个用于内存复制的函数,其作用是将一段连续的内存块从源地址复制到目标地址。在性能提升优化方面,可以考虑以下几个方面: 1. 使用SIMD指令集:SIMD (Single Instruction, Multiple Data)指令集是一种并行计算方式,可以在同一时钟周期内对多个数据进行相同的操作。在适用的硬件平台上,可以使用SIMD指令集进行优化,提高memcpy函数的复制速度。 2. 内存对齐:对于一些体积较大的数据块,可以考虑使用内存对齐的方式进行复制。内存对齐是指保证数据块的起始地址是某个固定值的整数倍,这样可以利用硬件平台的高效复制机制,提高memcpy函数的执行效率。 3. 分段复制:对于大内存块的复制,可以将其分成多个小内存块进行复制。这样可以充分利用CPU的缓存机制,减少内存访问的开销。 4. 多线程:对于多核CPU,可以考虑使用多线程并行复制的方式。将大内存块分成多个小块,每个线程负责复制其中的一部分,可以提高数据复制的速度。 5. 使用专门优化的库函数:除了使用标准库的memcpy函数,还可以考虑使用一些专门优化的库函数,比如Intel的MKL库、GCC的优化内存复制函数等。 在实际应用中,根据具体的场景和平台选择合适的优化方法。通过对memcpy函数进行性能提升优化,可以加快数据复制的速度,提高程序的整体性能。 ### 回答3: memcpy函数是C语言中常用的一个内存拷贝函数,它能够将指定数量的字节从源内存块复制到目标内存块中。然而,在某些情况下,对memcpy函数的性能提升的优化是非常必要的。 首先,在处理大量数据时,普通的memcpy函数可能会导致性能瓶颈。为了提升性能,可以采用一些优化技巧。一种常见的优化方式是利用SIMD(单指令多数据)指令集,如SSE(流式SIMD扩展)或AVX(高级矢量扩展)。这些指令集能够一次性处理多个字节或数据,从而提高内存拷贝的速度。 其次,内存对齐也是提升memcpy性能的重要因素。对齐的内存访问通常比非对齐的内存访问更高效。因此,在使用memcpy时,可以尽量保证源和目标内存块的地址是对齐的。如果数据是非对齐的,可以使用一些特殊的内存拷贝函数,如memcpy_s或_mm_loadu_si128。 另外,使用多线程或并行处理也是提升memcpy性能的有效方法。可以将大块的内存拷贝任务拆分成多个子任务,并由多个线程同时进行处理。这样可以充分利用多核处理器的性能,加快内存拷贝的速度。 此外,还可以根据具体的应用场景来进行一些特定的优化。例如,可以根据内存块的大小选择最合适的内存拷贝函数,利用缓存预取和预读取技术来提前加载数据等。 综上所述,对于memcpy函数的性能提升和优化,可以通过使用SIMD指令集、内存对齐、多线程或并行处理以及其他特定的优化技巧来实现。这些优化方法可以在处理大量数据时提高内存拷贝的效率,从而提升整体性能

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值