#!/bin/bash set -euf -o pipefail scripts=$(dirname $0) # shellcheck source=jenkins-helpers.sh . $scripts/jenkins-helpers.sh # shellcheck source=round-robin.sh . $scripts/round-robin.sh convert_args_to_variables "$@" obligatory_variables rr[ci_project] rr[ci_config] declare -A rr # tcwg_aosp-code_size-{aosp_modules} IFS=- read -a ci_project </dev/null & if ! wait $!; then # Wipe AOSP checkout on clean errors cd .. rm -rf "$dir" mkdir "$dir" cd "$dir" fi # Resync on superproject change if ! [ -f repo_synced ] \ || [ x"$(cat repo_synced)" != x"$superproject_rev" ]; then rm -f repo_synced local manifest_url manifest_branch manifest_rev # Add a newline after supermanifest file to avoid "read" exiting with # "1" due to EOF. read manifest_url manifest_branch manifest_rev \ < <(cat "$supermanifest"; echo) manifest_url="https://android.googlesource.com/$manifest_url" rm -rf ./.repo/repo repo init --partial-clone --clone-filter=blob:limit=10M \ --use-superproject -u "$manifest_url" -b "$manifest_branch" # Use manifest specified in superproject. We then use --nmu option # to "repo sync" to avoid manifest update. git -C .repo/manifests fetch "$manifest_url" "$manifest_rev" git -C .repo/manifests checkout FETCH_HEAD # FIXME: # Repo doesn't [yet] support fetching custom revisions of # superproject. We workaround that by hacking command line # for "git fetch branch:branch" to "git fetch SHA1:branch". # This hack is effective only when we have $manifest_branch # specified in "repo init", so don't remove "-b" option in "repo init". sed -i -e "s#\[self._branch + \":\" + self._branch\]#\['$superproject_rev' + \":\" + self._branch\]#" ./.repo/repo/git_superproject.py ./.repo/repo/repo sync --nmu -j"$(nproc --all)" -q & if ! wait $!; then ./.repo/repo/repo sync --nmu -j1 --fail-fast fi # FIXME: # Verify that "repo sync" fetched the desired revision of superproject. local super_git super_rev super_git=$(find ./.repo/exp-superproject/ -name "*-superproject.git") super_rev=$(git -C "$super_git" rev-parse "$manifest_branch") assert_with_msg "Could not hack superproject repo" \ [ "$super_rev" = "$superproject_rev" ] echo "$superproject_rev" > repo_synced fi ) } # Build AOSP's LLVM build_aosp_toolchain () { ( set -euf -o pipefail clone_repo toolchain_superproject clone_aosp llvm-toolchain "$(get_current_git toolchain_superproject_rev)" \ "$(pwd)/toolchain_superproject/.supermanifest" cd llvm-toolchain assert_with_msg "Missing repo_synced file" [ -f repo_synced ] # Check if sources were updated and rebuild AOSP toolchain on re-syncs. if [ -f out/stage2/cmake_invocation.sh ] \ && [ out/stage2/cmake_invocation.sh -ot repo_synced ]; then # Re-generate cmake recipe rm out/stage2/cmake_invocation.sh fi # Reproduce AOSP toolchain to get the cmake recipe if ! [ -f out/stage2/cmake_invocation.sh ]; then rm -rf out python toolchain/llvm_android/build.py --no-build lldb,windows \ --skip-runtimes --skip-tests --skip-package fi ) } # Build LLVM build_shadow_llvm () { ( set -euf -o pipefail clone_repo llvm cd llvm-toolchain local cc cxx ninja cc=$(cat out/stage2/cmake_invocation.sh \ | grep -e " -DCMAKE_C_COMPILER=" \ | sed -e "s/.* -DCMAKE_C_COMPILER=\([^ ]*\).*/\1/") cxx=$(cat out/stage2/cmake_invocation.sh \ | grep -e " -DCMAKE_CXX_COMPILER=" \ | sed -e "s/.* -DCMAKE_CXX_COMPILER=\([^ ]*\).*/\1/") ninja=$(cat out/stage2/cmake_invocation.sh \ | grep -e " -DCMAKE_MAKE_PROGRAM=" \ | sed -e "s/.* -DCMAKE_MAKE_PROGRAM=\([^ ]*\).*/\1/") cd .. local workspace workspace=$(pwd) # ${workspace:?}/bin is to avoid shellcheck warning that below never # expands to "rm -rf /bin" rm -rf "${workspace:?}/bin" mkdir "$workspace/bin" cat > "$workspace/bin/cc" < "$workspace/bin/c++" <> $run_step_top_artifacts/results echo "$success_code" >> $run_step_top_artifacts/results else echo "# shadow build has errors" >> $run_step_top_artifacts/results cp shadow.errors $run_step_top_artifacts/ exit 1 fi if [ -f shadow.size ]; then cp shadow.size $run_step_top_artifacts/size.csv success_code=$(($success_code + 1)) echo "# shadow.size present" >> $run_step_top_artifacts/results echo "$success_code" >> $run_step_top_artifacts/results fi ) } # Exit with code 0 if no regression compared to base-artifacts/results. no_regression_p () { ( set -euf -o pipefail no_build_regression_p "$@" if ! [ -f base-artifacts/size.csv ]; then return 0 elif ! [ -f $run_step_top_artifacts/size.csv ]; then return 1 fi # Fetch first-size.csv local -a first_size_csv readarray -t first_size_csv < <(get_git_history -1 base-artifacts size.csv) if [ ${#first_size_csv[@]} = 2 ]; then cp "${first_size_csv[1]}" $run_step_artifacts/first-size.csv else cp $run_step_top_artifacts/size.csv $run_step_artifacts/first-size.csv fi rm -rf "${first_size_csv[0]}" # Generate results-vs-first/results.csv and results-vs-prev/results.csv mkdir -p $run_step_top_artifacts/results-vs-first $scripts/../bmk-scripts/csvs2table.py \ --relative $run_step_artifacts/first-size.csv \ $run_step_top_artifacts/size.csv \ > $run_step_top_artifacts/results-vs-first/results.csv mkdir -p $run_step_top_artifacts/results-vs-prev $scripts/../bmk-scripts/csvs2table.py \ --relative "$(pwd)/base-artifacts/size.csv" \ $run_step_top_artifacts/size.csv \ > $run_step_top_artifacts/results-vs-prev/results.csv # Read result lines from <(tail -n +2 ...) below. # "-n +2" is to skip the header line. local -a arr local rel_text text1 text2 metric total1=0 total2=0 while IFS=, read -a arr; do binary=${arr[0]} rel_text=${arr[2]} text1=${arr[3]} text2=${arr[4]} if [ x"$rel_text" = x"n/a" ]; then case "$text1":"$text2" in "-1:-1") ;; "-1":*) echo "-1,$binary now builds successfully" \ >> $run_step_artifacts/binary.improvements ;; *:"-1") echo "1,$binary now fails to build" \ >> $run_step_artifacts/binary.regressions ;; esac continue fi metric=$(($rel_text - 100)) if [ $metric -lt 0 ]; then echo "$metric,$binary reduced in size by ${metric}% from $text1 to $text2" \ >> $run_step_artifacts/binary.improvements elif [ $metric -gt 0 ]; then echo "$metric,$binary increased in size by ${metric}% from $text1 to $text2" \ >> $run_step_artifacts/binary.regressions fi total1=$(($total1 + $text1)) total2=$(($total2 + $text2)) done < <(tail -n +2 $run_step_top_artifacts/results-vs-prev/results.csv) if [ $total1 != 0 ]; then metric=$(((100 * $total2) / $total1 - 100)) else # Corner case when baseline results have no intersection with # the current results. This happens when AOSP build fails and # size.csv only has the header. metric=0 fi if [ $metric -lt 0 ]; then echo "$metric,AOSP reduced in size by ${metric}% from $total1 to $total2" \ >> $run_step_artifacts/aosp.improvements elif [ $metric -gt 0 ]; then echo "$metric,AOSP increased in size by ${metric}% from $total1 to $total2" \ >> $run_step_artifacts/aosp.regressions fi local primary_change="" regression=false if [ -f $run_step_artifacts/aosp.regressions ]; then primary_change=$run_step_artifacts/aosp.regressions regression=true elif [ -f $run_step_artifacts/binary.regressions ]; then primary_change=$run_step_artifacts/binary.regressions regression=true elif [ -f $run_step_artifacts/aosp.improvements ]; then primary_change=$run_step_artifacts/aosp.improvements elif [ -f $run_step_artifacts/binary.improvements ]; then primary_change=$run_step_artifacts/binary.improvements fi if [ x"$primary_change" != x"" ]; then sort -gr -o "$primary_change" "$primary_change" if $regression; then head -n1 "$primary_change" \ | sed -e "s/^/# /" > $run_step_artifacts/results.regressions fi fi case "${rr[ci_project]}" in "tcwg_aosp-build"*) # We have passed no_build_regression_p() check above, # so succeed. return 0 ;; esac local -a changed_components IFS=" " read -r -a changed_components <<< "$(print_changed_components)" case " ${changed_components[*]} " in *" llvm "*) ;; *) # Code-size builds without changed LLVM we declare as # non-regressing. Code-size changes are due to changes in AOSP, # not in the compiler. return 0 ;; esac if $regression; then return 1 fi return 0 ) } rr[breakup_changed_components]="breakup_changed_components llvm" case "${rr[ci_project]}" in "tcwg_aosp-build"*) run_step stop_on_fail 0 reset_artifacts run_step skip_on_fail 1 build_aosp_toolchain run_step skip_on_fail 2 build_shadow_llvm run_step skip_on_fail 3 build_aosp run_step skip_on_fail x process_shadow_data -- 3 ;; *) run_step stop_on_fail -10 reset_artifacts run_step skip_on_fail -3 build_aosp_toolchain run_step skip_on_fail -2 build_shadow_llvm run_step skip_on_fail -1 build_aosp run_step skip_on_fail x process_shadow_data -- -1 ;; esac run_step reset_on_fail x check_regression trap "" EXIT