| 1 | #!/usr/bin/env bash
|
| 2 | #
|
| 3 | # Usage:
|
| 4 | # metrics/native-code.sh <function name>
|
| 5 |
|
| 6 | set -o nounset
|
| 7 | set -o pipefail
|
| 8 | set -o errexit
|
| 9 |
|
| 10 | source build/dev-shell.sh # put bloaty in $PATH, R_LIBS_USER
|
| 11 |
|
| 12 | readonly OVM_BASE_DIR=_tmp/metrics/ovm
|
| 13 | readonly OIL_BASE_DIR=_tmp/metrics/oils-for-unix
|
| 14 |
|
| 15 | pylibc-symbols() {
|
| 16 | symbols _devbuild/py-ext/x86_64/libc.so
|
| 17 | }
|
| 18 |
|
| 19 | fastlex-symbols() {
|
| 20 | symbols _devbuild/py-ext/x86_64/fastlex.so
|
| 21 | }
|
| 22 |
|
| 23 | print-symbols() {
|
| 24 | local obj=$1
|
| 25 | ls -l $obj
|
| 26 | echo
|
| 27 |
|
| 28 | # Summary
|
| 29 | bloaty $obj
|
| 30 | echo
|
| 31 |
|
| 32 | # Top symbols
|
| 33 | # fastlex_MatchToken is 21.2 KiB. That doesn't seem to large compared to
|
| 34 | # the 14K line output?
|
| 35 | bloaty -d symbols $obj
|
| 36 | echo
|
| 37 |
|
| 38 | nm $obj
|
| 39 | echo
|
| 40 | }
|
| 41 |
|
| 42 | # Big functions:
|
| 43 | # - PyEval_EvalFrameEx (38 KiB)
|
| 44 | # - fastlex_MatchOSHToken (22.5 KiB)
|
| 45 | # - convertitem() in args.py (9.04 KiB)
|
| 46 | # - PyString_Format() in args.py (6.84 KiB)
|
| 47 | #
|
| 48 | # Easy removals:
|
| 49 | # - marshal_dumps and marshal_dump! We never use those.
|
| 50 | # - Remove all docstrings!!! Like sys_doc.
|
| 51 |
|
| 52 | compileunits() {
|
| 53 | # Hm there doesn't seem to be a way to do this without
|
| 54 | local file=${1:-_build/oil/ovm-dbg}
|
| 55 |
|
| 56 | #local file=_build/oil/ovm-opt
|
| 57 | #local sym=_build/oil/ovm-opt.symbols
|
| 58 |
|
| 59 | bloaty --tsv -n 0 -d compileunits $file
|
| 60 | }
|
| 61 |
|
| 62 | symbols() {
|
| 63 | # NOTE: This is different than the release binary!
|
| 64 | # ovm-opt.stripped doesn't show a report.
|
| 65 | local file=${1:-_build/oil/ovm-opt}
|
| 66 |
|
| 67 | # Full output
|
| 68 | # 3,588 lines!
|
| 69 | bloaty --tsv -n 0 -d symbols $file
|
| 70 | }
|
| 71 |
|
| 72 | R-report() {
|
| 73 | metrics/native-code.R "$@"
|
| 74 | }
|
| 75 |
|
| 76 | build-ovm() {
|
| 77 | # 2022-12: hack for ./configure, because line_input failed to compile without
|
| 78 | # HAVE_READLINE See _build/oil/module_init.c
|
| 79 | # TODO: This metric should either be DELETED, or automated in the CI, so it
|
| 80 | # doesn't break
|
| 81 |
|
| 82 | ./configure
|
| 83 |
|
| 84 | make _build/oil/ovm-{dbg,opt}
|
| 85 | }
|
| 86 |
|
| 87 | collect-and-report() {
|
| 88 | local base_dir=$1
|
| 89 | local dbg=$2
|
| 90 | local opt=$3
|
| 91 |
|
| 92 | mkdir -p $base_dir
|
| 93 |
|
| 94 | print-symbols $opt > $base_dir/symbols.txt
|
| 95 |
|
| 96 | symbols $opt > $base_dir/symbols.tsv
|
| 97 |
|
| 98 | # Really 'translation units', but bloaty gives it that name.
|
| 99 | compileunits $dbg > $base_dir/compileunits.tsv
|
| 100 |
|
| 101 | head $base_dir/symbols.tsv $base_dir/compileunits.tsv
|
| 102 |
|
| 103 | # Hack for now
|
| 104 | if Rscript -e 'print("hi from R")'; then
|
| 105 | R-report metrics $base_dir $dbg $opt | tee $base_dir/overview.txt
|
| 106 | else
|
| 107 | echo 'R not detected' | tee $base_dir/overview.txt
|
| 108 | fi
|
| 109 | }
|
| 110 |
|
| 111 | oils-for-unix() {
|
| 112 | ### Report on the ones we just built
|
| 113 |
|
| 114 | soil/cpp-tarball.sh build-like-ninja dbg opt
|
| 115 |
|
| 116 | collect-and-report $OIL_BASE_DIR _bin/cxx-{dbg,opt}/oils-for-unix
|
| 117 |
|
| 118 | ls -l $OIL_BASE_DIR
|
| 119 | }
|
| 120 |
|
| 121 | compare-gcc-clang() {
|
| 122 | ### Run by Soil 'cpp-coverage' task, because it has clang
|
| 123 |
|
| 124 | local -a targets=(
|
| 125 | _bin/{clang,cxx}-dbg/oils-for-unix
|
| 126 | _bin/{clang,cxx}-opt/oils-for-unix.stripped
|
| 127 | _bin/cxx-{opt+bumpleak,opt+bumproot,opt+bigint}/oils-for-unix.stripped
|
| 128 | _bin/{clang,cxx}-opt/yaks/yaks_main.mycpp.stripped
|
| 129 | _bin/cxx-{opt+bumpleak,opt+bumproot}/yaks/yaks_main.mycpp.stripped
|
| 130 | )
|
| 131 | ninja "${targets[@]}"
|
| 132 |
|
| 133 | mkdir -p _tmp/metrics
|
| 134 | ls -l --sort=none "${targets[@]}" | tee _tmp/metrics/compare-gcc-clang.txt
|
| 135 | }
|
| 136 |
|
| 137 | readonly OIL_VERSION=$(head -n 1 oil-version.txt)
|
| 138 |
|
| 139 | run-for-release() {
|
| 140 | # 2024-08: Not building with DWARF 4
|
| 141 | if false; then
|
| 142 | build-ovm
|
| 143 |
|
| 144 | local dbg=_build/oil/ovm-dbg
|
| 145 | local opt=_build/oil/ovm-opt
|
| 146 |
|
| 147 | collect-and-report $OVM_BASE_DIR $dbg $opt
|
| 148 | fi
|
| 149 |
|
| 150 | # TODO: consolidate with benchmarks/common.sh, OSH_CPP_BENCHMARK_DATA
|
| 151 | # For some reason _bin/cxx-opt/ and _bin/cxx-opt-sh can differ by a few bytes
|
| 152 | local bin_dir="../benchmark-data/src/oils-for-unix-$OIL_VERSION"
|
| 153 | collect-and-report $OIL_BASE_DIR $bin_dir/_bin/cxx-{dbg,opt}-sh/oils-for-unix
|
| 154 | }
|
| 155 |
|
| 156 | dupe-strings() {
|
| 157 | ### Check for NUL-terminated strings
|
| 158 |
|
| 159 | python2 -c '
|
| 160 | import collections
|
| 161 | import re
|
| 162 | import sys
|
| 163 |
|
| 164 | with open(sys.argv[1]) as f:
|
| 165 | contents = f.read()
|
| 166 | strs = re.split("\\0", contents)
|
| 167 |
|
| 168 | printable = re.compile("[ -~]+$")
|
| 169 |
|
| 170 | d = collections.Counter()
|
| 171 | for s in strs:
|
| 172 | if len(s) > 1 and printable.match(s):
|
| 173 | d[s] += 1
|
| 174 |
|
| 175 | for s, count in d.most_common()[:50]:
|
| 176 | if count == 1:
|
| 177 | break
|
| 178 | print("%5d %r" % (count, s))
|
| 179 |
|
| 180 | ' "$@"
|
| 181 | }
|
| 182 |
|
| 183 | # Results:
|
| 184 | # Found StrFromC() and len() duplication
|
| 185 |
|
| 186 | oil-dupe-strings() {
|
| 187 | local bin=_bin/cxx-opt/oils-for-unix.stripped
|
| 188 | #local bin=_bin/clang-opt/oils-for-unix.stripped
|
| 189 | ninja $bin
|
| 190 |
|
| 191 | dupe-strings $bin
|
| 192 | }
|
| 193 |
|
| 194 | "$@"
|