qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Pierrick Bouvier <pierrick.bouvier@linaro.org>
To: "Alex Bennée" <alex.bennee@linaro.org>, qemu-devel@nongnu.org
Cc: Gustavo Romero <gustavo.romero@linaro.org>,
	Alexandre Iooss <erdnaxe@crans.org>,
	Mahmoud Mandour <ma.mandourr@gmail.com>,
	Richard Henderson <richard.henderson@linaro.org>
Subject: Re: [RFC PATCH v2] contrib/plugins: control flow plugin (WIP!)
Date: Thu, 14 Mar 2024 16:15:53 +0400	[thread overview]
Message-ID: <c5fae40d-8828-4ecb-b9b1-4d179cca2e74@linaro.org> (raw)
In-Reply-To: <87msr1ggxz.fsf@draig.linaro.org>

On 3/14/24 16:02, Alex Bennée wrote:
> Alex Bennée <alex.bennee@linaro.org> writes:
> 
>> This is a simple control flow tracking plugin that uses the latest
>> inline and conditional operations to detect and track control flow
>> changes. It is currently an exercise at seeing how useful the changes
>> are.
>>
>> Based-on: <20240312075428.244210-1-pierrick.bouvier@linaro.org>
>> Cc: Gustavo Romero <gustavo.romero@linaro.org>
>> Cc: Pierrick Bouvier <pierrick.bouvier@linaro.org>
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>> Message-Id: <20240311153432.1395190-1-alex.bennee@linaro.org>
>>
>> ---
>> v2
>>    - only need a single call back
>>    - drop need for INSN_WIDTH
>>    - still don't understand the early exits
>>
>> I'm still seeing weirdness in the generated code, for example the
>> plugin reports "early exits" which doesn't make sense for a ret which
>> terminates a block:
>>
>>    addr: 0x403c88 hexchar: ret  (1/1)
>>      early exits 1280
>>      branches 1280
>>        to 0x403d00 (639)
>>        to 0x403d24 (639)
>>
> <snip>
>> +
>> +/*
>> + * At the start of each block we need to resolve two things:
>> + *
>> + *  - is last_pc == block_end, if not we had an early exit
>> + *  - is start of block last_pc + insn width, if not we jumped
>> + *
>> + * Once those are dealt with we can instrument the rest of the
>> + * instructions for their execution.
>> + *
>> + */
>> +static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
>> +{
>> +    uint64_t pc = qemu_plugin_tb_vaddr(tb);
>> +    size_t insns = qemu_plugin_tb_n_insns(tb);
>> +    struct qemu_plugin_insn *last_insn = qemu_plugin_tb_get_insn(tb, insns - 1);
>> +
>> +    /*
>> +     * check if we are executing linearly after the last block. We can
>> +     * handle both early block exits and normal branches in the
>> +     * callback if we hit it.
>> +     */
>> +    gpointer udata = GUINT_TO_POINTER(pc);
>> +    qemu_plugin_register_vcpu_tb_exec_cond_cb(
>> +        tb, vcpu_tb_branched_exec, QEMU_PLUGIN_CB_NO_REGS,
>> +        QEMU_PLUGIN_COND_NE, pc_after_block, pc, udata);
>> +
>> +    /*
>> +     * Now we can set start/end for this block so the next block can
>> +     * check where we are at.
>> +     */
>> +    qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(tb,
>> +                                                      QEMU_PLUGIN_INLINE_STORE_U64,
>> +                                                      end_block, qemu_plugin_insn_vaddr(last_insn));
>> +    qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(tb,
>> +                                                      QEMU_PLUGIN_INLINE_STORE_U64,
>> +                                                      pc_after_block,
>> +                                                      qemu_plugin_insn_vaddr(last_insn) +
>> +
>> qemu_plugin_insn_size(last_insn));
> 
> With the following:
> 
> modified   contrib/plugins/cflow.c
> @@ -220,7 +220,7 @@ static void vcpu_tb_branched_exec(unsigned int cpu_index, void *udata)
>       g_mutex_lock(&node->lock);
>   
>       if (early_exit) {
> -        fprintf(stderr, "%s: pc=%"PRIx64", epbc=%"PRIx64"
> +        fprintf(stderr, "%s: pc=%"PRIx64", epbc=%"PRIx64
>                   " npc=%"PRIx64", lpc=%"PRIx64", \n",
>                   __func__, pc, ebpc, npc, lpc);
>           node->early_exit++;
> @@ -264,6 +264,7 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
>   {
>       uint64_t pc = qemu_plugin_tb_vaddr(tb);
>       size_t insns = qemu_plugin_tb_n_insns(tb);
> +    struct qemu_plugin_insn *first_insn = qemu_plugin_tb_get_insn(tb, 0);
>       struct qemu_plugin_insn *last_insn = qemu_plugin_tb_get_insn(tb, insns - 1);
>   
>       /*
> @@ -278,12 +279,13 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
>   
>       /*
>        * Now we can set start/end for this block so the next block can
> -     * check where we are at.
> +     * check where we are at. Do this on the first instruction and not
> +     * the TB so we don't get mixed up with above.
>        */
> -    qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(tb,
> +    qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(first_insn,
>                                                         QEMU_PLUGIN_INLINE_STORE_U64,
>                                                         end_block, qemu_plugin_insn_vaddr(last_insn));
> -    qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(tb,
> +    qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(first_insn,
>                                                         QEMU_PLUGIN_INLINE_STORE_U64,
>                                                         pc_after_block,
>                                                         qemu_plugin_insn_vaddr(last_insn) +
> 
> The report looks more sane:
> 
>    collected 9013 control flow nodes in the hash table
>      addr: 0x403c88 hexchar: ret  (0/1)
>        branches 1280
>          to 0x403d00 (639)
>          to 0x403d24 (639)
> 
> So I think we need to think about preserving the ordering of
> instrumentation (at least from the same plugin) so we are not laying any
> API bear traps for users.
> 
> I assume because loads and stores are involved we won't see the
> optimiser trying to swap stuff around.
> 

Currently, order is fixed.

Series introducing more inline ops changed order to be:
- inline ops:
   - PLUGIN_GEN_CB_INLINE_ADD_U64
   - PLUGIN_GEN_CB_INLINE_STORE_U64
- callbacks:
   - PLUGIN_GEN_CB_UDATA
   - PLUGIN_GEN_CB_UDATA_R
   - PLUGIN_GEN_CB_COND_UDATA
   - PLUGIN_GEN_CB_COND_UDATA_R,

It made much more sense than having callbacks first (especially 
regarding new condition callback).

In general, I agree that user should be able to introduce op in any 
order he wants, and compose them like they want.
We could imagine keeping a simple array/list for block/insn with any 
type of instrumentation possible, with a simple enum dictacting 
instrumentation kind (instead of several variables like it's the case now).

The current plugin core is not really flexible regarding this, but 
hopefully once cleaned with a single pass, we can take a look at this.

      reply	other threads:[~2024-03-14 12:16 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-14 11:49 [RFC PATCH v2] contrib/plugins: control flow plugin (WIP!) Alex Bennée
2024-03-14 12:02 ` Alex Bennée
2024-03-14 12:15   ` Pierrick Bouvier [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c5fae40d-8828-4ecb-b9b1-4d179cca2e74@linaro.org \
    --to=pierrick.bouvier@linaro.org \
    --cc=alex.bennee@linaro.org \
    --cc=erdnaxe@crans.org \
    --cc=gustavo.romero@linaro.org \
    --cc=ma.mandourr@gmail.com \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).