admin管理员组

文章数量:1625849

1. 场景:需要多次数统计Android的开机时间

在移植完汇编解释执行后,需要对比c++的解释执行和汇编解释执行这两种情况下的开机时间。一开始采用的比较土的自己掐秒表方法,但一方面需要统计的次数比较多,另一方面自己掐秒表太费时也太耗精力,如何使用shell脚本实现自己开机,统计。

首先通过查询,android启动成功的标志为Android字样出现,在riscv汇编解释执行的情况下在logcat中会生成I ActivityTaskManager: Displayed com.eswin.tv.launcher/.homepage.HomepageActivity:,本来想直接查看logcat中该字符串出现的时间,但是在log中时间参数会发生两次跳变,因此需要通过计算自身pc的时间:从emulator启动到该字符串出现。

2. shell脚本需要注意的事项

shell脚本其实就是在linux终端中敲得命令集合生成的一个文件,相当于我们把所有敲得命令都放到一个文件中,执行这个文件就可以直接运行很多代码。这样做可以大幅度减少测试的时间,提高开发的效率。最简单的shell脚本就是把你要执行的文件复制到一个sh文件中,然后执行。

在终端中创建一个shell脚本,此次创建的脚本名称为launch_time.sh,如果直接./launch_time.sh那么是无法执行的,需要先进行增加权限操作chmod +x launch_time.sh再./launch_time.sh方可以执行。在一些情况下,不需要改变权限,通过source的方式可以直接运行脚本。但是在这次的测试的时候发现如果source launch_time.sh终端会直接挂掉,具体原因不得而知。

在vscode中创建sh脚本文件最麻烦的一点就是没有命令的提示。这就导致在上下文中如果变量比较多,自己写就很容易写错。所以所有的变量不要手写,在定义一次之后就全部复制。比如我在写的时候就出现了这个问题:sum_time=$(($sumtime+$total_time))本意是实现sum_time每次运行之后加上total_time,但sumtime和sum_time在这里被我搞混了。在计算机眼中,这是两个变量,这就导致自加失败,因为sumtime如果没有定义的情况下,默认为0

shell脚本和c语言不同之处在于,shell脚本不需要编译,而是直接运行,但是其语法与c又有相似之处。在shell脚本中,变量是不要定义的,可以直接使用比如pid=1。

shell脚本对格式的要求是比较高的,很多地方必须要加上空格比如if [ -n "$pid" ];then-n前,“pid”后必须得有空格。在if和then之间需要加;,但是在if的实现中是不需要加;的。还有比如变量的定义pid=1等号两边是不能空格的,如果写成pid = 1就错了,这些在c语言中空格等不会影响程序。

3、代码实现

function get_starttime(){

starttime=$(date +%Y-%m-%d\ %H:%M:%S)

# echo "start emulator: $starttime" | tee -a launch_time.txt

}

# function可以用来定义函数,其函数的定义格式和c比较像。

# 但是该函数没有返回值,如果调用该函数只不过是把这个函数中的代码进行移动。

# 如果定义的是函数,如果没有调用函数,该函数中的内容也不会执行。

# date指令可以实现打印时间,读者可以再终端中直接敲date命令,会显示出时间。

# %Y-%m-%d\ %H:%M:%S分别代表年月日,小时,分钟,秒:2021-03-25 17:00:22

#这个时间的格式也需要注意,因为接下来我们会用字符串出现的时间减去emulator开启的时间

# 所有变量的使用都要加上$ 不然默认的是字符串,比如pid=1,打印要变成echo $pid

function get_endtime(){

endtime=$(date +%Y-%m-%d\ %H:%M:%S)

# echo "end time:$endtime" | tee -a launch_time.txt

}

# 此处得到的是字符串出现的时间,在出现的时候获取pc的时间,如果需要查看该处的具体时间可以放开注释

# tee -a表示将内容添加到launch_time.txt中,如果没有-a,则是直接覆盖

function stop_adb(){

pid=$(ps -a | grep adb | awk '{printf $1}');

if [ -n "$pid" ]; then

kill -9 $pid

fi

}

# 由于我们是在emulator中,如果需要多次尝试开机关机,那么就需要多次开启adb,关闭adb

# 关闭adb的方法就是ps -a在开启的所有进程中grep寻找adb的进程

# awk '{printf $1}'的意思为截断输出的结果,并输出为第一列的值,如果为awk '{printf $3}'则是第三列的值

# 用kill -9来杀死对应的adb进程号

# 项目组前期使用的命令为:pid=$(netstat -anp | grep 5554|awk '{printf $7}'|cut -d/ -f1);我用我的理解进行了改进

function stop_emulator(){

pid=$(ps -a | grep qemu | awk '{printf $1}');

if [ -n "$pid" ]; then

kill -9 $pid

fi

}

# emulator为安卓模拟器,开启之后会有开机画面

function get_totaltime(){

total_time=$(($(date -d "$endtime" +%s) - $(date -d "$starttime" +%s)))

echo "NO.$num total time:$total_time s" | tee -a launch_time.txt

}

# 此处首先要注意函数的命名和变量的命名要区分开,不然在理解上容易出错,之前把函数名也定义成为了total_time

# date -d有比较强大的功能,后面跟上指令可以实现很多,比如:date -d tomorrow会输出明天的日期:2021年 03月 26日 星期五 17:07:18 CST

# 此处的作用加上了+%s,其作用是将时间转化成秒数,如果要算数运算,需要用上$(()),或者$[]

function launch_time(){

stop_adb

stop_emulator

# 为了阻止前一次的emulator没有关掉影响我们的启动,首先先确保一次emulator和adb关了

emulator -no-cache &

# emulator -no-cache为启动模拟器,&为后台运行,因为接下来的操作相等于需要在另一个终端中运行

get_starttime

# 启动之后获取此刻的pc时间

adb wait-for-devive

# 等待emulator启动成功

adb logcat > launch_time.log &

# 生成的log文档保存到 launch_time.log

while true

sleep 1

# 不停的循环去寻找成功开启的字符串,直到找到后退出while循环,sleep的原因是等log生成之后再去寻找,如果运行的太快launch_time.log中可能还没有东西

do

if grep "I ActivityTaskManager: Displayed com.eswin.tv.launcher/.homepage.HomepageActivity:" launch_time.log; then

get_endtime

# 找到字符串之后获取此刻的pc时间作为endtime

get_totaltime

# 将两个时间转化成秒然后相减

sum_time=$(($sum_time+$total_time))

# 需要统计开机的平均时间,所以先计算总时间

stop_adb

stop_emulator

# 本次时间计算完成,关闭模拟器和adb

# rm launch_time.log

break

fi

done

}

if(($1 > 0)) && (($1 < 21)) && (($2 > 0)); then

# $1为脚本的第一个入参,lunch的环境只有1~20,$2为第二个参数为需要测试的次数

stop_adb

stop_emulator

source build/envsetup.sh

lunch $1

echo "lunch target: $1"

rm launch_time.txt

echo "Number of tests: $2"

sum_time=0

# 将sum_time初始化为0,加下来循环执行开关机

for((num=1;num<=$2;num++))

do

launch_time

done

average_time=$(($sum_time/$2))

# 计算平均时间

echo | tee -a launch_time.txt

echo "$2 times in total"| tee -a launch_time.txt

echo "avergae time: $average_time s" | tee -a launch_time.txt

else

echo "please input right TARGET_PROTECT and Cycle boot times eg:./launch_time.sh 16 3"

exit 8

fi

#如果输入的情况不正确,shell退出

执行脚本,lunch的环境为riscv,在本机中为16,循环的次数为2:

./launch_time.sh 16 2

结果输出到launch_time.txt中:

NO.1 total time:157 s

NO.2 total time:162 s

2 times in total

avergae time: 159 s

本文标签: 脚本次数语言代码时间