On Tue, Apr 19, 2022 at 04:39:13PM +0200, Paolo Bonzini wrote: > Hi all, > > a while ago I looked at tools that could be used too build a call graph. > The simplest but most effective that I found was a small Perl program > (called "egypt", which is rot13 for "rtlcg" aka RTL call graph) that used > the GCC dumps to build the graph. > > I have now rewritten it in Python and extended it with a lot of new > functionality: > > - consult compile_commands.json to find/build dumps automatically > > - virtual (manually created) nodes and edges > > - query call graph in addition to generating DOT file > > - interactive mode with readline + completion > > The name is unfortunately not rot13 anymore, it stands for visit RTL > callgraph. > > Here is an example (run vrc from the root build directory of QEMU): > > # load files > load libblock.fa.p/*.c.o > > # introduce virtual edges corresponding to function pointers > node BlockDriverState.bdrv_co_flush > edge bdrv_co_flush BlockDriverState.bdrv_co_flush > edge BlockDriverState.bdrv_co_flush blk_log_writes_co_do_file_flush > edge BlockDriverState.bdrv_co_flush preallocate_co_flush > edge BlockDriverState.bdrv_co_flush raw_co_invalidate_cache > edge BlockDriverState.bdrv_co_flush cbw_co_flush > edge BlockDriverState.bdrv_co_flush quorum_co_flush > edge BlockDriverState.bdrv_co_flush throttle_co_flush > edge BlockDriverState.bdrv_co_flush blkdebug_co_flush > edge BlockDriverState.bdrv_co_flush blkverify_co_flush > edge BlockDriverState.bdrv_co_flush bdrv_mirror_top_flush > # apply filter > only --callees bdrv_co_flush > # draw graph > dotty --files > > The filtering functionality is a bit rough in the presence of mutual > recursion, but hopefully this can be already useful to find the root calls > of bdrv_*, which are the places where the graph lock has to be taken for > read. Continuing the previous example: > > # apply another filter > reset > omit --callees bdrv_co_flush > keep bdrv_co_flush > # example of query > callers bdrv_co_flush > > already gives a reasonable answer (not entirely correct, but the actual > analysis must be done on all callbacks at once): > > qed_co_request -> bdrv_co_flush > qed_need_check_timer_entry -> bdrv_co_flush > blk_log_writes_co_log -> bdrv_co_flush > bdrv_co_flush_entry -> bdrv_co_flush > bdrv_co_flush -> bdrv_co_flush > blk_co_do_flush -> bdrv_co_flush > bdrv_driver_pwritev -> bdrv_co_flush > blk_co_flush -> bdrv_co_flush > bdrv_flush -> bdrv_co_flush > bdrv_co_do_pwrite_zeroes -> bdrv_co_flush > blk_aio_flush_entry -> bdrv_co_flush
Cool, thanks for sharing. I will keep this in mind when I need to analyze call graphs. Stefan
signature.asc
Description: PGP signature