Linux环境下进程的CPU占用率

Linux环境下进程的CPU占用率,第1张

概述阿里云服务器网站:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=qqwovx6h 文字来源:http://www.samirchen.com/linux-cpu-performance/ 1、Linux 环境下查看 CPU 信息 1.1、查看 CPU 详细信息 通过 cat /proc/cpuinfo 命令,可以查 阿里云服务器网站:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=qqwovx6h 文字来源:http://www.samirchen.com/linux-cpu-performance/ 1、linux 环境下查看 cpu 信息 1.1、查看 cpu 详细信息

通过 cat /proc/cpuinfo 命令,可以查看 cpu 相关的信息:

[[email protected]~]$cat/proc/cpuinfoprocessor:0vendor_ID:GenuineIntelcpufamily:6model:44modelname:Intel(R)Xeon(R)[email protected]2.40GHzstepPing:2cpuMHz:1596.000cachesize:12288KBphysicalID:0siblings:8coreID:0cpucores:4APIcID:0initialAPIcID:0fpu:yesfpu_exception:yescpuIDlevel:11wp:yesflags:fpuvmedepsetsCMSrpaemcecx8APIcsepmtrrpgemcacmovpatpse36clflushdtsacpimmxfxsRSSesse2sshttmpbesyscallnxpdpe1gbrdtscplmconstant_tscarch_perfmonpebsbtsrep_goodxtopologynonstop_tscaperfmperfpnipclmulqdqdtes64monitords_cplvmxsmxesttm2ssse3cx16xtprpdcmpcIDdcasse4_1sse4_2popcntaeslahf_lmaratepbdtstpr_shadowvnmiflexpriorityeptvpIDbogomips:4800.15clflushsize:64cache_alignment:64addresssizes:40bitsphysical,48bitsvirtualpowermanagement:......

 

在查看到的相关信息中,通常有些信息比较让人迷惑,这里列出一些解释:

physical ID: 指的是物理封装的处理器的 ID。 cpu cores: 位于相同物理封装的处理器中的内核数量。 core ID: 每个内核的 ID。 siblings: 位于相同物理封装的处理器中的逻辑处理器的数量。 processor: 逻辑处理器的 ID。

我们通常可以用下面这些命令获得这些参数的信息:

[[email protected] ~]$ cat /proc/cpuinfo | grep "physical ID"| sort|uniqphysical ID :0physical ID :1[[email protected] ~]$ cat /proc/cpuinfo | grep "cpu cores"| sort|uniqcpu cores :4[[email protected] ~]# cat /proc/cpuinfo | grep "core ID" | sort|uniqcore ID :0core ID :1core ID :10core ID :9[[email protected] ~]$ cat /proc/cpuinfo | grep "siblings"| sort|uniqsiblings :8[[email protected] ~]$ cat /proc/cpuinfo | grep "processor"| sort|uniqprocessor :0processor :1processor :10processor :11processor :12processor :13processor :14processor :15processor :2processor :3processor :4processor :5processor :6processor :7processor :8processor :9

通过上面的结果,可以看出这台机器:

1)有 2 个物理封装的处理器(physical ID 有 2 个); 2)每个物理封装的处理器有 4 个内核(cpu cores 为 4); 3)每个物理封装的处理器有 8 个逻辑处理器(siblings 为 8),可见台机器的处理器开启了超线程技术,每个内核(core)被划分为了 2 个逻辑处理器(processor); 4)总共有 16 个逻辑处理器(processor 有 16 个);

超线程技术:超线程技术就是利用特殊的硬件指令,把两个逻辑内核模拟成两个物理芯片,让单个处理器都能使用线程级并行计算,进而兼容多线程 *** 作系统和软件,减少了cpu的闲置时间,提高的cpu的运行效率。

1.2、查看多核 cpu 信息

可以使用 mpstat 命令或 sar 命令来查看。 具体使用可以通过 man mpstat/sar 来查看。

2、在 linux 环境下计算进程的 cpu 占用 2.1、通过 /proc/stat 文件查看所有的 cpu 活动信息

下面实例数据是内核 2.6.24-24 版本以上的:

[[email protected] ~]$ cat /proc/statcpu 22344724045041824108021655975341258620900cpu0 17625111934142575516534590721678000cpu1 124129139234258609121139271569700cpu2 14953055861825310182230738785100cpu3 40880138057258734793404191586200cpu4 13417171611232582975610429221715500cpu5 23935533183725605479369202609500cpu6 193200319132256197282060183069000cpu7 184300324300256161424170203308100cpu8 319400661718252319111474156766100cpu9 80798715203525829339237191630800cpu10 42472414005225869331168181505900cpu11 16305440147325567904207143467400cpu12 8227015781525853353319101480800cpu13 1889446479709253542796532615788500cpu14 70003020476025769743159162105900cpu15 4567114089925855452138161553600intr 114673438499700110001000001302607002620870712704000<...省略若干数据...>ctxt 89793364btime 1366591448processes 27283procs_running 1procs_blocked 0softirq 1262462448063122856507893291074176388225020046121395355817613064075931

第一行的数据表示的是 cpu 总的使用情况。我们来解释一下这行数据各数值的含义:

1)这些数值的单位都是 jiffIEs,jiffIEs 是内核中的一个全局变量,用来记录系统启动以来产生的节拍数,在 linux 中,一个节拍大致可以理解为 *** 作系统进程调度的最小时间片,不同的 linux 系统内核这个值可能不同,通常在 1ms 到 10ms 之间。 2)cpu 223447 240 4504182 410802165 59753 412 586209 0 0
user(223447) 从系统启动开始累积到当前时刻,处于用户态的运行时间,不包含 nice 值为负的进程。 nice(240) 从系统启动开始累积到当前时刻,nice 值为负的进程所占用的 cpu 时间。 system(4504182) 从系统启动开始累积到当前时刻,处于核心态的运行时间。 IDle(410802165) 从系统启动开始累积到当前时刻,除 IO 等待时间以外的其他等待时间。 iowait(59753) 从系统启动开始累积到当前时刻,IO 等待时间。(since 2.5.41) irq(412) 从系统启动开始累积到当前时刻,硬中断时间。(since 2.6.0-test4) softirq(586209) 从系统启动开始累积到当前时刻,软中断时间。(since 2.6.0-test4) stealstolen(0) Which is the time spent in other operating systems when running in a virtualized environment.(since 2.6.11) guest(0) Which is the time spent running a virtual cpu for guest operating systems under the control of the linux kernel.(since 2.6.24)

从以上信息我们可以得到总的 cpu 活动时间为:

totalcpuTime = user + nice + system + IDle + iowait + irq + softirq + stealstolen + guest

2.2、通过 /proc/[PID]/stat 文件查看某一进程的 cpu 活动信息

2.2.1、存储进程信息的文件目录

linux 系统贯彻“一切都是文件”的思想,所有的进程的运行状态也都可以通过读取文件来获取。 /proc 文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为内核与进程提供通信的接口。用户和应用程序可以通过 /proc 得到系统的信息,并可以改变内核的某些参数。

/proc/[PID]/ 目录下的各个文件记录着 这个进程的各项运行指标。 是进程号。

2.2.2、查看进程运行的详细信息

通过查看 /proc/[PID]/stat 文件,可以进程运行的详细信息,其中就包括 cpu 占用信息。 比如:

[[email protected] ~]$ cat /proc/1/stat1(init) S 0110-1420275230262635222948351651023463188016200101198205443841844674407370955161511000004096536962595184467440737095516150004003400

 

/proc/[PID]/stat 文件信息解释

看到上面这些信息,肯定会很迷惑,不知道每个字段都是什么意思。

1)我们可以通过 man 5 proc 命令查看文档,找到 /proc/[pID]/stat 节点,就可以看到各字段的意思了。如:

/proc/[pID]/statStatus information about the process.Thisis used by ps(1).Itisdefinedin/usr/src/linux/fs/proc/array.c.The fIElds,in order,with their proper scanf(3) format specifIErs,are:pID %d The process ID.comm %s The filename of the executable,in parentheses.Thisis visible whether ornot the executable is swapped out.state %c One character from the string"RSDZTW"where R is running,S is sleePing in an interruptible wait,D is waiting in uninterruptible disk sleep,Z is zombIE,T is traced or stopped (on a signal),and W is paging.ppID %d The PID of the parent.......

2)具体解释,一个示例:

pID=6873 进程(包括轻量级进程,即线程)号comm=a.out 应用程序或命令的名字。task_state=R 任务的状态,R:runnign,S:sleePing (TASK_INTERRUPTIBLE),D:disk sleep (TASK_UNINTERRUPTIBLE),T: stopped,T:tracing stop,Z:zombIE,X:dead。ppID=6723 父进程ID。pgID=6873 线程组号。sID=6723 该任务所在的会话组 ID。tty_nr=34819(pts/3) 该任务的 tty 终端的设备号,INT(34817/256)= 主设备号,(34817-主设备号)= 次设备号。tty_pgrp=6873 终端的进程组号,当前运行在该任务所在终端的前台任务(包括 shell 应用程序)的 PID。task->flags=8388608 进程标志位,查看该任务的特性。min_flt=77 该任务不需要从硬盘拷数据而发生的缺页(次缺页)的次数。cmin_flt=0 累计的该任务的所有的 waited-for 进程曾经发生的次缺页的次数目。maj_flt=0 该任务需要从硬盘拷数据而发生的缺页(主缺页)的次数。cmaj_flt=0 累计的该任务的所有的 waited-for 进程曾经发生的主缺页的次数目。utime=1587 该任务在用户态运行的时间,单位为 jiffIEs。stime=1 该任务在核心态运行的时间,单位为 jiffIEs。cutime=0 累计的该任务的所有的 waited-for 进程曾经在用户态运行的时间,单位为 jiffIEs。cstime=0 累计的该任务的所有的 waited-for 进程曾经在核心态运行的时间,单位为 jiffIEs。priority=25 任务的动态优先级。nice=0 任务的静态优先级。num_threads=3 该任务所在的线程组里线程的个数。it_real_value=0 由于计时间隔导致的下一个 SIgalRM 发送进程的时延,以 jiffy 为单位。start_time=5882654 该任务启动的时间,单位为 jiffIEs。vsize=1409024(page) 该任务的虚拟地址空间大小。RSS=56(page) 该任务当前驻留物理地址空间的大小;Number of pages the process has in real memory,minu 3 for administrative purpose. 这些页可能用于代码,数据和栈。rlim=4294967295(bytes) 该任务能驻留物理地址空间的最大值。start_code=134512640 该任务在虚拟地址空间的代码段的起始地址。end_code=134513720 该任务在虚拟地址空间的代码段的结束地址。start_stack=3215579040 该任务在虚拟地址空间的栈的结束地址。kstkesp=0 esp(32 位堆栈指针) 的当前值,与在进程的内核堆栈页得到的一致。kstkeip=2097798 指向将要执行的指令的指针,EIP(32 位指令指针)的当前值。pendingsig=0 待处理信号的位图,记录发送给进程的普通信号。block_sig=0 阻塞信号的位图。sigign=0 忽略的信号的位图。sigcatch=082985 被俘获的信号的位图。wchan=0 如果该进程是睡眠状态,该值给出调度的调用点。nswap 被 swapped 的页数,当前没用。cnswap 所有子进程被 swapped 的页数的和,当前没用。exit_signal=17 该进程结束时,向父进程所发送的信号。task_cpu(task)=0 运行在哪个 cpu 上。task_rt_priority=0 实时进程的相对优先级别。task_policy=0 进程的调度策略,0=非实时进程,1=FIFO实时进程;2=RR实时进程

2.2.3、关于进程占用 cpu 的相关信息

在上述的时间中,这些信息会在计算 cpu 占用率时用到:

pID 进程号。 utime 该任务在用户态运行的时间,单位为 jiffIEs。 stime 该任务在核心态运行的时间,单位为 jiffIEs。 cutime 累计的该任务的所有的 waited-for 进程曾经在用户态运行的时间,单位为 jiffIEs。 cstime 累计的该任务的所有的 waited-for 进程曾经在核心态运行的时间,单位为 jiffIEs。

该进程的 cpu 占用时间(该值包括其所有线程的 cpu 时间):

processcpuTime = utime + stime + cutime + cstime

2.3、通过 /proc/[PID]/task/[TID]/stat 文件查看某一进程下的某一线程的活动信息

该文件包含了某一轻量级进程(lwp,即通常所说的线程)所有的活动信息,该文件中的所有值都是从系统启动开始累计到当前时刻。该文件的内容格式以及各字段的含义与 /proc/[PID]/stat 文件类似。该文件中的 tID 字段表示的是轻量级线程号。

该线程的 cpu 占用时间:

threadcpuTime = utime + stime

2.4、单核情况下 cpu 使用率的计算

2.4.1、基本思想

首先,通过读取 /proc/stat 文件获取总的 cpu 时间,读取 /proc/[PID]/stat 获取进程 cpu 时间,读取 /proc/[PID]/task/[TID]/stat 获取线程 cpu 时间。然后,采样两个足够短的时间间隔的 cpu 快照与进程或线程快照来计算其 cpu 使用率。

2.4.2、计算总的 cpu 使用率 totalcpuUse

1)采样两个足够短的时间间隔的 cpu 快照,即读取 /proc/stat 文件,获取两个时间点的下列数据:

cpuT1 (user1,nice1,system1,IDle1,iowait1,irq1,softirq1,stealstolen1,guest1); cpuT2 (user2,nice2,system2,IDle2,iowait2,irq2,softirq2,stealstolen2,guest2);

2)计算总的 cpu 时间 totalcpuTime:

cpuTime1 = user1 + nice1 + system1 + IDle1 + iowait1 + irq1 + softirq1 + stealstolen1 + guest1; cpuTime2 = user2 + nice2 + system2 + IDle2 + iowait2 + irq2 + softirq2 + stealstolen2 + guest2;

totalcpuTime = cpuTime2 – cpuTime1;

3)计算 cpu 空闲时间 IDlecpuTime:

IDlecpuTime = IDle2 – IDle1;

4)计算总的 cpu 使用率 totalcpuUse:

totalcpuUse = (totalcpuTime – IDlecpuTime) / totalcpuTime;

2.4.3、计算某一进程的 cpu 使用率 processcpuUse

1)采样两个足够短的时间间隔的 cpu 快照和对应的进程快照,即读取 /proc/stat 文件,获取两个时间点的下列数据:

cpuT1 (user1,guest2);

读取 /proc/[PID]/stat 文件,获取两个时间点的下列数据:

Processt1 (utime1,stime1,cutime1,cstime1); Processt2 (utime2,stime2,cutime2,cstime2);

2)计算总的 cpu 时间 totalcpuTime 和进程时间 processtime:

cpuTime1 = user1 + nice1 + system1 + IDle1 + iowait1 + irq1 + softirq1 + stealstolen1 + guest1; cpuTime2 = user2 + nice2 + system2 + IDle2 + iowait2 + irq2 + softirq2 + stealstolen2 + guest2;

totalcpuTime = cpuTime2 – cpuTime1;

processtime1 = utime1 + stime1 + cutime1 + cstime1; processtime2 = utime2 + stime2 + cutime1 + cstime2;

processtime = processtime2 – processtime1;

3)计算该进程的 cpu 使用率 processcpuUse:

processcpuUse = processtime / totalcpuTime;

2.4.4、计算某一线程的 cpu 使用率 threadcpuUse

1)采样两个足够短的时间间隔的 cpu 快照和对应的线程快照,即读取 /proc/stat 文件,获取两个时间点的下列数据:

cpuT1 (user1,guest2);

读取 /proc/[PID]/task/[TID]/stat 文件,获取两个时间点的下列数据:

threadT1 (utime1,stime1); threadT2 (utime2,stime2);

2)计算总的 cpu 时间 totalcpuTime 和线程时间 threadTime:

cpuTime1 = user1 + nice1 + system1 + IDle1 + iowait1 + irq1 + softirq1 + stealstolen1 + guest1; cpuTime2 = user2 + nice2 + system2 + IDle2 + iowait2 + irq2 + softirq2 + stealstolen2 + guest2;

totalcpuTime = cpuTime2 – cpuTime1;

threadTime1 = utime1 + stime1; threadTime2 = utime2 + stime2;

threadTime = threadTime2 – threadTime1;

3)计算该线程的 cpu 使用率 threadcpuUse:

threadcpuUse = threadTime / totalcpuTime;

2.5、多核情况下 cpu 使用率的计算

2.5.1、基本思想

首先,通过读取 /proc/stat 文件获取总的 cpu 时间,读取 /proc/[PID]/stat 获取进程 cpu 时间,读取 /proc/[PID]/task/[TID]/stat 获取线程 cpu 时间,读取 /proc/cpuinfo 获取 cpu 个数。

在多核情况下计算进程或线程的 cpu 使用率,用上面的方式得到的通常是相对于 cpu 所有核的总共时间的占用率,而我们通常习惯得到进程或线程对某一个单核的占用率。所以我们可以按上面的方式计算得到 cpu 占用率,然后把结果乘上 cpu 的核数,即可得到进程或线程相对于一个单核的占用率。

2.5.2、计算总的 cpu 使用率

同 2.4.2。

2.5.3、计算某一进程的 cpu 使用率 mProcesscpuUse

1)同 2.4.3 计算某一进程的 cpu 使用率 processcpuUse;

2)读取 /proc/cpuinfo 文件获取逻辑 cpu(processor) 的个数(参见 1.1): processorNum

3)多核情况下该进程的 cpu 使用率 mProcesscpuUse:

mProcesscpuUse = processcpuUse * processorNum;

2.5.4、计算某一线程的 cpu 使用率 mThreadcpuUse

1)同 2.4.4 计算某一线程的 cpu 使用率 threadcpuUse;

2)读取 /proc/cpuinfo 文件获取逻辑 cpu(processor) 的个数(参见 1.1): processorNum

3)多核情况下该线程的 cpu 使用率 mThreadcpuUse:

mThreadcpuUse = threadcpuUse * processorNum;

2.6、问题 1)不同内核版本 /proc/stat 文件格式不一致。/proc/stat 文件中第一行是总的 cpu 使用情况。
各个内核版本都有的 4 个字段:user,nice,system,IDle; 2.5.41 版本新增字段:iowait; 2.6.0-test4 版本新增字段:irq,softirq; 2.6.11 版本新增字段:stealstolen; 2.6.24 版本新增字段:guest;
2)/proc/[PID]/task 目录是 linux 2.6.0-test6 之后才有的功能。 3)关于 cpu 使用率为负的情况,解决方案是如果出现负值,连续采样计算 cpu 使用率直到为非负。 4)有些线程生命周期较短,可能在采样期间就已经死掉了。 2.7、一个计算总的 cpu 占用率的小程序
#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<time.h>typedefstruct procstat {char processorname[20];unsignedint user;unsignedint nice;unsignedint system;unsignedint IDle;unsignedint iowait;unsignedint irq;unsignedint softirq;unsignedint stealstolen;unsignedint guest;}Procstat;Procstat getcpuStatus(){// Get "/proc/stat" info.file* inputfile = NulL;chdir("/proc");inputfile = fopen("stat","r");if(!inputfile){perror("error: Can not open file.\n");}char buff[1024];fgets(buff,sizeof(buff),inputfile);// Read 1 line.printf(buff);Procstat ps;sscanf(buff,"%s %u %u %u %u %u %u %u %u %u",ps.processorname,&ps.user,&ps.nice,&ps.system,&ps.IDle,&ps.iowait,&ps.irq,&ps.softirq,&ps.stealstolen,&ps.guest);// Scan from "buff".printf("user: %u\n",ps.user);fclose(inputfile);return ps;}float calculatecpuUse(Procstat ps1,Procstat ps2){unsignedint totalcpuTime =(ps2.user + ps2.nice + ps2.system + ps2.IDle + ps2.iowait + ps2.irq + ps2.softirq + ps2.stealstolen + ps2.guest)-(ps1.user + ps1.nice + ps1.system + ps1.IDle + ps1.iowait + ps1.irq + ps1.softirq + ps1.stealstolen + ps1.guest);unsignedint IDlecpuTime = ps2.IDle - ps1.IDle;floatcpuUse=((float) totalcpuTime -(float) IDlecpuTime)/(float) totalcpuTime;printf("totalcpuTime: %u\nIDlecpuTime: %u\n",totalcpuTime,IDlecpuTime);returncpuUse;}int main(int argc,char* argv[]){printf("Test cpu\n");// Get processor num.int processorNum = sysconf(_SC_NPROCESSORS_CONF);// "unistd.h" is required.printf("Processors: %d\n",processorNum);// TestProcstat ps1,ps2;int i =0;for(i =0; i <=100000; i++){srand((unsigned) time(NulL));int m = rand()%100000;int n =1+ rand()%100000;int k = m / n;if(i ==10){ps1 = getcpuStatus();}if(i ==10000){ps2 = getcpuStatus();}}floatcpuUse= calculatecpuUse(ps1,ps2);printf("cpuUse: %f\n",cpuUse);return0;}
3、linux 环境查看进程运行相关信息 3.1、使用 ps 命令查看进程信息

几个常用参数:

a: 与终端无关的所有进程。 u: 有效用户(effective user)的相关进程。 x: 通常与 a 参数因使用,可列出较完整的信息。 -e: 选择所有进程。 -L: 显示线程,一般是 LWP 或 NLWP 列。 -o: 用户自定义显示选项。

示例1)列出所有当前所有正在内存中的进程

[[email protected] ~]$ ps auxUSER PID %cpu %MEM VSZ RSS TTY STAT START TIME COMMANDroot 10.00.0193561536?SsApr220:01/sbin/initroot 20.00.000? S Apr220:00[kthreadd]root 30.00.000? S Apr220:00[migration/0]root 40.00.000? S Apr220:00[ksoftirqd/0]root 50.00.000? S Apr220:00[migration/0]root 60.00.000? S Apr220:00[watchdog/0]root 70.00.000? S Apr220:00[migration/1]root 80.00.000? S Apr220:00[migration/1]......

示例2)列出进程号为 13560 这个进程的所有线程及 cpu 占用率

[[email protected] ~]$ ps -eLo pID,lwp,pcpu | grep 13560135601356049.5
3.2、使用 top 命令查看进程信息

几个常用的参数:

-d: 后面接秒数,就是整个进程画面更新的频率。默认是 5 秒。 -b: 以批处理的方式执行 top,还有更多的参数可用。通常会搭配数据流重导向,将批处理的结果输出为文件。 -n: 与 -b 搭配,意义是,需要进行几次 top 的输出结果。 -p: 指定某个 PID 来进行观察监测。 在 top 执行过程中可以使用的按键命令: ?: 显示在 top 中可以输入的按键命令。 P: 按照 cpu 的使用资源排序显示。 M: 按内存(Memory)的使用资源排序显示。 N: 按 PID 来排序。 T: 按该进程使用的 cpu 时间积累(TIME+)排序。 k: 给某个 PID 一个信号(signal)。 r: 给某个 PID 重新确定一个值。 1: 显示所有 cpu 占用信息。

示例1)将 top 命令执行两次,然后将结果输出到 /top_result.data

[[email protected] ~]$ top -b -n 2&gt;/top_result.data

示例2)监测进程 13620

[[email protected] ~]$ top -d 2-p 13620top -16:27:35 up 4 days,7:43,2 users,load average:0.35,0.47,0.44Tasks:1 total,1 running,0 sleePing,0 stopped,0 zombIEcpu(s):0.1%us,3.1%sy,0.0%ni,96.5%ID,0.0%wa,0.0%hi,0.3%si,0.0%stMem:16320632k total,1790796k used,14529836k free,233168k buffersSwap:8232952k total,0k used,8232952k free,941540k cachedPID USER PR NI VIRT RES SHR S %cpu %MEM TIME+ COMMAND13620 test1370 20011060944760 R 53.40.00:04.78 netperf
本文参考

http://www.blogjava.net/fjzag/articles/317773.html

http://www.brokestream.com/procstat.html

http://www.voidcn.com/article/p-dyasoquq-bk.html

《鸟哥linux私房菜》

总结

以上是内存溢出为你收集整理的Linux环境下进程的CPU占用率全部内容,希望文章能够帮你解决Linux环境下进程的CPU占用率所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/1021397.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存