Re: [PATCH 2/3] tools/erf/util/annotate: Set register_char and memory_ref_char for powerpc

2024-03-09 Thread Segher Boessenkool
All instructions with a primary opcode from 32 to 63 are memory insns,
and no others.  It's trivial to see whether it is a load or store, too
(just bit 3 of the insn).  Trying to parse disassembled code is much
harder, and you easily make some mistakes here.

On Sat, Mar 09, 2024 at 12:55:12PM +0530, Athira Rajeev wrote:
> To identify if the instruction has any memory reference,
> "memory_ref_char" field needs to be set for specific architecture.
> Example memory instruction:
> lwz r10,0(r9)
> 
> Here "(" is the memory_ref_char. Set this as part of arch->objdump

What about "lwzx r10,0,r19", semantically exactly the same instruction?
There is no paren in there.  Not all instructions using parens are
memory insns, either, not in assembler code at least.

> To get register number and access offset from the given instruction,
> arch->objdump.register_char is used. In case of powerpc, the register
> char is "r" (since reg names are r0 to r31). Hence set register_char
> as "r".

cr0..cr7
r0..r31
f0..f31
v0..v31
vs0..vs63
and many other spellings.  Plain "0..63" is also fine.

The "0" in my lwzx example is a register field as well (and it stands
for "no register", not for "r0").  Called "(RA|0)" usually (incidentally,
see the parens there as well, oh joy).

Don't you have the binary code here as well, not just a disassembled
representation of it?  It is way easier to just use that, and you'll get
much better results that way :-)


Segher


Re: [PATCH 01/19] vdso: Consolidate vdso_calc_delta()

2024-03-09 Thread John Stultz
On Fri, Mar 8, 2024 at 5:15 AM Adrian Hunter  wrote:
>
> Consolidate vdso_calc_delta(), in preparation for further simplification.
>
> Suggested-by: Thomas Gleixner 
> Signed-off-by: Adrian Hunter 
> ---
>  arch/powerpc/include/asm/vdso/gettimeofday.h | 17 ++---
>  arch/s390/include/asm/vdso/gettimeofday.h|  7 ++-
>  lib/vdso/gettimeofday.c  |  4 
>  3 files changed, 8 insertions(+), 20 deletions(-)
>
> --- a/lib/vdso/gettimeofday.c
> +++ b/lib/vdso/gettimeofday.c
> @@ -13,7 +13,11 @@
>  static __always_inline
>  u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
>  {
> +#ifdef VDSO_DELTA_NOMASK
> +   return (cycles - last) * mult;
> +#else
> return ((cycles - last) & mask) * mult;
> +#endif
>  }

Nit: Just for readability, usually we avoid #ifdefs inside of functions.

Instead maybe:
#ifdef VDSO_DELTA_NOMASK
static __always_inline
u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
 {
   return (cycles - last) * mult;
 }
#else
static __always_inline
u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
 {
  return ((cycles - last) & mask) * mult;
 }
#endif


Re: [PATCH 3/3] tools/perf/arch/powerc: Add get_arch_regnum for powerpc

2024-03-09 Thread Christophe Leroy


Le 09/03/2024 à 08:25, Athira Rajeev a écrit :
> The function get_dwarf_regnum() returns a DWARF register number
> from a register name string. This calls arch specific function
> get_arch_regnum to return register number for corresponding arch.
> Add mappings for register name to register number in powerpc code:
> arch/powerpc/util/dwarf-regs.c
> 
> Signed-off-by: Athira Rajeev 
> ---
>   tools/perf/arch/powerpc/util/dwarf-regs.c | 29 +++
>   1 file changed, 29 insertions(+)
> 
> diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c 
> b/tools/perf/arch/powerpc/util/dwarf-regs.c
> index 0c4f4caf53ac..d955e3e577ea 100644
> --- a/tools/perf/arch/powerpc/util/dwarf-regs.c
> +++ b/tools/perf/arch/powerpc/util/dwarf-regs.c
> @@ -98,3 +98,32 @@ int regs_query_register_offset(const char *name)
>   return roff->ptregs_offset;
>   return -EINVAL;
>   }
> +
> +struct dwarf_regs_idx {
> + const char *name;
> + int idx;
> +};
> +
> +static const struct dwarf_regs_idx powerpc_regidx_table[] = {
> + { "r0", 0 }, { "r1", 1 }, { "r2", 2 }, { "r3", 3 }, { "r4", 4 },
> + { "r5", 5 }, { "r6", 6 }, { "r7", 7 }, { "r8", 8 }, { "r9", 9 },
> + { "r10", 10 }, { "r11", 11 }, { "r12", 12 }, { "r13", 13 }, { "r14", 14 
> },
> + { "r15", 15 }, { "r16", 16 }, { "r17", 17 }, { "r18", 18 }, { "r19", 19 
> },
> + { "r20", 20 }, { "r21", 21 }, { "r22", 22 }, { "r23", 23 }, { "r24", 24 
> },
> + { "r25", 25 }, { "r26", 26 }, { "r27", 27 }, { "r27", 27 }, { "r28", 28 
> },
> + { "r29", 29 }, { "r30", 30 }, { "r31", 31 },
> +};
> +
> +int get_arch_regnum(const char *name)
> +{
> + unsigned int i;
> +
> + if (*name != 'r')
> + return -EINVAL;
> +
> + for (i = 0; i < ARRAY_SIZE(powerpc_regidx_table); i++)
> + if (!strcmp(powerpc_regidx_table[i].name, name))
> + return powerpc_regidx_table[i].idx;

Can you do more simple ?

Something like:

int n;

if (*name != 'r')
return -EINVAL;
n = atoi(name + 1);
return n >= 0 && n < 32 ? n : -ENOENT;

> +
> + return -ENOENT;
> +}


Re: [PATCH 1/3] tools/perf/arch/powerpc: Add load/store in powerpc annotate instructions for data type profling

2024-03-09 Thread Christophe Leroy


Le 09/03/2024 à 08:25, Athira Rajeev a écrit :
> Add powerpc instruction nmemonic table to associate load/store
> instructions with move_ops. mov_ops is used to identify mem_type
> to associate instruction with data type and offset. Also initialize
> and allocate arch specific fields for nr_instructions, instructions and
> nr_instructions_allocate.
> 
> Signed-off-by: Athira Rajeev 
> ---
>   .../perf/arch/powerpc/annotate/instructions.c | 66 +++
>   1 file changed, 66 insertions(+)
> 
> diff --git a/tools/perf/arch/powerpc/annotate/instructions.c 
> b/tools/perf/arch/powerpc/annotate/instructions.c
> index a3f423c27cae..07af4442be38 100644
> --- a/tools/perf/arch/powerpc/annotate/instructions.c
> +++ b/tools/perf/arch/powerpc/annotate/instructions.c
> @@ -1,6 +1,65 @@
>   // SPDX-License-Identifier: GPL-2.0
>   #include 
>   
> +/*
> + * powerpc instruction nmemonic table to associate load/store instructions 
> with
> + * move_ops. mov_ops is used to identify mem_type to associate instruction 
> with
> + * data type and offset.
> + */
> +static struct ins powerpc__instructions[] = {
> + { .name = "lbz",.ops = &mov_ops,  },
> + { .name = "lbzx",   .ops = &mov_ops,  },
> + { .name = "lbzu",   .ops = &mov_ops,  },
> + { .name = "lbzux",  .ops = &mov_ops,  },
> + { .name = "lhz",.ops = &mov_ops,  },
> + { .name = "lhzx",   .ops = &mov_ops,  },
> + { .name = "lhzu",   .ops = &mov_ops,  },
> + { .name = "lhzux",  .ops = &mov_ops,  },
> + { .name = "lha",.ops = &mov_ops,  },
> + { .name = "lhax",   .ops = &mov_ops,  },
> + { .name = "lhau",   .ops = &mov_ops,  },
> + { .name = "lhaux",  .ops = &mov_ops,  },
> + { .name = "lwz",.ops = &mov_ops,  },
> + { .name = "lwzx",   .ops = &mov_ops,  },
> + { .name = "lwzu",   .ops = &mov_ops,  },
> + { .name = "lwzux",  .ops = &mov_ops,  },
> + { .name = "lwa",.ops = &mov_ops,  },
> + { .name = "lwax",   .ops = &mov_ops,  },
> + { .name = "lwaux",  .ops = &mov_ops,  },
> + { .name = "ld", .ops = &mov_ops,  },
> + { .name = "ldx",.ops = &mov_ops,  },
> + { .name = "ldu",.ops = &mov_ops,  },
> + { .name = "ldux",   .ops = &mov_ops,  },
> + { .name = "stb",.ops = &mov_ops,  },
> + { .name = "stbx",   .ops = &mov_ops,  },
> + { .name = "stbu",   .ops = &mov_ops,  },
> + { .name = "stbux",  .ops = &mov_ops,  },
> + { .name = "sth",.ops = &mov_ops,  },
> + { .name = "sthx",   .ops = &mov_ops,  },
> + { .name = "sthu",   .ops = &mov_ops,  },
> + { .name = "sthux",  .ops = &mov_ops,  },
> + { .name = "stw",.ops = &mov_ops,  },
> + { .name = "stwx",   .ops = &mov_ops,  },
> + { .name = "stwu",   .ops = &mov_ops,  },
> + { .name = "stwux",  .ops = &mov_ops,  },
> + { .name = "std",.ops = &mov_ops,  },
> + { .name = "stdx",   .ops = &mov_ops,  },
> + { .name = "stdu",   .ops = &mov_ops,  },
> + { .name = "stdux",  .ops = &mov_ops,  },
> + { .name = "lhbrx",  .ops = &mov_ops,  },
> + { .name = "sthbrx", .ops = &mov_ops,  },
> + { .name = "lwbrx",  .ops = &mov_ops,  },
> + { .name = "stwbrx", .ops = &mov_ops,  },
> + { .name = "ldbrx",  .ops = &mov_ops,  },
> + { .name = "stdbrx", .ops = &mov_ops,  },
> + { .name = "lmw",.ops = &mov_ops,  },
> + { .name = "stmw",   .ops = &mov_ops,  },
> + { .name = "lswi",   .ops = &mov_ops,  },
> + { .name = "lswx",   .ops = &mov_ops,  },
> + { .name = "stswi",  .ops = &mov_ops,  },
> + { .name = "stswx",  .ops = &mov_ops,  },
> +};

What about lwarx and stwcx ?

> +
>   static struct ins_ops *powerpc__associate_instruction_ops(struct arch 
> *arch, const char *name)
>   {
>   int i;
> @@ -52,6 +111,13 @@ static struct ins_ops 
> *powerpc__associate_instruction_ops(struct arch *arch, con
>   static int powerpc__annotate_init(struct arch *arch, char *cpuid 
> __maybe_unused)
>   {
>   if (!arch->initialized) {
> + arch->nr_instructions = ARRAY_SIZE(powerpc__instructions);
> + arch->instructions = calloc(arch->nr_instructions, 
> sizeof(struct ins));
> + if (arch->instructions == NULL)

Prefered form is

if (!arch->instructions)

> + return -ENOMEM;
> +
> + memcpy(arch->instructions, (struct ins *)powerpc__instructions, 
> sizeof(struct ins) * arch->nr_instructions);

No need to cast powerpc__instructions, it is already a pointer.


> + arch->nr_instructions_allocated = arch->nr_instructions;
>   arch->initialized = true;
>   arch->associate_instruction_ops = 
> powerpc__associate_instruction_ops;
>   arch->objdump.comment_char  = '#';