整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Makefile实现编译时间统计

前言

最近的一个项目中,想要统计make整个项目的时间,并添加到中,生成镜像后,自动输出时间到屏幕。

调研了,发现可以使用以下两种方式来实现。

一、time工具

最简单的方式,使用time工具来统计运行脚本时间,百度百科对time命令的解释:

time命令常用于测量一个命令的运行时间

测试环境是.04, 在终端输入time命令

time
real    0m0.000s
user    0m0.000s
sys     0m0.000s

以一个驱动demo编译过程为例。

在编译目录下,运行的make动作。

make
make -C /lib/modules/`uname -r`/build M=/home/xxx/Desktop/xxx/test/driver modules
make[1]: Entering directory '/usr/src/linux-headers-5.13.0-41-generic'
  CC [M]  /home/xxx/Desktop/xxx/test/driver/msg_test.o
  MODPOST /home/xxx/Desktop/xxx/test/driver/Module.symvers
  CC [M]  /home/xxx/Desktop/xxx/test/driver/msg_test.mod.o
  LD [M]  /home/xxx/Desktop/xxx/test/driver/msg_test.ko
  BTF [M] /home/xxx/Desktop/xxx/test/driver/msg_test.ko
Skipping BTF generation for /home//home/xxx/Desktop/xxx/test/driver/msg_test.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.13.0-41-generic'
real    0m14.638s
user    0m0.663s
sys     0m0.560s

可以看到整个过程,耗时14.638秒, 用户态与内核态消耗的时间分别是0.663秒、0.560秒。

二、自行实现 思路

我们只需要在开始运行时,记录一个时间戳。执行完成时记录一个时间戳,在进行时间的相减,就可以获取总的运行时间。

1、获取开始时间戳。

可以采用linux系统的/proc/uptime来获取当前时间。

可以先分析一下/proc/uptime里面的内容,里面记录了Linux系统运行时间。

cat /proc/uptime
4643.14 34329.17

2、提取时间戳的思路

只需要用awk命令,通过.分割/proc/uptime里面的内容,就可以获取到秒的时间戳。

cat /proc/uptime | awk -F "." '{print $1}'
4643

只要在运行结束时,再获取一次/proc/time里面的秒数,前后数值相减,便可以得到时间差,即项目的运行时间。

3、date命令转换时间戳为 年月日时分秒 格式

可以通过data --help命令来查看data的用法。

data -d @时间戳 [format]

format用到以下的参数,获取日、时、分、秒

%j   day of year (001..366)
%H   hour (00..23)
%M   minute (00..59)
%S   second (00..60)

linux秒数转为时间_linux系统时间时间秒数_linux时间戳换算

此时输入的时间戳是以1970年开始作为运算。如上面获取的4643, 由于博主时UTC-8的时间,所以时间+了8小时,4643对应是9点17分23秒。

date -d @4643
1970年 01月 01日 星期四 09:17:23 CST

\- u选项

加上-u选项,可以让时间以UTC为参考,不加时区偏移。

date -u -d@4643
1970年 01月 01日 星期四 01:17:23 UTC

就可以看到时间是1点17分23秒,正好是我们的系统运行时间,4643秒。

格式化截取时分秒

date -u -d @4643 +%Hh:%Mm:%Ss
01h:17m:23s

+%Hh:%Mm:%Ss命令中的%H、%M、%S分别获取了时分秒,并以h:m:s这样的格式输出。与printf函数类似。至此便可以获取到运行时间的时分秒。

实现

原来的

DIR = $(shell pwd)
KER_DIR = /lib/modules/`uname -r`/build
obj-m = msg_netlink.o
all:
	make -C $(KER_DIR) M=$(PWD) modules
clean:
	make -C $(KER_DIR) M=$(PWD) clean

改动后的

	DIR = $(shell pwd)
	KER_DIR = /lib/modules/`uname -r`/build
	
	START_TIME = $(shell cat /proc/uptime | awk -F "." '{print $$1}') # Makefile进入,获取时间戳
	
	obj-m = msg_netlink.o
	
	all: module showruntime
	
	module: 
		make -C $(KER_DIR) M=$(PWD) modules
	
	clean:
		make -C $(KER_DIR) M=$(PWD) clean
	
	showruntime:
		@current_time=`cat /proc/uptime | awk -F "." '{print $$1}'`; \
		time_interval=`expr $${current_time} - $(START_TIME)`; \
		runtime=`date -u -d @$${time_interval} +%Hh:%Mm:%Ss`; \
		echo "######## runtime: $${runtime} ########"

分析

小知识:

中,调用自身的变量,用$符号,比如中的。中,target执行的shell命令,定义的变量,需要用$$符号调用,比如中的,因为是shell运行过程生成的变量,需要用$$来调用.同样 = $(shell cat /proc/uptime | awk -F "." '{print $$1}')中,在终端命令中,获取awk参数用$1即可,但由于是在中,调用shell,所以需要用$$1才可以获取到分割数值。运行的target中,如,里面的shell命令,如果需要做多个shell命令,需要用; \符号来连续整个shell命令,否则会报错,详细查看里面的内容。中@字符shell命令可以隐藏shell命令运行打印。

	showruntime:
		current_time=`cat /proc/uptime | awk -F "." '{print $$1}'`; \
		time_interval=`expr $${current_time} - $(START_TIME)`; \
		runtime=`date -u -d @$${time_interval} +%Hh:%Mm:%Ss`; \
		echo "######## runtime: $${runtime} ########"

输出如下, 可以看到整个shell命令都打印出来了:

make -C /lib/modules/`uname -r`/build M=/home/xxx/Desktop/xxx/test/driver modules
make[1]: Entering directory '/usr/src/linux-headers-5.13.0-41-generic'
make[1]: Leaving directory '/usr/src/linux-headers-5.13.0-41-generic'
current_time=`cat /proc/uptime | awk -F "." '{print $1}'`; \
time_interval=`expr ${current_time} - 6710 `; \
runtime=`date -u -d @${time_interval} +%Hh:%Mm:%Ss`; \
echo "######## runtime: ${runtime} ########"
######## runtime: 00h:00m:00s ########

加上@符号后, 只会打印echo出来的字符。

	showruntime:
		@current_time=`cat /proc/uptime | awk -F "." '{print $$1}'`; \
		time_interval=`expr $${current_time} - $(START_TIME)`; \
		runtime=`date -u -d @$${time_interval} +%Hh:%Mm:%Ss`; \
		echo "######## runtime: $${runtime} ########"

输出如下:

make -C /lib/modules/`uname -r`/build M=/home/xxx/Desktop/xxx/test/driver modules
make[1]: Entering directory '/usr/src/linux-headers-5.13.0-41-generic'
make[1]: Leaving directory '/usr/src/linux-headers-5.13.0-41-generic'
######## runtime: 00h:00m:00s ########

这里运行时间为0,是因为驱动已经编译过,没有改动,make clean后,再重新编译,即可以看到运行时间。

make clean
ake -C /lib/modules/`uname -r`/build M=/home/xxx/Desktop/xxx/test/driver clean
make[1]: Entering directory '/usr/src/linux-headers-5.13.0-41-generic'
  CLEAN   /home/xxx/Desktop/xxx/test/driver/Module.symvers
make[1]: Leaving directory '/usr/src/linux-headers-5.13.0-41-generic'
time make # 用了time一起统计时间
make -C /lib/modules/`uname -r`/build M=/home/xxx/Desktop/xxx/test/driver modules
make[1]: Entering directory '/usr/src/linux-headers-5.13.0-41-generic'
  CC [M]  /home/xxx/Desktop/xxx/test/driver/msg_test.o
  MODPOST /home/xxx/Desktop/xxx/test/driver/Module.symvers
  CC [M]  /home/xxx/Desktop/xxx/test/driver/msg_test.mod.o
  LD [M]  /home/xxx/Desktop/xxx/test/driver/msg_test.ko
  BTF [M] /home/xxx/Desktop/xxx/test/driver/msg_test.ko
Skipping BTF generation for /home/xxx/Desktop/xxx/test/driver/msg_test.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.13.0-41-generic'
######## runtime: 00h:00m:02s ########
real    0m2.107s
user    0m0.821s
sys     0m0.301s

可以看到 time make统计到的时间,与计算得到的时间都是2秒左右。实验结果ok。

总结 熟悉/proc/uptime里面参数的含义。可以不用/proc/uptime来获取时间戳,可以用date +%s获取当前时间戳,代替cat /proc/uptime熟悉date命令的时候,获取时间戳、格式化获取日期。仔细观看实现的小知识,这里面涉及到很多细节内容,建议反复观看。中的target依赖问题,仔细观看所在位置。中$`符号 与 $$符号的区别