qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] Instruction trace for ARM target
@ 2008-04-02 19:28 Klaus Goffart
  2008-04-03 14:13 ` Stuart Brady
  0 siblings, 1 reply; 4+ messages in thread
From: Klaus Goffart @ 2008-04-02 19:28 UTC (permalink / raw)
  To: qemu-devel

Hi,

I would like to generate an instruction trace for an ARM target. I
applied the patch from Stuart Brady posted in this thread
http://thread.gmane.org/gmane.comp.emulators.qemu/16604
to the corresponding "arm-target/*" files. It seems to work fine and
generates a trace of pc values. 

But, I'm not sure if these are all pc values. I do not completely
understand the way the helper_dump_pc() method is called, but it seems
that it is triggered in the disas_insn() respectively the
disas_arm_insn() method. But isn't each instruction just disassembled
once and then cached for the next execution? Then the corresponding pc
values would be missing.

To get the instructions being executed I call the ldl_code() method with
the actual pc value in the helper_dump_pc() method. It seems to work,
but it would be great if anybody could just point out if this is
correct.

My next step is to mark those instructions that are not executed due to
their condition codes and the memory accessed by executed instructions.
But I have no idea where this information is available. Can anybody give
me a clue?

I appreciate any help!

Thanks,

Klaus

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] Instruction trace for ARM target
  2008-04-02 19:28 [Qemu-devel] Instruction trace for ARM target Klaus Goffart
@ 2008-04-03 14:13 ` Stuart Brady
  2008-04-04 15:10   ` Klaus Goffart
  0 siblings, 1 reply; 4+ messages in thread
From: Stuart Brady @ 2008-04-03 14:13 UTC (permalink / raw)
  To: qemu-devel

On Wed, Apr 02, 2008 at 09:28:19PM +0200, Klaus Goffart wrote:
> But, I'm not sure if these are all pc values. I do not completely
> understand the way the helper_dump_pc() method is called, but it seems
> that it is triggered in the disas_insn() respectively the
> disas_arm_insn() method. But isn't each instruction just disassembled
> once and then cached for the next execution? Then the corresponding pc
> values would be missing.

That's why disas_insn() should call gen_op_dump_pc(), instead of calling
helper_dump_pc() directly.  Calling gen_op_dump_pc() adds the code
needed to call helper_dump_pc() to the translation block that is
currently being generated.

Actually, with the code in SVN, you'd probably want something like:

    tcg_gen_helper_0_1(helper_dump_pc, tcg_const_ptr(s->pc));

You would then no longer need op_dump_pc().

The program counter isn't updated after each instruction is executed for
performance reasons, so it's passed as a parameter during translation,
whenever it is needed.  On the other hand, when the program counter is
finally updated (e.g. after a conditional branch) you often can't
determine its new value at translation time -- but where the instruction
fetch occurs, this isn't a problem!

> To get the instructions being executed I call the ldl_code() method with
> the actual pc value in the helper_dump_pc() method. It seems to work,
> but it would be great if anybody could just point out if this is
> correct.

If by 'actualy pc value', you mean the PC in the CPUState ('env'), then
I'm very surprised that this would appear to produce correct output.

> My next step is to mark those instructions that are not executed due to
> their condition codes and the memory accessed by executed instructions.
> But I have no idea where this information is available. Can anybody give
> me a clue?

Well, you'd certainly have to generate extra ops to mark instructions as
executed, as instruction fetches occur at translation time.  For memory
access, you could modify the memory accessors to perform the marking...
probably by adding helper calls in tcg-op.h.

Cheers,
-- 
Stuart Brady

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] Instruction trace for ARM target
  2008-04-03 14:13 ` Stuart Brady
@ 2008-04-04 15:10   ` Klaus Goffart
  2008-04-07 21:58     ` Stuart Brady
  0 siblings, 1 reply; 4+ messages in thread
From: Klaus Goffart @ 2008-04-04 15:10 UTC (permalink / raw)
  To: qemu-devel

Hi,

first of all, thanks for your help.

Am Donnerstag, den 03.04.2008, 15:13 +0100 schrieb Stuart Brady: 
> On Wed, Apr 02, 2008 at 09:28:19PM +0200, Klaus Goffart wrote:
> > But, I'm not sure if these are all pc values. I do not completely
> > understand the way the helper_dump_pc() method is called, but it seems
> > that it is triggered in the disas_insn() respectively the
> > disas_arm_insn() method. But isn't each instruction just disassembled
> > once and then cached for the next execution? Then the corresponding pc
> > values would be missing.
> 
> That's why disas_insn() should call gen_op_dump_pc(), instead of calling
> helper_dump_pc() directly. 

OK. This was my first approach, so it missed pc values of reused code
blocks.

> Calling gen_op_dump_pc() adds the code
> needed to call helper_dump_pc() to the translation block that is
> currently being generated.

Just to make sure I picked it up right. The call of gen_op_dump_pc()
during translation adds the op_dump_pc() to the generated micro
instruction stream of the translation block. When the TB is executed,
the op_dump_pc() operation is called, calling helper_dump_pc() with
PARAM1. PARAM1 in op_dump_pc() is the first parameter passed to
gen_op_dump_pc(), i.e. s->pc. So the pc values to be traced are included
into the micro instruction stream and printed at execution time, right?

> The program counter isn't updated after each instruction is executed for
> performance reasons, so it's passed as a parameter during translation,
> whenever it is needed.  On the other hand, when the program counter is
> finally updated (e.g. after a conditional branch) you often can't
> determine its new value at translation time -- but where the instruction
> fetch occurs, this isn't a problem!
> 
> > To get the instructions being executed I call the ldl_code() method with
> > the actual pc value in the helper_dump_pc() method. It seems to work,
> > but it would be great if anybody could just point out if this is
> > correct.
> 
> If by 'actualy pc value', you mean the PC in the CPUState ('env'), then
> I'm very surprised that this would appear to produce correct output.

No, my helper_dump_pc() looks like this:

void helper_dump_pc(target_ulong pc) 
{
    if (logfile)
    {
	fputc('#', logfile);
        fwrite(&pc, sizeof(pc), 1, logfile);
        insn = ldl_code(pc);
        fwrite(&insn, sizeof(insn), 1, logfile);
    }	
}

> > My next step is to mark those instructions that are not executed due to
> > their condition codes and the memory accessed by executed instructions.
> > But I have no idea where this information is available. Can anybody give
> > me a clue?
> 
> Well, you'd certainly have to generate extra ops to mark instructions as
> executed, as instruction fetches occur at translation time. 

OK, so conditional instructions are skipped by a jump to the next
instruction if the condition code fails. This is what I found in the
documentation. In the code it looks like this jump is also a micro
operation. Therefore, an op should be placed right after the jump_op
that marks the last dumped instruction as executed. Is this what you
meant?

Thanks!

Klaus

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] Instruction trace for ARM target
  2008-04-04 15:10   ` Klaus Goffart
@ 2008-04-07 21:58     ` Stuart Brady
  0 siblings, 0 replies; 4+ messages in thread
From: Stuart Brady @ 2008-04-07 21:58 UTC (permalink / raw)
  To: qemu-devel

On Fri, Apr 04, 2008 at 05:10:51PM +0200, Klaus Goffart wrote:
> Am Donnerstag, den 03.04.2008, 15:13 +0100 schrieb Stuart Brady: 
> > Calling gen_op_dump_pc() adds the code
> > needed to call helper_dump_pc() to the translation block that is
> > currently being generated.
> 
> Just to make sure I picked it up right. The call of gen_op_dump_pc()
> during translation adds the op_dump_pc() to the generated micro
> instruction stream of the translation block.

That's right.

> When the TB is executed, the op_dump_pc() operation is called

Well, op_dump_pc() is never called, as its code is instead copied into
the generated TB, but I think that's what you meant anyway.

> calling helper_dump_pc() with PARAM1. PARAM1 in op_dump_pc() is the
> first parameter passed to gen_op_dump_pc(), i.e. s->pc. So the pc
> values to be traced are included into the micro instruction stream 
> and printed at execution time, right?

That's correct.  It would be better to avoid an immediate load of the
emulated PC for each instruction -- with dyngen, doing so would not be
very practical, as we'd really prefer to hold the emulated PC in an
extra register -- but with TCG, that shouldn't really be a problem.

> > If by 'actual pc value', you mean the PC in the CPUState ('env'), then
> > I'm very surprised that this would appear to produce correct output.
> 
> No, my helper_dump_pc() looks like this:
> 
> void helper_dump_pc(target_ulong pc) 
> {
>     if (logfile)
>     {
> 	fputc('#', logfile);
>         fwrite(&pc, sizeof(pc), 1, logfile);
>         insn = ldl_code(pc);
>         fwrite(&insn, sizeof(insn), 1, logfile);
>     }	
> }

Okay, that looks roughly correct -- although if you plan for anyone else
to use that code, it would be preferable to produce the same output on
big-endian and little-endian machines.

> > Well, you'd certainly have to generate extra ops to mark instructions as
> > executed, as instruction fetches occur at translation time. 
> 
> OK, so conditional instructions are skipped by a jump to the next
> instruction if the condition code fails. This is what I found in the
> documentation. In the code it looks like this jump is also a micro
> operation. Therefore, an op should be placed right after the jump_op
> that marks the last dumped instruction as executed. Is this what you
> meant?

Actually, I'd forgotten about ARM's conditional execution, and was
talking about conditional branches.  I expect that translated code can
still be generated after a conditional branch, but never executed, as a
result of that branch always (or perhaps never) being taken.

What I meant was that you cannot mark instructions as executed by adding
extra code to ldl_code(), but thanks to conditional execution, that was
already rather more obvious than I had realised.

Placing the dump_pc op after the jump op sounds correct, but you'll also
need to deal with unconditional instructions, and conditional branches.
Bear in mind that the program counter is incremented after ldl_code() is
called, though.

I wonder, does a branch count as 'executed' if and only if it is taken?
What about branches with static 'taken' or 'not taken' prediction?

Cheers,
-- 
Stuart Brady

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2008-04-07 21:58 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-02 19:28 [Qemu-devel] Instruction trace for ARM target Klaus Goffart
2008-04-03 14:13 ` Stuart Brady
2008-04-04 15:10   ` Klaus Goffart
2008-04-07 21:58     ` Stuart Brady

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).