From c235b4f55a3aa4c9be35b30ab459f5ed550d2e12 Mon Sep 17 00:00:00 2001 From: Thorsten Leemhuis Date: Oct 15 2007 16:06:25 +0000 Subject: import package -- review #326831 --- diff --git a/kcbench b/kcbench new file mode 100644 index 0000000..992b355 --- /dev/null +++ b/kcbench @@ -0,0 +1,443 @@ +#!/bin/bash +# +# kcbench - kernel compile benchmark +# Copyright (c) 2007 Thorsten Leemhuis +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +# this is me +myprog_name=kcbench +myprog_version=0.1.1 + +# set some defaults -- called before cmdoptions are parsed +kcbench_init () +{ + # verbose? + verboselevel=2 + + # results are normally stable, thus 3 runs after filling the cache should normally be enough + default_number_of_iterations=3 + + # used together with make -j + # number of CPUs * 2 + default_number_of_jobs=$(($(grep '^processor' < /proc/cpuinfo | wc -l)*2)) + + # we search for kernels to compile here + # note that I didn't use /usr/src/ on purpose as localtion -- kernels there + # might be modified + default_sources_dir="/usr/share/kcbench-data/" + + # optional: retrieve settings from file + if [[ -e "${HOME}/.kcbench" ]]; then + source "${HOME}/.kcbench" + fi +} + + +# check everthing before starting +kcbench_startupchecks() +{ + # check for tools we need + # thinkaboutme: there are likely more needed + for tool in make gcc ld ; do + if ! which ${tool} &> /dev/null ; then + echo "Could not find ${tool}" + exit 2 + fi + done + + # check if cron or other stuff runs and give a warning + if [[ ! "${ignore_running_apps}" ]]; then + local runningtasks="$(echo $(ps -A | grep --word -e crond -e httpd -e atd -e sendmail -e smbd | awk '{print $4}' | sort | uniq))" + if [[ "${runningtasks}" ]] ; then + echo "WARNING: The following daemons run and might disturb the benchmark: ${runningtasks}; use '--ignore-running-apps' to disabled this warning" >&2 + sleep 5 + fi + fi + + + # find a srctree to compile! + if [[ "${compile_srctree}" ]]; then + # user provided some informations what kernel to use + if [[ -e "${compile_srctree}/include/linux/kernel.h" ]] ; then + # is a local tree -- but we need the full path! + if [[ "${compile_srctree}" == "${compile_srctree##/}" ]]; then + dir_sources="${PWD}/${compile_srctree}" + else + dir_sources="${compile_srctree}" + fi + elif [[ -e "${default_sources_dir}/linux-${compile_srctree}/include/linux/kernel.h" ]]; then + # user meant one of our trees by just giving version number + dir_sources="${default_sources_dir%%/}/linux-${compile_srctree%%/}/" + else + echo "Could neither find directory ${compile_srctree} nor ${default_sources_dir%%/}/linux-${compile_srctree%%/}/" >&2 + exit 2 + fi + else + # we are own our own + + # without our std-dir it doesn't make sense to continue + if [[ ! -d "${default_sources_dir}" ]]; then + echo "${default_sources_dir} not found." >&2 + exit 2 + fi + + # use the latest one by default + dir_sources="${default_sources_dir%%/}/$(ls -r "${default_sources_dir}" | head -n 1)" + if [[ ! -e "${dir_sources}/include/linux/kernel.h" ]]; then + echo "Found ${default_sources_dir}, but doesn't look like a kernel srctree." >&2 + exit 2 + fi + fi + + + # on testsystems the date often is set incorectly, thus check it to prevent misscompiles + if (( $(date -r "${dir_sources}/Makefile" "+%s") > $(date "+%s") )); then + echo "Makefile is younger then current date; please set your system time properly." >&2 + exit 2 + fi + + + # create tempdir and remove it on exit + trap 'kcbench_exit 127' 1 2 15 + if [[ "${dir_topoutput}" ]]; then + # dir_topoutput present? + if [[ ! -d "${dir_topoutput}" ]]; then + echo "Could not find ${dir_topoutput}" >&2 + exit 2 + fi + if [[ "${dir_topoutput}" == "${dir_topoutput##/}" ]]; then + # we need the full path + dir_topoutput="${PWD}/${dir_topoutput}" + fi + + # if our dir in dir_topoutput exist already just use it + if [[ -d "${dir_topoutput%%/}/${myprog_name}" ]]; then + readonly dir_outputtmp="${dir_topoutput%%/}/${myprog_name}" + else + readonly dir_outputtmp=$(mktemp -d ${dir_topoutput%%/}/${myprog_name}) + fi + else + # use a tmp dir + readonly dir_outputtmp=$(mktemp -d -t ${myprog_name}.XXXXXXXXX) + fi + + # did dir get created? + local returncode=$? + if (( "${returncode}" > 0 )) || [[ ! -d "${dir_outputtmp}" ]]; then + echo "Could not create temporary output directory" >&2 + exit 2 + fi + + if [[ "${savefailedlogs}" ]] && [[ ! -d "${savefailedlogs}" ]] ; then + echo "Could not find ${savefailedlogs}." >&2 + exit 2 + fi + + + # how many jobs? + if [[ ! "${number_of_jobs}" ]]; then + # use default + number_of_jobs=${default_number_of_jobs} + else + # user provided number of jobs; but check user input + for number in ${number_of_jobs}; do + # is number_of_jobs a real number? + if (( ! ${number} > 0 )) ; then + echo "Please provide a real number together with --jobs" >&2 + exit 2 + fi + done + fi + + + # is number_of_iterations a real number? + if [[ ! "${number_of_iterations}" ]] ; then + # use default + if [[ "${run_infinite}" ]]; then + # when running infinite just 1 + number_of_iterations=1 + else + number_of_iterations=${default_number_of_iterations} + fi + elif (( ! ${number_of_iterations} > 0 )) ; then + echo "Please provide a real number together with --ilterations" >&2 + exit 2 + fi + + + # create a logdirectory in dir_outputtmp + [[ ! -d "${dir_outputtmp}/kcbench" ]] && mkdir "${dir_outputtmp}/kcbench" + kcbench_logdir="${dir_outputtmp}/kcbench/" + kcbench_logfile="${dir_outputtmp}/kcbench/log" + touch "${kcbench_logfile}" + + + + # disable sceensaver (should we reset this? how?) + setterm -blank 0 +} + + +kcbench_exit() +{ + kcbench_echo 1 4 "Removing ${dir_outputtmp}" + + if [[ "${dir_outputtmp}" ]] && [[ -d "${dir_outputtmp}" ]]; then + # the directory should contain our name, thus check it to be on the safe side + if echo "${dir_outputtmp}" | grep "${myprog_name}" &> /dev/null ; then + rm -rf "${dir_outputtmp}" + else + echo "Leaving ${dir_outputtmp} behind" >&2 + fi + fi + + exit ${1} +} + +kcbench_echo () +{ + # where to output + local this_fd=${1} + shift + + # verboselevel + local this_verbose=${1} + shift + + # output + if (( ${verboselevel} >= ${this_verbose} )); then + echo "$@" >&${this_fd} + echo "$@" >> "${kcbench_logfile}" + fi +} + +kcbench_main() +{ + # info + kcebench_sysinfo 2 + + # create defconfig + kcbench_echo 1 3 "Creating default configuration with 'make defconfig'." + make O="${dir_outputtmp}" -C "${dir_sources}" -j ${default_number_of_jobs} defconfig >> "${kcbench_logdir}"/make_defconfig 2>&1 + + # prepration run + if [[ ! "${no_cachefill}" ]]; then + # Note: I tried to use something like this first: + # find "${dir_sources}" -type f | grep -e '.h$' -e '.c$' -e 'Makefile' -e 'Kconfig' -e 'Kbuild' -e '.S$' | xargs cat > /dev/null + # But it does not work as good as a thrown-away compile-run + + # only print result in verbose mode + (( ${verboselevel} == 2 )) && kcbench_echo 1 2 -n "Filling caches: This might take a while..." + kcbench_compile_kernel 3 ${default_number_of_jobs} run-0-fillcaches "Filling caches: " + kcbench_echo 1 3 "-------------------------------------------------------------------------------" + # is there a better way to move the cursor to the left? + (( ${verboselevel} == 2 )) && kcbench_echo 1 2 -e "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bFilling caches: Done " + fi + + # go + local totalruns=1 + local errorruns=0 + while : ; do + for number in ${number_of_jobs}; do + for ((run=1; run <= number_of_iterations ; run++)) ; do + kcbench_compile_kernel 1 ${number} "run${totalruns}" "$(printf "%-20s" "Run ${totalruns} (-j ${number}):")" + local returncode=$? + if (( ${returncode} > 0 )); then + let errorruns++ + fi + let totalruns++ + done + done + + if (( ${errorruns} > 0 )) ; then + kcbench_echo 1 1 "Total erroruns: ${errorruns}" + fi + + if [[ ! "${run_infinite}" ]]; then + # get out of the while loop + break + fi + done +} + + +kcbench_compile_kernel() +{ + local this_verboselevel="${1}" + local this_nrjobs="${2}" + local this_logfile="${kcbench_logdir%%/}/${3}" + local this_msgstart="${4}" + + echo "make O=${dir_outputtmp} -C ${dir_sources} -j ${this_nrjobs} vmlinux" > "${this_logfile}" + kcbench_echo 1 4 "Running 'make O=${dir_outputtmp} -C ${dir_sources} -j ${this_nrjobs} vmlinux'" + + kcbench_echo 1 ${this_verboselevel} -n "${this_msgstart}" + + + if /usr/bin/time -o "${this_logfile}.time" -f "P:%P R:%e U:%U S:%S" make O="${dir_outputtmp}" -C "${dir_sources}" -j ${this_nrjobs} vmlinux >> "${this_logfile}" 2>&1 ; then + local time_points="$(echo 1000000/$(cut -d ' ' -f 2 < "${this_logfile}.time" | cut -d ':' -f 2) | /usr/bin/bc)" + local time_details="$(cat "${this_logfile}.time")" + kcbench_echo 1 ${this_verboselevel} "${time_points} (${time_details})" + else + kcbench_echo 2 1 "Failed ($(date))." + + if [[ "${savefailedlogs}" ]]; then + # safe log and continue + kcbench_echo 2 2 "Saving logfile to ${savefailedlogs}/kcbench-$(basename ${this_logfile})" + cp "${this_logfile}" "${savefailedlogs}/kcbench-$(basename ${this_logfile})" + elif [[ "${run_infinite}" ]]; then + return 1 + else + # what to do with the logfile? + read -n 1 -s -t 300 -p "Hit 'l' within 300 seconds to view log-file." answer + echo + + if [[ "${answer}" == [lL] ]]; then + less "${this_logfile}" + fi + + # end + kcbench_exit 2 + fi + fi + + # cleanup + kcbench_echo 1 3 "Cleaning up builddir" + make O="${dir_outputtmp}" -C "${dir_sources}" -j ${default_number_of_jobs} clean &> "${kcbench_logdir}/make_clean" +} + +# basic information about the system +kcebench_sysinfo() +{ + kcbench_echo 1 ${1} "Linux running: $(uname -r)" + kcbench_echo 1 ${1} "Compiler: $(gcc --version | head -n 1)" + kcbench_echo 1 ${1} "CPU: $(grep '^processor' < /proc/cpuinfo | wc -l) x $(grep 'model name' /proc/cpuinfo | sed 's!model name\t: !!' | sort | uniq)" + kcbench_echo 1 ${1} "Memory: $(( $(awk '/MemTotal:/ { print $2}' /proc/meminfo) / 1024 )) MByte" + kcbench_echo 1 ${1} "Linux compiled: $(basename "${dir_sources}") (${dir_sources})" +} + +myprog_help() +{ + echo "Usage: ${myprog_name} [options]" + echo $'\n'"Compiles a kernel and messures the time it takes" + echo $'\n'"Available options:" + echo " --compiledir -- use /kcbench for compile results (O=)" + echo " --ignore-running-apps -- Do not warn if cron or other daemons run" + echo " --infinite -- run endlessly" + echo " --iterations -- number or iterations" + echo " --jobs -- number of jobs to use ('make -j #') (*)" + echo " --no-cachefill -- omit the initial kernel compile to fill caches" + echo " --verbose -- increase verboselevel (*)" + echo " --savefailedlogs -- save log of failed compile runs in " + echo " --src (|) -- take sources in or from" + echo " /usr/share/kcdata/linux-" + echo + echo " --help -- this text" + echo " --version -- output program version" + echo + echo "(*) -- option can be past multiple times" +} + + +# set defaults which might get overwritten my command line parameters +kcbench_init + + +# parse cmdline options +while [ "${1}" ] ; do + case "${1}" in + --compiledir) + shift + dir_topoutput="${1}" + shift + ;; + --jobs) + shift + # without quotes, to make --jobs "4 8 16 32" possible + number_of_jobs="${number_of_jobs} ${1}" + shift + ;; + --ignore-running-apps) + shift + ignore_running_apps="true" + ;; + --infinite) + shift + run_infinite="true" + ;; + --iterations) + shift + number_of_iterations="${1}" + shift + ;; + --no-cachefill) + shift + no_cachefill="true" + ;; + --quiet) + verboselevel="1" + shift + ;; + --savefailedlogs) + shift + savefailedlogs="${1}" + shift + ;; + --src) + shift + compile_srctree="${1}" + shift + ;; + --verbose) + shift + let verboselevel++ + ;; + --help) + myprog_help + exit 0 + ;; + --version) + echo "${myprog_name} ${myprog_version}" + exit 0 + ;; + --*) + echo "Error: Unknown option '${1}'." >&2 + myprog_help >&2 + exit 2 + ;; + *) + list_of_packages="${list_of_packages} ${1}" + shift + ;; + esac +done + +# startup checks +kcbench_startupchecks + +# go +kcbench_main + +# cleanup +kcbench_exit + +exit 0 diff --git a/kcbench-README b/kcbench-README new file mode 100644 index 0000000..e8114fd --- /dev/null +++ b/kcbench-README @@ -0,0 +1,102 @@ +kcbench - Kernel compile benchmark + +## About + +Kcbench compiles a Linux kernel to benchmark a system or test system stability + + +## Available options: + + --compiledir + Use the subdirectory kcbench in / for compile results -- passes + 'O= /kcbench/' to make when calling it to compile a kernel; use a + tempdir if not given + + --ignore-running-apps + Do not warn if cron or other daemons run in the background; the results + might not be stable when those run and call jobs that consume CPU time or + do a lot of I/O + + --infinite + run endlessly to test system stability + + --iterations + Number or iterations per number of jobs (default: 3) + + --jobs + Number of jobs to use ('make -j #'); option can be given multiple times + (default: number of CPUs * 2) + + --no-cachefill + Omit the initial kernel compile to fill caches; saves time, but first + result might be slightly lower then the following ones + + --verbose + Increase verboselevel; option can be given multiple times + + --savefailedlogs + Save log of failed compile runs in + + --src (|) + Take sources in or from /usr/share/kcdata/linux- + + --help + Show usage + + --version + Output program version + + +## Examples: + + $ kcbench + Takes newest kernel from /usr/share/kcdata/ and compiles three times + + $ kcbench--iterations 3 --jobs 2 --jobs 4 + Compile 3 times with 2 jobs and three times with 4 jobs + + +## Example output: + +$ kcbench --iterations 2 --jobs 2 --jobs 4 --jobs 8 --ignore-running-apps +Linux running: 2.6.23-0.222.rc9.git4.fc8 +Compiler: gcc (GCC) 4.1.2 20070925 (Red Hat 4.1.2-31) +CPU: 2 x Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz +Memory: 1964 MByte +Linux compiled: linux-2.6.20 (/usr/share/kcbench-data/linux-2.6.20) +Filling caches: Done +Run 1 (-j 2): 5858 (P:195% R:170.70 U:263.51 S:69.42) +Run 2 (-j 2): 5830 (P:194% R:171.51 U:263.92 S:69.39) +Run 3 (-j 4): 5727 (P:193% R:174.60 U:267.12 S:70.42) +Run 4 (-j 4): 5779 (P:194% R:173.03 U:266.74 S:70.09) +Run 5 (-j 8): 5636 (P:191% R:177.43 U:270.14 S:70.39) +Run 6 (-j 8): 5607 (P:190% R:178.32 U:269.64 S:70.88) + + +## Results + +In this example + + Run 1 (-j 4): 5775 (P:192% R:173.15 U:263.49 S:69.42) + +is has taken 173.15 seconds real time (R) to compile the kernel; the CPU-Usage +(P) was 192 percent; user time (U) spend was 296.49 and sys time (S) 69.42. + +As most people prefer if higher numbers mean faster systems -- to give them +what they expect kcbench divides 1000000 by the real time spend, which results +in 5775 kcbench points (1000000/173.15) in this example. + + +## Usage hints + + * sometimes using exactly as much jobs as processors in the system results in + the a result faster than the default (two times the number of processors) + + * the compiler has a huge impact on the results; if you compare results from + different machines make sure they use the same one + + * the kernel that is being compiled of course has a huge impact as well; + compare only results where you compiled the same kernel version + + +## EOF diff --git a/kcbench.spec b/kcbench.spec new file mode 100644 index 0000000..d94b876 --- /dev/null +++ b/kcbench.spec @@ -0,0 +1,58 @@ +Name: kcbench +Version: 0.1 +Release: 2 +Summary: Kernel compile benchmark + +Group: Applications/System +License: MIT +URL: http://fedoraproject.org/wiki/Packages/kcbench +Source0: kcbench +Source1: %{name}-README + +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildArch: noarch + +# data we compile; no need for a specific version; +Requires: kcbench-datafiles +# needed for compiling a kernel: +Requires: make gcc binutils +# needed for kcbench +Requires: %{_bindir}/time %{_bindir}/bc + +%description +Compiles a linux kernel to benchmark a system or test system stability. + + +%prep +%setup -q -c -T +echo "Nothing to prep" + + +%build +echo "Nothing to build" + + +%install +rm -rf ${RPM_BUILD_ROOT} +install -D -p -m 0755 %{SOURCE0} ${RPM_BUILD_ROOT}%{_bindir}/kcbench +install -D -p -m 0644 %{SOURCE1} ./README + + +%clean +rm -rf ${RPM_BUILD_ROOT} + + +%files +%defattr(-,root,root,-) +%doc README +%{_bindir}/kcbench + + +%changelog +* Sat Oct 13 2007 Thorsten Leemhuis - 0.1-2 +- require make gcc and binutils, needed for kernel compile +- require /usr/bin/{time,bc} for kcbench +- include a README file + +* Mon Oct 01 2007 Thorsten Leemhuis - 0.1-1 +- initial package