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 | fi | 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 | __faddr2line() { | 171 | __faddr2line() { |
| 130 | local objfile=$1 | 172 | local objfile=$1 |
| 131 | local func_addr=$2 | 173 | local func_addr=$2 |
| @@ -260,12 +302,8 @@ __faddr2line() { · 128 unmodified lines | |||
| 260 | 302 | ||
| 261 | # Pass section address to addr2line and strip absolute paths | 303 | # Pass section address to addr2line and strip absolute paths |
| 262 | # from the output: | 304 | # from the output: |
| 263 | local args="--functions --pretty-print --inlines --addresses --exe=$objfile" | 305 | run_addr2line $addr $sec_name |
| 264 | [[ $IS_VMLINUX = 0 ]] && args="$args --section=$sec_name" | 306 | local output=$(echo "${ADDR2LINE_OUT}" | sed "s; $dir_prefix\(\./\)*; ;") |
| 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]*: //') | ||
| 269 | [[ -z $output ]] && continue | 307 | [[ -z $output ]] && continue |
| 270 | 308 | ||
| 271 | # Default output (non --list): | 309 | # Default output (non --list): |
| @@ -309,7 +347,7 @@ run_readelf $objfile · 37 unmodified lines | |||
| 309 | 347 | ||
| 310 | echo "${ELF_SECHEADERS}" | ${GREP} -q '\.debug_info' || die "CONFIG_DEBUG_INFO not enabled" | 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 | DIR_PREFIX=supercalifragilisticexpialidocious | 352 | DIR_PREFIX=supercalifragilisticexpialidocious |
| 315 | find_dir_prefix $objfile | 353 | find_dir_prefix $objfile |