qemu-block
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

introducing vrc :)


From: Paolo Bonzini
Subject: introducing vrc :)
Date: Tue, 19 Apr 2022 16:39:13 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.8.0

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

Paolo

Attachment: vrc
Description: Text document


reply via email to

[Prev in Thread] Current Thread [Next in Thread]