linux/tools/perf/arch/s390/annotate/instructions.c
Arnaldo Carvalho de Melo bc3bb79534 perf annotate: Calculate the max instruction name, align column to that
We were hardcoding '6' as the max instruction name, and we have lots
that are longer than that, see the diff from two 'P' printed TUI
annotations for a libc function that uses instructions with long names,
such as 'vpmovmskb' with its 9 chars:

  --- __strcmp_avx2.annotation.before	2019-03-06 16:31:39.368020425 -0300
  +++ __strcmp_avx2.annotation	2019-03-06 16:32:12.079450508 -0300
  @@ -2,284 +2,284 @@
   Event: cycles:ppp

   Percent        endbr64
  -  0.10         mov    %edi,%eax
  +  0.10         mov        %edi,%eax
  -               xor    %edx,%edx
  +               xor        %edx,%edx
  -  3.54         vpxor  %ymm7,%ymm7,%ymm7
  +  3.54         vpxor      %ymm7,%ymm7,%ymm7
  -               or     %esi,%eax
  +               or         %esi,%eax
  -               and    $0xfff,%eax
  +               and        $0xfff,%eax
  -               cmp    $0xf80,%eax
  +               cmp        $0xf80,%eax
  -             ↓ jg     370
  +             ↓ jg         370
  - 27.07         vmovdqu (%rdi),%ymm1
  + 27.07         vmovdqu    (%rdi),%ymm1
  -  7.97         vpcmpeqb (%rsi),%ymm1,%ymm0
  +  7.97         vpcmpeqb   (%rsi),%ymm1,%ymm0
  -  2.15         vpminub %ymm1,%ymm0,%ymm0
  +  2.15         vpminub    %ymm1,%ymm0,%ymm0
  -  4.09         vpcmpeqb %ymm7,%ymm0,%ymm0
  +  4.09         vpcmpeqb   %ymm7,%ymm0,%ymm0
  -  0.43         vpmovmskb %ymm0,%ecx
  +  0.43         vpmovmskb  %ymm0,%ecx
  -  1.53         test   %ecx,%ecx
  +  1.53         test       %ecx,%ecx
  -             ↓ je     b0
  +             ↓ je         b0
  -  5.26         tzcnt  %ecx,%edx
  +  5.26         tzcnt      %ecx,%edx
  - 18.40         movzbl (%rdi,%rdx,1),%eax
  + 18.40         movzbl     (%rdi,%rdx,1),%eax
  -  7.09         movzbl (%rsi,%rdx,1),%edx
  +  7.09         movzbl     (%rsi,%rdx,1),%edx
  -  3.34         sub    %edx,%eax
  +  3.34         sub        %edx,%eax
     2.37         vzeroupper
                ← retq
                  nop
  -         50:   tzcnt  %ecx,%edx
  +         50:   tzcnt      %ecx,%edx
  -               movzbl 0x20(%rdi,%rdx,1),%eax
  +               movzbl     0x20(%rdi,%rdx,1),%eax
  -               movzbl 0x20(%rsi,%rdx,1),%edx
  +               movzbl     0x20(%rsi,%rdx,1),%edx
  -               sub    %edx,%eax
  +               sub        %edx,%eax
                  vzeroupper
                ← retq
  -               data16 nopw %cs:0x0(%rax,%rax,1)
  +               data16     nopw %cs:0x0(%rax,%rax,1)

Reported-by: Travis Downs <travis.downs@gmail.com>
LPU-Reference: CAOBGo4z1KfmWeOm6Et0cnX5Z6DWsG2PQbAvRn1MhVPJmXHrc5g@mail.gmail.com
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lkml.kernel.org/n/tip-89wsdd9h9g6bvq52sgp6d0u4@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-03-06 16:40:15 -03:00

173 lines
3.6 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include <linux/compiler.h>
static int s390_call__parse(struct arch *arch, struct ins_operands *ops,
struct map_symbol *ms)
{
char *endptr, *tok, *name;
struct map *map = ms->map;
struct addr_map_symbol target = {
.map = map,
};
tok = strchr(ops->raw, ',');
if (!tok)
return -1;
ops->target.addr = strtoull(tok + 1, &endptr, 16);
name = strchr(endptr, '<');
if (name == NULL)
return -1;
name++;
if (arch->objdump.skip_functions_char &&
strchr(name, arch->objdump.skip_functions_char))
return -1;
tok = strchr(name, '>');
if (tok == NULL)
return -1;
*tok = '\0';
ops->target.name = strdup(name);
*tok = '>';
if (ops->target.name == NULL)
return -1;
target.addr = map__objdump_2mem(map, ops->target.addr);
if (map_groups__find_ams(&target) == 0 &&
map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
ops->target.sym = target.sym;
return 0;
}
static int call__scnprintf(struct ins *ins, char *bf, size_t size,
struct ins_operands *ops, int max_ins_name);
static struct ins_ops s390_call_ops = {
.parse = s390_call__parse,
.scnprintf = call__scnprintf,
};
static int s390_mov__parse(struct arch *arch __maybe_unused,
struct ins_operands *ops,
struct map_symbol *ms __maybe_unused)
{
char *s = strchr(ops->raw, ','), *target, *endptr;
if (s == NULL)
return -1;
*s = '\0';
ops->source.raw = strdup(ops->raw);
*s = ',';
if (ops->source.raw == NULL)
return -1;
target = ++s;
ops->target.raw = strdup(target);
if (ops->target.raw == NULL)
goto out_free_source;
ops->target.addr = strtoull(target, &endptr, 16);
if (endptr == target)
goto out_free_target;
s = strchr(endptr, '<');
if (s == NULL)
goto out_free_target;
endptr = strchr(s + 1, '>');
if (endptr == NULL)
goto out_free_target;
*endptr = '\0';
ops->target.name = strdup(s + 1);
*endptr = '>';
if (ops->target.name == NULL)
goto out_free_target;
return 0;
out_free_target:
zfree(&ops->target.raw);
out_free_source:
zfree(&ops->source.raw);
return -1;
}
static struct ins_ops s390_mov_ops = {
.parse = s390_mov__parse,
.scnprintf = mov__scnprintf,
};
static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *name)
{
struct ins_ops *ops = NULL;
/* catch all kind of jumps */
if (strchr(name, 'j') ||
!strncmp(name, "bct", 3) ||
!strncmp(name, "br", 2))
ops = &jump_ops;
/* override call/returns */
if (!strcmp(name, "bras") ||
!strcmp(name, "brasl") ||
!strcmp(name, "basr"))
ops = &s390_call_ops;
if (!strcmp(name, "br"))
ops = &ret_ops;
/* override load/store relative to PC */
if (!strcmp(name, "lrl") ||
!strcmp(name, "lgrl") ||
!strcmp(name, "lgfrl") ||
!strcmp(name, "llgfrl") ||
!strcmp(name, "strl") ||
!strcmp(name, "stgrl"))
ops = &s390_mov_ops;
if (ops)
arch__associate_ins_ops(arch, name, ops);
return ops;
}
static int s390__cpuid_parse(struct arch *arch, char *cpuid)
{
unsigned int family;
char model[16], model_c[16], cpumf_v[16], cpumf_a[16];
int ret;
/*
* cpuid string format:
* "IBM,family,model-capacity,model[,cpum_cf-version,cpum_cf-authorization]"
*/
ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%s", &family, model_c,
model, cpumf_v, cpumf_a);
if (ret >= 2) {
arch->family = family;
arch->model = 0;
return 0;
}
return -1;
}
static int s390__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
int err = 0;
if (!arch->initialized) {
arch->initialized = true;
arch->associate_instruction_ops = s390__associate_ins_ops;
if (cpuid)
err = s390__cpuid_parse(arch, cpuid);
}
return err;
}