Rather than invoking a separate addr2line process for each address, invoke a single addr2line coprocess, and pass each address to its stdin. Previous work [0] applied a similar change to perf, leading to a ~60x speed-up [1]. If using an object file that is _not_ vmlinux, faddr2line passes a section name argument to addr2line. Because we do not know until runtime which section names will be passed to addr2line, we cannot apply this change to non-vmlinux object files. Hence, it only applies to vmlinux. [0] commit be8ecc57f180 ("perf srcline: Use long-running addr2line per DSO") [1] Link: https://eighty-twenty.org/2021/09/09/perf-addr2line-speed-improvement
Showing the changes to scripts (1 of 1 file). Show all
Unified · Split
| @@ -126,6 +126,48 @@ check_vmlinux() { · 125 unmodified lines | ||
| 126 | 126 | fi |
| 127 | 127 | } |
| 128 | 128 | |
| 129 | +init_addr2line() { | |
| 130 | + local objfile=$1 | |
| 131 | + | |
| 132 | + check_vmlinux | |
| 133 | + | |
| 134 | + ADDR2LINE_ARGS="--functions --pretty-print --inlines --addresses --exe=$objfile" | |
| 135 | + if [[ $IS_VMLINUX = 1 ]]; then | |
| 136 | + # If the executable file is vmlinux, we don't pass section names to | |
| 137 | + # addr2line, so we can launch it now as a single long-running process. | |
| 138 | + coproc ADDR2LINE_PROC (${ADDR2LINE} ${ADDR2LINE_ARGS}) | |
| 139 | + fi | |
| 140 | +} | |
| 141 | + | |
| 142 | +run_addr2line() { | |
| 143 | + local addr=$1 | |
| 144 | + local sec_name=$2 | |
| 145 | + | |
| 146 | + if [[ $IS_VMLINUX = 1 ]]; then | |
| 147 | + # We send to the addr2line process: (1) the address, then (2) a sentinel | |
| 148 | + # value, i.e., something that can't be interpreted as a valid address | |
| 149 | + # (i.e., ","). This causes addr2line to write out: (1) the answer for | |
| 150 | + # our address, then (2) either "?? ??:0" or "0x0...0: ..." (if | |
| 151 | + # using binutils' addr2line), or "," (if using LLVM's addr2line). | |
| 152 | + echo ${addr} >& "${ADDR2LINE_PROC[1]}" | |
| 153 | + echo "," >& "${ADDR2LINE_PROC[1]}" | |
| 154 | + local first_line | |
| 155 | + read -r first_line <& "${ADDR2LINE_PROC[0]}" | |
| 156 | + ADDR2LINE_OUT=$(echo "${first_line}" | sed 's/^0x[0-9a-fA-F]*: //') | |
| 157 | + while read -r line <& "${ADDR2LINE_PROC[0]}"; do | |
| 158 | + if [[ "$line" == "?? ??:0" ]] || [[ "$line" == "," ]] || [[ $(echo "$line" | ${GREP} "^0x00*: ") ]]; then | |
| 159 | + break | |
| 160 | + fi | |
| 161 | + ADDR2LINE_OUT+=$'\n'$(echo "$line" | sed 's/^0x[0-9a-fA-F]*: //') | |
| 162 | + done | |
| 163 | + else | |
| 164 | + # Run addr2line as a single invocation. | |
| 165 | + local sec_arg | |
| 166 | + [[ -z $sec_name ]] && sec_arg="" || sec_arg="--section=${sec_name}" | |
| 167 | + ADDR2LINE_OUT=$(${ADDR2LINE} ${ADDR2LINE_ARGS} ${sec_arg} ${addr} | sed 's/^0x[0-9a-fA-F]*: //') | |
| 168 | + fi | |
| 169 | +} | |
| 170 | + | |
| 129 | 171 | __faddr2line() { |
| 130 | 172 | local objfile=$1 |
| 131 | 173 | local func_addr=$2 |
| @@ -260,12 +302,8 @@ __faddr2line() { · 128 unmodified lines | ||
| 260 | 302 | |
| 261 | 303 | # Pass section address to addr2line and strip absolute paths |
| 262 | 304 | # from the output: |
| 263 | − local args="--functions --pretty-print --inlines --addresses --exe=$objfile" | |
| 264 | − [[ $IS_VMLINUX = 0 ]] && args="$args --section=$sec_name" | |
| 265 | − local output_with_addr=$(${ADDR2LINE} $args $addr | sed "s; $dir_prefix\(\./\)*; ;") | |
| 266 | − [[ -z $output_with_addr ]] && continue | |
| 267 | − | |
| 268 | − local output=$(echo "${output_with_addr}" | sed 's/^0x[0-9a-fA-F]*: //') | |
| 305 | + run_addr2line $addr $sec_name | |
| 306 | + local output=$(echo "${ADDR2LINE_OUT}" | sed "s; $dir_prefix\(\./\)*; ;") | |
| 269 | 307 | [[ -z $output ]] && continue |
| 270 | 308 | |
| 271 | 309 | # Default output (non --list): |
| @@ -309,7 +347,7 @@ run_readelf $objfile · 37 unmodified lines | ||
| 309 | 347 | |
| 310 | 348 | echo "${ELF_SECHEADERS}" | ${GREP} -q '\.debug_info' || die "CONFIG_DEBUG_INFO not enabled" |
| 311 | 349 | |
| 312 | −check_vmlinux | |
| 350 | +init_addr2line $objfile | |
| 313 | 351 | |
| 314 | 352 | DIR_PREFIX=supercalifragilisticexpialidocious |
| 315 | 353 | find_dir_prefix $objfile |