1#!/bin/bash
2# kernbench by Con Kolivas <kernbench@kolivas.org>
3# based on a benchmark by Martin J. Bligh
4trap 'echo "ABORTING";exit' 1 2 15
5
6VERSION=0.42
7
8num_runs=5
9single_runs=0
10half_runs=1
11opti_runs=1
12max_runs=1
13fast_run=0
14
15while getopts vsHOMn:o:hf i
16do
17	case $i in
18		 h) 	echo "kernbench v$VERSION by Con Kolivas <kernbench@kolivas.org>"
19				echo "Usage:"
20				echo "kernbench [-n runs] [-o jobs] [-s] [-H] [-O] [-M] [-h] [-v]"
21				echo "n : number of times to perform benchmark (default 5)"
22				echo "o : number of jobs for optimal run (default 4 * cpu)"
23				echo "s : perform single threaded runs (default don't)"
24				echo "H : don't perform half load runs (default do)"
25				echo "O : don't perform optimal load runs (default do)"
26				echo "M : don't perform maximal load runs (default do)"
27				echo "f : fast run"
28				echo "h : print this help"
29				echo "v : print version number"
30				exit ;;
31		 v) echo "kernbench Version $VERSION by Con Kolivas <kernbench@kolivas.org>" ; exit ;;
32		 n) nruns=$OPTARG ;;
33		 o) optijobs=$OPTARG ;;
34		 s) single_runs=1 ;;
35		 H) half_runs=0 ;;
36		 O) opti_runs=0 ;;
37		 M) max_runs=0 ;;
38		 f) fast_run=1 ;;
39	esac
40done
41
42if [[ ! -f include/linux/kernel.h ]] ; then
43	echo "No kernel source found; exiting"
44	exit
45fi
46
47for i in time awk yes date
48do
49	iname=`which $i`
50	if [[ ! -a $iname ]] ; then
51		echo "$i not found in path, please install it; exiting"
52		exit
53	fi
54done
55
56time=`which time`
57
58if [[ $nruns -gt 0 ]] ; then
59	num_runs=$nruns
60elif [[ $fast_run -eq 1 ]]; then
61	echo "Dropping to 3 runs for fast run"
62	num_runs=3
63fi
64
65if (($num_runs < 1)) ; then
66	echo "Nothing to do; exiting"
67	exit
68fi
69
70if (($num_runs > 10)) ; then
71	echo "Are you crazy? trimming number of runs to 10"
72	num_runs=10
73fi
74
75if [[ ! -d /proc ]] ; then
76	echo "Can't find proc filesystem; exiting"
77	exit
78fi
79
80mem=`awk '/MemTotal/ {print $2}' /proc/meminfo`
81if [[ $mem -lt 4000000 && $max_runs -gt 0 ]] ; then
82	echo Less than 4Gb ram detected!
83	echo Maximal loads will not measure cpu throughput and may cause a swapstorm!
84	echo If you did not plan this, -M flag is recommended to bypass maximal load.
85fi
86
87(( single_runs *= $num_runs ))
88(( half_runs *= $num_runs ))
89(( opti_runs *= $num_runs ))
90(( max_runs *= $num_runs ))
91
92cpus=`grep -c ^processor /proc/cpuinfo`
93echo $cpus cpus found
94echo Cleaning source tree...
95make clean > /dev/null 2>&1
96
97if [[ $fast_run -eq 0 ]] ; then
98	echo Caching kernel source in ram...
99	for i in `find -type f`
100	do
101		cat $i > /dev/null
102	done
103fi
104
105if [[ ! -f .config ]] ; then
106	echo No old config found, using defconfig
107	echo Making mrproper
108	make mrproper > /dev/null 2>&1
109	echo Making defconfig...
110	make defconfig > /dev/null 2>&1
111else
112	echo Making oldconfig...
113	yes "" | make oldconfig > /dev/null 2>&1
114fi
115
116halfjobs=$(( $cpus / 2 ))
117optijobs=${optijobs:=$(( $cpus * 4 ))}
118
119if [[ $halfjobs -lt 2 ]] ; then
120	echo "Half load is no greater than single; disabling"
121	half_runs=0
122elif [[ $halfjobs -eq 2 ]] ; then
123	echo "Half load is 2 jobs, changing to 3 as a kernel compile won't guarantee 2 jobs"
124	halfjobs=3
125fi
126
127echo Kernel `uname -r`
128echo Performing $num_runs runs of
129if [[ $single_runs -gt 0 ]] ; then
130	echo make
131fi
132if [[ $half_runs -gt 0 ]] ; then
133	echo make -j $halfjobs
134fi
135if [[ $opti_runs -gt 0 ]] ; then
136	echo make -j $optijobs
137fi
138if [[ $max_runs -gt 0 ]] ; then
139	echo make -j
140fi
141echo
142
143echo All data logged to kernbench.log
144
145if [[ $fast_run -eq 0 ]] ; then
146	echo Warmup run...
147	make -j $optijobs > /dev/null 2>&1
148fi
149
150date >> kernbench.log
151uname -r >> kernbench.log
152
153add_data_point()
154{
155    echo $@ | awk '{printf "%.6f %.6f %d", $1 + $2, $1 * $1 + $3, $4 + 1}'
156}
157
158show_statistics()
159{
160    case $3 in
161	0)
162	    echo "No data"
163	    ;;
164	1)
165	    echo $1
166	    ;;
167	*)
168	    avg=`echo $1 $3 | awk '{print $1 / $2}'`
169	    var=`echo $1 $2 $3 | awk '{print ($2 - ($1 * $1) / $3) / ($3 - 1)}'`
170	    sdev=`echo $var | awk '{print $1^0.5}'`
171	    echo "$avg ($sdev)"
172	    ;;
173    esac
174}
175
176do_log()
177{
178	echo "Average $runname Run (std deviation):" > templog
179	echo Elapsed Time  `show_statistics $temp_elapsed` >> templog
180	echo User Time  `show_statistics $temp_user` >> templog
181	echo System Time  `show_statistics $temp_sys` >> templog
182	echo Percent CPU  `show_statistics $temp_percent` >> templog
183	echo Context Switches  `show_statistics $temp_ctx` >> templog
184	echo Sleeps  `show_statistics $temp_sleeps` >> templog
185	echo >> templog
186	cat templog
187	cat templog >> kernbench.log
188}
189
190do_runs()
191{
192	temp_elapsed="a"
193	for (( i=1 ; i <= temp_runs ; i++ ))
194	do
195		echo $runname run number $i...
196		make clean > /dev/null 2>&1
197		sync
198		if [[ $fast_run -eq 0 ]] ; then
199			sleep 5
200		fi
201		$time -f "%e %U %S %P %c %w" -o timelog make -j $tempjobs > /dev/null 2>&1
202		read elapsed_time user_time sys_time percent ctx sleeps <timelog
203		temp_elapsed=`add_data_point $elapsed_time $temp_elapsed`
204		temp_user=`add_data_point $user_time $temp_user`
205		temp_sys=`add_data_point $sys_time $temp_sys`
206		temp_percent=`add_data_point $percent $temp_percent`
207		temp_ctx=`add_data_point $ctx $temp_ctx`
208		temp_sleeps=`add_data_point $sleeps $temp_sleeps`
209	done
210	if [[ $temp_runs -ne 0 ]] ; then
211		do_log
212	fi
213}
214
215temp_runs=$single_runs
216tempjobs=1
217runname="Single threaded"
218do_runs
219
220temp_runs=$half_runs
221tempjobs=$halfjobs
222runname="Half load -j $halfjobs"
223do_runs
224
225temp_runs=$opti_runs
226tempjobs=$optijobs
227runname="Optimal load -j $optijobs"
228do_runs
229
230temp_runs=$max_runs
231tempjobs=""
232runname="Maximal load -j"
233do_runs
234