Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf annotate-data: Do not delete non-asm lines

For data type profiling, it removed non-instruction lines from the list
of annotation lines. It was to simplify the implementation dealing with
instructions like to calculate the PC-relative address and to search the
shortest path to the target instruction or basic block.

But it means that it removes all the comments and debug information in
the annotate output like source file name and line numbers. To support
both code annotation and data type annotation, it'd be better to keep
the non-instruction lines as well.

So this change is to skip those lines during the data type profiling
and to display them in the normal perf annotate output.

No function changes intended (other than having more lines).

Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20240405211800.1412920-4-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
879ebf3c 65785213

+74 -25
+6
tools/perf/util/annotate-data.c
··· 1314 1314 list_for_each_entry(bb, basic_blocks, list) { 1315 1315 struct disasm_line *dl = bb->begin; 1316 1316 1317 + BUG_ON(bb->begin->al.offset == -1 || bb->end->al.offset == -1); 1318 + 1317 1319 pr_debug_dtp("bb: [%"PRIx64" - %"PRIx64"]\n", 1318 1320 bb->begin->al.offset, bb->end->al.offset); 1319 1321 1320 1322 list_for_each_entry_from(dl, &notes->src->source, al.node) { 1321 1323 u64 this_ip = sym->start + dl->al.offset; 1322 1324 u64 addr = map__rip_2objdump(dloc->ms->map, this_ip); 1325 + 1326 + /* Skip comment or debug info lines */ 1327 + if (dl->al.offset == -1) 1328 + continue; 1323 1329 1324 1330 /* Update variable type at this address */ 1325 1331 update_var_state(&state, dloc, addr, dl->al.offset, var_types);
+68 -25
tools/perf/util/annotate.c
··· 2159 2159 2160 2160 static void symbol__ensure_annotate(struct map_symbol *ms, struct evsel *evsel) 2161 2161 { 2162 - struct disasm_line *dl, *tmp_dl; 2163 - struct annotation *notes; 2162 + struct annotation *notes = symbol__annotation(ms->sym); 2164 2163 2165 - notes = symbol__annotation(ms->sym); 2166 - if (!list_empty(&notes->src->source)) 2167 - return; 2168 - 2169 - if (symbol__annotate(ms, evsel, NULL) < 0) 2170 - return; 2171 - 2172 - /* remove non-insn disasm lines for simplicity */ 2173 - list_for_each_entry_safe(dl, tmp_dl, &notes->src->source, al.node) { 2174 - if (dl->al.offset == -1) { 2175 - list_del(&dl->al.node); 2176 - free(dl); 2177 - } 2178 - } 2164 + if (list_empty(&notes->src->source)) 2165 + symbol__annotate(ms, evsel, NULL); 2179 2166 } 2180 2167 2181 2168 static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, ··· 2174 2187 notes = symbol__annotation(sym); 2175 2188 2176 2189 list_for_each_entry(dl, &notes->src->source, al.node) { 2190 + if (dl->al.offset == -1) 2191 + continue; 2192 + 2177 2193 if (sym->start + dl->al.offset == ip) { 2178 2194 /* 2179 2195 * llvm-objdump places "lock" in a separate line and ··· 2241 2251 return false; 2242 2252 } 2243 2253 2254 + static struct disasm_line * 2255 + annotation__prev_asm_line(struct annotation *notes, struct disasm_line *curr) 2256 + { 2257 + struct list_head *sources = &notes->src->source; 2258 + struct disasm_line *prev; 2259 + 2260 + if (curr == list_first_entry(sources, struct disasm_line, al.node)) 2261 + return NULL; 2262 + 2263 + prev = list_prev_entry(curr, al.node); 2264 + while (prev->al.offset == -1 && 2265 + prev != list_first_entry(sources, struct disasm_line, al.node)) 2266 + prev = list_prev_entry(prev, al.node); 2267 + 2268 + if (prev->al.offset == -1) 2269 + return NULL; 2270 + 2271 + return prev; 2272 + } 2273 + 2274 + static struct disasm_line * 2275 + annotation__next_asm_line(struct annotation *notes, struct disasm_line *curr) 2276 + { 2277 + struct list_head *sources = &notes->src->source; 2278 + struct disasm_line *next; 2279 + 2280 + if (curr == list_last_entry(sources, struct disasm_line, al.node)) 2281 + return NULL; 2282 + 2283 + next = list_next_entry(curr, al.node); 2284 + while (next->al.offset == -1 && 2285 + next != list_last_entry(sources, struct disasm_line, al.node)) 2286 + next = list_next_entry(next, al.node); 2287 + 2288 + if (next->al.offset == -1) 2289 + return NULL; 2290 + 2291 + return next; 2292 + } 2293 + 2244 2294 u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, 2245 2295 struct disasm_line *dl) 2246 2296 { ··· 2296 2266 * disasm_line. If it's the last one, we can use symbol's end 2297 2267 * address directly. 2298 2268 */ 2299 - if (&dl->al.node == notes->src->source.prev) 2269 + next = annotation__next_asm_line(notes, dl); 2270 + if (next == NULL) 2300 2271 addr = ms->sym->end + offset; 2301 - else { 2302 - next = list_next_entry(dl, al.node); 2272 + else 2303 2273 addr = ip + (next->al.offset - dl->al.offset) + offset; 2304 - } 2274 + 2305 2275 return map__rip_2objdump(ms->map, addr); 2306 2276 } 2307 2277 ··· 2433 2403 * from the previous instruction. 2434 2404 */ 2435 2405 if (dl->al.offset > 0) { 2406 + struct annotation *notes; 2436 2407 struct disasm_line *prev_dl; 2437 2408 2438 - prev_dl = list_prev_entry(dl, al.node); 2439 - if (ins__is_fused(arch, prev_dl->ins.name, dl->ins.name)) { 2409 + notes = symbol__annotation(ms->sym); 2410 + prev_dl = annotation__prev_asm_line(notes, dl); 2411 + 2412 + if (prev_dl && ins__is_fused(arch, prev_dl->ins.name, dl->ins.name)) { 2440 2413 dl = prev_dl; 2441 2414 goto retry; 2442 2415 } ··· 2544 2511 2545 2512 last_dl = list_last_entry(&notes->src->source, 2546 2513 struct disasm_line, al.node); 2514 + if (last_dl->al.offset == -1) 2515 + last_dl = annotation__prev_asm_line(notes, last_dl); 2516 + 2517 + if (last_dl == NULL) 2518 + return false; 2547 2519 2548 2520 list_for_each_entry_from(dl, &notes->src->source, al.node) { 2521 + /* Skip comment or debug info line */ 2522 + if (dl->al.offset == -1) 2523 + continue; 2549 2524 /* Found the target instruction */ 2550 2525 if (sym->start + dl->al.offset == target) { 2551 2526 found = true; ··· 2574 2533 /* jump instruction creates new basic block(s) */ 2575 2534 next_dl = find_disasm_line(sym, sym->start + dl->ops.target.offset, 2576 2535 /*allow_update=*/false); 2577 - add_basic_block(bb_data, link, next_dl); 2536 + if (next_dl) 2537 + add_basic_block(bb_data, link, next_dl); 2578 2538 2579 2539 /* 2580 2540 * FIXME: determine conditional jumps properly. ··· 2583 2541 * next disasm line. 2584 2542 */ 2585 2543 if (!strstr(dl->ins.name, "jmp")) { 2586 - next_dl = list_next_entry(dl, al.node); 2587 - add_basic_block(bb_data, link, next_dl); 2544 + next_dl = annotation__next_asm_line(notes, dl); 2545 + if (next_dl) 2546 + add_basic_block(bb_data, link, next_dl); 2588 2547 } 2589 2548 break; 2590 2549