#! /bin/bash # a script to mechanically generate a bunch of compilation variants # # #Scope: Platforms {RHEL8,Rawhide} # Compilers {GCC,LLVM} # Architectures {x86-64,ppc64le} (?) # CFLAGS {-O0,-O2} x {-flto,} x {-g,-gdwarf-4,-gdwarf-5} x {-gsplit-dwarf,} # Consumers {systemtap,gdb,lldb} (?) # upon some nontrivial program, like systemtap build_rpm () { local compiler="$1" local options="$2" local variant="$3" local spec_file="$4" case $compiler in gcc) cc=gcc cxx=g++ ;; clang) cc=clang cxx=clang++ ;; *) echo "unknown compiler $compiler" exit 1 ;; esac echo export CC=$cc echo export CXX=$cxx echo building "rpmbuild --define \"%optflags $options\" --define \"%dist $name\" -bi $spec_file" export CC=$cc export CXX=$cxx rpmbuild --define "%optflags $options" --define "%dist $variant" -bi $spec_file } set_debug_links () { broot=$1 pushd ${broot} exec_dirs=$(find -type f -executable -exec file -i '{}' \; | grep 'charset=binary' | awk -F: '{print $1}' | sed 's/\(.*\)\/.*/\1/' |sort|uniq) for a_dir in $exec_dirs ; do rm -rf ${broot}/${a_dir}/.debug ln -s ${broot}/usr/lib/debug/${a_dir} ${broot}/${a_dir}/.debug done popd } analyze_rpm () { local compiler="$1" local options="$2" local variant="$3" local spec_file="$4" local file_of_interest=$5 echo "analyze ${file_of_interest} in ${spec_file}" #find the directory echo $spec_file base=${spec_file%.spec} echo $base broot=$(ls -d ~/rpmbuild/BUILDROOT/${base}*${variant}.*) if test -z ${broot}; then # exit 1 return fi bdir=/usr/bin ldir=$(rpm --eval "%_libdir") # set up debuginfo links set_debug_links ${broot} # compute some simple metrics # count number of statements with a line record # (= number of breakpointable points) foi=$(basename ${file_of_interest}) foi_dir=$(dirname ${file_of_interest}) pushd ${broot}${foi_dir} probe_lines="process(\"./${foi}\").statement(\"*@*:*\")" num_breakpoints=$(stap -l ${probe_lines} | wc -l) # then for all statements with a line record, # count number of variables with consumer-supported location lists probe_variables="process(\"./${foi}\").statement(\"*@*:*\")" num_variables=$(stap -L ${probe_variables} | sed "s, \\$,\n \\$,g" |grep -c " \\$") popd # store the info key=$(echo $name | tr '_' ',' |tr -d '.') #add arch to variant info to key key="${key},$(arch)" echo "${key},${num_breakpoints},${num_variables}" >> $data_file } find_base_optflags () { local orig_optflags=$(rpm --eval %optflags) local _optflags #remove -g and -O2 _optflags=${orig_optflags/-g/} _optflags=${_optflags/-O2/} # turn off compiler options as workarounds for llvm # _optflags="${_optflags%-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1}" # _optflags="${_optflags%-specs=/usr/lib/rpm/redhat/redhat-annobin}" # _optflags="${_optflags/-Wall/}" _optflags="${_optflags/-fstack-clash-protection/}" _optflags="${_optflags} -Wno-narrowing" echo ${_optflags} } driver () { local spec_file=$1 local file_of_interest=$2 local base_name=$(rpm --eval "%dist") local base_optflags=$(find_base_optflags) arch=$(arch) for compiler in "gcc" ; do for lto in "" "-flto -ffat-lto-objects"; do for opt_level in "-O2"; do for debug in "-g"; do for split in ""; do optflags="$lto $opt_level $debug $split $base_optflags" case $compiler in gcc) compiler_name="_gcc" ;; clang) compiler_name="_llvm" ;; esac if test -n "$lto"; then lto_name="_lto" else lto_name="_" fi case $opt_level in -O0) opt_name="_o0" ;; -O2) opt_name="_o2" ;; esac case $debug in -g) debug_name="_g" ;; -gdwarf-4) debug_name="_d4" ;; -gdwarf-5) debug_name="_d5" ;; esac case $split in -gsplit-dwarf) split_name="_split" ;; *) split_name="_" ;; esac # generate name name="${base_name}${compiler_name}${opt_name}${lto_name}${debug_name}${split_name}" echo "$compiler" "$optflags" "$name" "$spec_file" build_rpm "$compiler" "$optflags" "$name" "$spec_file" analyze_rpm "$compiler" "$optflags" "$name" "$spec_file" "$file_of_interest" done done done done done } exec_base_name=$(basename $2) pwd=$(pwd) data_file="$(pwd)/${exec_base_name}_data_file.txt" rm -rf ${data_file} driver $1 $2