| 1 | #!/usr/bin/env bash
 | 
| 2 | #
 | 
| 3 | # Usage:
 | 
| 4 | #   test/coverage.sh <function name>
 | 
| 5 | 
 | 
| 6 | set -o nounset
 | 
| 7 | set -o pipefail
 | 
| 8 | set -o errexit
 | 
| 9 | 
 | 
| 10 | REPO_ROOT=$(cd "$(dirname $0)/.."; pwd)
 | 
| 11 | source build/common.sh  # $CLANG_DIR
 | 
| 12 | 
 | 
| 13 | html-report() {
 | 
| 14 |   local out_dir=$1
 | 
| 15 |   shift  # other args are suites
 | 
| 16 | 
 | 
| 17 |   local -a args=()
 | 
| 18 |   local -a to_merge=()
 | 
| 19 | 
 | 
| 20 |   for subdir in "$@"; do
 | 
| 21 |     local prof_dir="_test/$subdir"
 | 
| 22 |     local bin_dir="_bin/$subdir"
 | 
| 23 | 
 | 
| 24 |     # args for merging
 | 
| 25 |     to_merge+=($prof_dir/*.profraw)
 | 
| 26 | 
 | 
| 27 |     # args for reporting (weird syntax)
 | 
| 28 |     for b in $bin_dir/*; do
 | 
| 29 |       if ! test -f $b; then  # skip mycpp/examples, which is a dir
 | 
| 30 |         continue
 | 
| 31 |       fi
 | 
| 32 |       args+=(--object $b)
 | 
| 33 |     done
 | 
| 34 | 
 | 
| 35 |   done
 | 
| 36 | 
 | 
| 37 |   local merged=$out_dir/ALL.profdata
 | 
| 38 | 
 | 
| 39 |   $CLANG_DIR/bin/llvm-profdata merge -sparse "${to_merge[@]}" \
 | 
| 40 |     -o $merged
 | 
| 41 | 
 | 
| 42 |   # https://llvm.org/docs/CommandGuide/llvm-cov.html
 | 
| 43 | 
 | 
| 44 | 
 | 
| 45 |   # Text report
 | 
| 46 |   # $CLANG_DIR/bin/llvm-cov show --instr-profile $dir/ALL.profdata "${args[@]}"
 | 
| 47 | 
 | 
| 48 |   local html_dir=$out_dir/html
 | 
| 49 |   mkdir -p $html_dir
 | 
| 50 | 
 | 
| 51 |   local -a filter_flags=(
 | 
| 52 |     --ignore-filename-regex '_test.cc$' \
 | 
| 53 |     --ignore-filename-regex 'greatest.h$' \
 | 
| 54 |     --ignore-filename-regex '_gen/' \
 | 
| 55 |     --ignore-filename-regex 'mycpp/demo' \
 | 
| 56 |     --ignore-filename-regex 'mycpp/examples' \
 | 
| 57 |     --ignore-filename-regex 'prebuilt/' \
 | 
| 58 |   )
 | 
| 59 | 
 | 
| 60 |   local title=$(basename $subdir)
 | 
| 61 | 
 | 
| 62 |   $CLANG_DIR/bin/llvm-cov show \
 | 
| 63 |     --instr-profile $merged \
 | 
| 64 |     --format html --output-dir $html_dir \
 | 
| 65 |     --project-title "$title" \
 | 
| 66 |     --show-instantiation-summary \
 | 
| 67 |     "${filter_flags[@]}" \
 | 
| 68 |     "${args[@]}"
 | 
| 69 | 
 | 
| 70 |   #echo "Wrote $html"
 | 
| 71 |   #ls -l --si -h $html  # 2.2 MB of HTML
 | 
| 72 | 
 | 
| 73 |   # Clang quirk: permissions of this tree aren't right.  Without this, the Soil
 | 
| 74 |   # host won't be able to zip and publish them.
 | 
| 75 | 
 | 
| 76 |   # make sure dirs can be listed
 | 
| 77 |   echo 'fix DIRS'
 | 
| 78 |   find $html_dir -type d | xargs -- chmod --changes o+rx
 | 
| 79 |   echo
 | 
| 80 | 
 | 
| 81 |   # make sure files are readable
 | 
| 82 |   echo 'fix FILES'
 | 
| 83 |   chmod --changes -R o+r $html_dir
 | 
| 84 |   echo
 | 
| 85 | 
 | 
| 86 |   $CLANG_DIR/bin/llvm-cov report \
 | 
| 87 |     --instr-profile $merged \
 | 
| 88 |     "${filter_flags[@]}" \
 | 
| 89 |     "${args[@]}"
 | 
| 90 | 
 | 
| 91 |   # --format text is JSON.  Need --skip-expansions to avoid running out of memory
 | 
| 92 |   # Doesn't seem to work?
 | 
| 93 |   # --Xdemangler=$CLANG_DIR/bin/llvm-cxxfilt \
 | 
| 94 |   # --Xdemangler=-n \
 | 
| 95 | 
 | 
| 96 |   local json=$out_dir/coverage.json
 | 
| 97 | 
 | 
| 98 |   $CLANG_DIR/bin/llvm-cov export \
 | 
| 99 |     --instr-profile $merged \
 | 
| 100 |     --format text --skip-expansions \
 | 
| 101 |     "${filter_flags[@]}" \
 | 
| 102 |     "${args[@]}" > $json
 | 
| 103 | 
 | 
| 104 |   ls -l --si $json
 | 
| 105 |   echo
 | 
| 106 | 
 | 
| 107 |   wc -l $json
 | 
| 108 |   echo
 | 
| 109 | 
 | 
| 110 |   # 2.4 MB of HTML
 | 
| 111 |   du --si -s $html_dir
 | 
| 112 |   echo
 | 
| 113 | }
 | 
| 114 | 
 | 
| 115 | extract-coverage() {
 | 
| 116 |   local json=${1:-'_test/clang-coverage/cpp/coverage.json'}
 | 
| 117 | 
 | 
| 118 |   # Shows the same totals
 | 
| 119 |   cat $json | jq -r '.data[0] | .totals'
 | 
| 120 | 
 | 
| 121 |   # 1291 functions.
 | 
| 122 |   # - Includes greatest.h stuff, which you can filter away
 | 
| 123 |   # - Hm this doesn't seem to respect the --ignore-filename-regex?
 | 
| 124 |   # - It has many template expansions.
 | 
| 125 |   # - Some of these have filename prefixes, and some don't.
 | 
| 126 | 
 | 
| 127 |   cat $json | jq -r '.data[0] | .functions[] | .name' | $CLANG_DIR/bin/llvm-cxxfilt #| wc -l
 | 
| 128 | 
 | 
| 129 |   # Each of this has a "regions" key, which is a list of list of integers.
 | 
| 130 |   # It's not clear how to tell if there was coverage or not!
 | 
| 131 |   # cat $json | jq -r '.data[0] | .functions'
 | 
| 132 | }
 | 
| 133 | 
 | 
| 134 | llvm-cov-help() {
 | 
| 135 |   # many options for filtering
 | 
| 136 |   # --name-allowlist
 | 
| 137 | 
 | 
| 138 |   $CLANG_DIR/bin/llvm-cov show --help
 | 
| 139 |   echo
 | 
| 140 | 
 | 
| 141 |   $CLANG_DIR/bin/llvm-cov export --help
 | 
| 142 | }
 | 
| 143 | 
 | 
| 144 | unified-report() {
 | 
| 145 |   # Merge 3 suites
 | 
| 146 | 
 | 
| 147 |   local out_dir=_test/clang-coverage/unified
 | 
| 148 |   mkdir -p $out_dir
 | 
| 149 | 
 | 
| 150 |   html-report $out_dir \
 | 
| 151 |     clang-coverage/mycpp/examples \
 | 
| 152 |     clang-coverage/mycpp \
 | 
| 153 |     clang-coverage/mycpp clang-coverage+bumpleak/mycpp \
 | 
| 154 |     clang-coverage/cpp
 | 
| 155 | }
 | 
| 156 | 
 | 
| 157 | log-files-index() {
 | 
| 158 |   local dir=${1:-_test/clang-coverage}
 | 
| 159 |   pushd $dir
 | 
| 160 |   # Unit tests logs
 | 
| 161 |   find . -name '*.log' \
 | 
| 162 |     | gawk '{ printf("<a href=\"%s\">%s</a> <br/>\n", $0, $0); }' \
 | 
| 163 |     > log-files.html
 | 
| 164 |   popd
 | 
| 165 | }
 | 
| 166 | 
 | 
| 167 | run-for-release() {
 | 
| 168 |   ### Similar to cpp-coverage in soil/worker.sh
 | 
| 169 | 
 | 
| 170 |   mycpp/TEST.sh unit-test-coverage
 | 
| 171 |   mycpp/TEST.sh examples-coverage
 | 
| 172 |   cpp/TEST.sh coverage
 | 
| 173 | 
 | 
| 174 |   log-files-index _test/clang-coverage
 | 
| 175 | 
 | 
| 176 |   unified-report
 | 
| 177 | }
 | 
| 178 | 
 | 
| 179 | "$@"
 | 
| 180 | 
 |