爱测未来移动-QNX性能监控方案

1、背景介绍

目前各平台通过各自的脚本获取数据,然后通过其他工具对数据进行展示,方案已能够满足当前的项目需求,但跨平台数据统计项和数据展示方式不一致,可对比性较差。

当前的监控方案是通过shell脚本,定期执行top命令收集cpu使用信息,执行showmem命令收集内存使用信息,然后保存到日志文件中。最后将日志文件下载到PC并导入Excel对数据进行筛选和分析,展示出cpu和内存的使用情况。

该方案实现简单,数据采集完全通过shell脚本完成,数据分析由Excel完成,但存在以下不足:

A、脚本通用性较差,因为在linux平台和QNX平台需要使用不同的命令获取内存信息

B、数据分析逻辑不能通用,不同平台获取的数据格式存在差异

C、使用top命令获取cpu使用信息,不能控制采样间隔,每次获取的是系统的top占用,不利于统计待机的cpu占用,数据存在误差


2、新的方案

统一通过代码获取cpu和memory数据,以获取更好的性能,减少系统资源的消耗,并能够按PID进行性能统计,增强数据的实时和有效性。同时提供扩展,便于将来支持更多的统计内容。在数据收集层,优先采用系统API和文件系统,无法实现时再考虑使用shell命令实现。


3、数据收集

(1)CPU使用数据

目前Android平台通过读取 /proc/${pid}/stat 文件获取cpu使用信息,linux平台也可采用相同的方案,在QNX平台,需要读取 /proc/${pid}/as 文件获得cpu信息


(2)Memory数据

对于单个进程的内存使用数据,Android平台实用的是 getProcessMemoryInfo 接口获取内存占用信息,linux平台和QNX平台没有提供这个API,需要自行设计实现。Linux平台可通过 /proc/${pid}/statm 文件获取,QNX平台可通过 /proc/${pid}/vmstat 文件获取。

对于系统总体的内存使用数据,Android平台和linux平台通过读取 /proc/meminfo 文件获取,在QNX平台,通过读取 /proc 目录的大小获得内存使用信息


4、QNX CPU 获取

(1)单个CPU整体占用算法

Pid为1的进程为Idle进程,通过计算Idle进程的CPU使用时间得出CPU的使用情况。

ProcFd =open( "/proc/1/as", O_RDONLY );

使用 DCMD_PROC_TIDSTATUS 参数读取Idle进程下各个thread的信息,其中tid和cpu一一对应,tid = 1 对应 cpu0。单cpu情况下 tid = 1 即可获得全部数据。

debug_data.tid = 1;

devctl( ProcFd,DCMD_PROC_TIDSTATUS, &debug_data, sizeof( debug_data ), NULL );

通过 debug_data.sutime 可以获取该进程的cpu占用时间,这个时间是从该进程启动以来的总时间,要计算当前的实时cpu占用情况,需要进行定期采样。默认采用500ms采用周期(采样周期可通过配置文件修改),计算两次的差值即可得到采样周期内该进程的cpu使用时间。

假设第一次采样时间记为 sutime1,第二次采样记为 sutime2,采样间隔记为 time_delta。则采样周期内cpu占用为

100.0 - ((float)( (sutime2 - sutime1) * 100 ) / (float)time_delta )


(2)多个CPU整体占用算法

对于多个CPU,分别计算单个CPU的使用情况,Idle进程的不同tid对应使用了不同的CPU。

根据CPU数量循环对不同Idle进程的thread进行计算,计算出每个cpu的占用率。

总体占用率为: 各个CPU占用率总和 / CPU数量。

统计数据除总体占用数据外,还需要记录各个CPU的数据以供后续分析。


(3)进程CPU占用算法

通过读取对应pid的文件,可以获取该进程的相关信息

ProcFd =open( "/proc/${pid}/as", O_RDONLY );

使用 DCMD_PROC_INFO 参数读取该进行的详细信息

devctl(fd,DCMD_PROC_INFO, info, sizeof(info), 0)

其中 info.start_time, info.utime, info.stime 分别记录了该进程的启动时间,cpu占用时间和系统占用时间,这些都是从进程启动以来的总体时间,因此和前面一样,需要采样才能获取当前时刻的实时占用情况。

这里也可以通过 info.num_threads 获得该进程的线程数量信息,然后通过DCMD_PROC_TIDSTATUS参数获得每个线程的cpu占用情况

debug_data.tid= i ;

devctl(ProcFd, DCMD_PROC_TIDSTATUS, &debug_data, sizeof( debug_data ), NULL );


5、QNX 内存获取

(1)总内存占用

系统总内存的获取参考QNX源码,通过系统指针_syspage_ptr->asinfo.entry_size 获取。

staticuint64_tget_total_mem(void) {

    char                    *str = SYSPAGE_ENTRY(strings)->data;

    structasinfo_entry     *as = SYSPAGE_ENTRY(asinfo);

    uint64_t                total = 0;

    unsigned                num;

 

    for(num = _syspage_ptr->asinfo.entry_size /sizeof(*as); num > 0;--num) {

       if(strcmp(&str[as->name],"ram") == 0) {

           total += as->end - as->start+ 1;

       }

       ++as;

    }

    return total;

}

QNX系统通过 /proc 文件夹的大小映射系统内存的占用情况,因此只需要读取这个文件夹的大小就可以获得总内存的使用情况

stat("/proc", &buf );

memused= buf.st_size;


(2)进程内存占用

可通过读取/proc/${pid}/vmstat 文件获取,读取该文件可获得以下数据

as_stats.map_size

as_stats.map_phys

as_stats.map_shared

as_stats.map_private

更多的详细信息可以通过读取 /proc/${pid} 文件夹获取,通过DCMD_PROC_PAGEDATA 参数可以获取进程的 page mapping

devctl(fd, DCMD_PROC_PAGEDATA, mp, mpsize, &num)





附录

(1)/proc/pid/stat

包含了所有CPU活跃的信息,该文件中的所有值都是从系统启动开始累计到当前时刻。

[root@localhost ~]# cat /proc/6873/stat

6873 (a.out) R 6723 6873 6723 34819 6873 8388608 77 0 0 0 41958 31 0 0 25 03 0 5882654 1409024 56 4294967295 134512640 134513720 3215579040 0 2097798 0 00 0 0 0 0 17 0 0 0 [root@localhost ~]#

每个参数意思为:

参数 解释

pid=6873 进程(包括轻量级进程,即线程)号

comm=a.out 应用程序或命令的名字

task_state=R 任务的状态,R:runnign, S:sleeping (TASK_INTERRUPTIBLE), D:disksleep (TASK_UNINTERRUPTIBLE), T: stopped, T:tracing stop,Z:zombie, X:dead

ppid=6723 父进程ID

pgid=6873 线程组号

sid=6723 c该任务所在的会话组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 administrativepurpose.

这些页可能用于代码,数据和栈。

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)/proc/pid/statm

[root@localhost proc]# cat /proc/1/statm

487 185 133 31 0 67 0

参数解释:

size:任务虚拟地址空间大小

Resident:正在使用的物理内存大小

Shared:共享页数

Trs:程序所拥有的可执行虚拟内存大小

Lrs:被映像倒任务的虚拟内存空间的库的大小

Drs:程序数据段和用户态的栈的大小

dt:脏页数量



公众号:itest_forever


CSDN:http://blog.csdn.net/itest_2016

QQ群:274166295(爱测未来2群)、610934609(爱测未来3群)








  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值