Merge tag 'perf-tools-for-v5.18-2022-03-26' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

Pull perf tools updates from Arnaldo Carvalho de Melo:
 "New features:

  perf ftrace:

   - Add -n/--use-nsec option to the 'latency' subcommand.

     Default: usecs:

     $ sudo perf ftrace latency -T dput -a sleep 1
     #   DURATION     |      COUNT | GRAPH                          |
          0 - 1    us |    2098375 | #############################  |
          1 - 2    us |         61 |                                |
          2 - 4    us |         33 |                                |
          4 - 8    us |         13 |                                |
          8 - 16   us |        124 |                                |
         16 - 32   us |        123 |                                |
         32 - 64   us |          1 |                                |
         64 - 128  us |          0 |                                |
        128 - 256  us |          1 |                                |
        256 - 512  us |          0 |                                |

     Better granularity with nsec:

     $ sudo perf ftrace latency -T dput -a -n sleep 1
     #   DURATION     |      COUNT | GRAPH                          |
          0 - 1    us |          0 |                                |
          1 - 2    ns |          0 |                                |
          2 - 4    ns |          0 |                                |
          4 - 8    ns |          0 |                                |
          8 - 16   ns |          0 |                                |
         16 - 32   ns |          0 |                                |
         32 - 64   ns |          0 |                                |
         64 - 128  ns |    1163434 | ##############                 |
        128 - 256  ns |     914102 | #############                  |
        256 - 512  ns |        884 |                                |
        512 - 1024 ns |        613 |                                |
          1 - 2    us |         31 |                                |
          2 - 4    us |         17 |                                |
          4 - 8    us |          7 |                                |
          8 - 16   us |        123 |                                |
         16 - 32   us |         83 |                                |

  perf lock:

   - Add -c/--combine-locks option to merge lock instances in the same
     class into a single entry.

     # perf lock report -c
                    Name acquired contended avg wait(ns) total wait(ns) max wait(ns) min wait(ns)

           rcu_read_lock   251225         0            0              0            0            0
      hrtimer_bases.lock    39450         0            0              0            0            0
     &sb->s_type->i_l...    10301         1          662            662          662          662
        ptlock_ptr(page)    10173         2          701           1402          760          642
     &(ei->i_block_re...     8732         0            0              0            0            0
            &xa->xa_lock     8088         0            0              0            0            0
             &base->lock     6705         0            0              0            0            0
             &p->pi_lock     5549         0            0              0            0            0
     &dentry->d_lockr...     5010         4         1274           5097         1844          789
               &ep->lock     3958         0            0              0            0            0

      - Add -F/--field option to customize the list of fields to output:

     $ perf lock report -F contended,wait_max -k avg_wait
                     Name contended max wait(ns) avg wait(ns)

           slock-AF_INET6         1        23543        23543
        &lruvec->lru_lock         5        18317        11254
           slock-AF_INET6         1        10379        10379
               rcu_node_1         1         2104         2104
      &dentry->d_lockr...         1         1844         1844
      &dentry->d_lockr...         1         1672         1672
         &newf->file_lock        15         2279         1025
      &dentry->d_lockr...         1          792          792

   - Add --synth=no option for record, as there is no need to symbolize,
     lock names comes from the tracepoints.

  perf record:

   - Threaded recording, opt-in, via the new --threads command line
     option.

   - Improve AMD IBS (Instruction-Based Sampling) error handling
     messages.

  perf script:

   - Add 'brstackinsnlen' field (use it with -F) for branch stacks.

   - Output branch sample type in 'perf script'.

  perf report:

   - Add "addr_from" and "addr_to" sort dimensions.

   - Print branch stack entry type in 'perf report --dump-raw-trace'

   - Fix symbolization for chrooted workloads.

  Hardware tracing:

  Intel PT:

   - Add CFE (Control Flow Event) and EVD (Event Data) packets support.

   - Add MODE.Exec IFLAG bit support.

     Explanation about these features from the "Intel® 64 and IA-32
     architectures software developer’s manual combined volumes: 1, 2A,
     2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4" PDF at:

        https://cdrdv2.intel.com/v1/dl/getContent/671200

     At page 3951:
      "32.2.4

       Event Trace is a capability that exposes details about the
       asynchronous events, when they are generated, and when their
       corresponding software event handler completes execution. These
       include:

        o Interrupts, including NMI and SMI, including the interrupt
          vector when defined.

        o Faults, exceptions including the fault vector.

           - Page faults additionally include the page fault address,
             when in context.

        o Event handler returns, including IRET and RSM.

        o VM exits and VM entries.¹

           - VM exits include the values written to the “exit reason”
             and “exit qualification” VMCS fields. INIT and SIPI events.

        o TSX aborts, including the abort status returned for the RTM
          instructions.

        o Shutdown.

       Additionally, it provides indication of the status of the
       Interrupt Flag (IF), to indicate when interrupts are masked"

  ARM CoreSight:

   - Use advertised caps/min_interval as default sample_period on ARM
     spe.

   - Update deduction of TRCCONFIGR register for branch broadcast on
     ARM's CoreSight ETM.

  Vendor Events (JSON):

  Intel:

   - Update events and metrics for: Alderlake, Broadwell, Broadwell DE,
     BroadwellX, CascadelakeX, Elkhartlake, Bonnell, Goldmont,
     GoldmontPlus, Westmere EP-DP, Haswell, HaswellX, Icelake, IcelakeX,
     Ivybridge, Ivytown, Jaketown, Knights Landing, Nehalem EP,
     Sandybridge, Silvermont, Skylake, Skylake Server, SkylakeX,
     Tigerlake, TremontX, Westmere EP-SP, and Westmere EX.

  ARM:

   - Add support for HiSilicon CPA PMU aliasing.

  perf stat:

   - Fix forked applications enablement of counters.

   - The 'slots' should only be printed on a different order than the
     one specified on the command line when 'topdown' events are
     present, fix it.

  Miscellaneous:

   - Sync msr-index, cpufeatures header files with the kernel sources.

   - Stop using some deprecated libbpf APIs in 'perf trace'.

   - Fix some spelling mistakes.

   - Refactor the maps pointers usage to pave the way for using refcount
     debugging.

   - Only offer the --tui option on perf top, report and annotate when
     perf was built with libslang.

   - Don't mention --to-ctf in 'perf data --help' when not linking with
     the required library, libbabeltrace.

   - Use ARRAY_SIZE() instead of ad hoc equivalent, spotted by
     array_size.cocci.

   - Enhance the matching of sub-commands abbreviations:
	'perf c2c rec' -> 'perf c2c record'
	'perf c2c recport -> error

   - Set build-id using build-id header on new mmap records.

   - Fix generation of 'perf --version' string.

  perf test:

   - Add test for the arm_spe event.

   - Add test to check unwinding using fame-pointer (fp) mode on arm64.

   - Make metric testing more robust in 'perf test'.

   - Add error message for unsupported branch stack cases.

  libperf:

   - Add API for allocating new thread map array.

   - Fix typo in perf_evlist__open() failure error messages in libperf
     tests.

  perf c2c:

   - Replace bitmap_weight() with bitmap_empty() where appropriate"

* tag 'perf-tools-for-v5.18-2022-03-26' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux: (143 commits)
  perf evsel: Improve AMD IBS (Instruction-Based Sampling) error handling messages
  perf python: Add perf_env stubs that will be needed in evsel__open_strerror()
  perf tools: Enhance the matching of sub-commands abbreviations
  libperf tests: Fix typo in perf_evlist__open() failure error messages
  tools arm64: Import cputype.h
  perf lock: Add -F/--field option to control output
  perf lock: Extend struct lock_key to have print function
  perf lock: Add --synth=no option for record
  tools headers cpufeatures: Sync with the kernel sources
  tools headers cpufeatures: Sync with the kernel sources
  perf stat: Fix forked applications enablement of counters
  tools arch x86: Sync the msr-index.h copy with the kernel sources
  perf evsel: Make evsel__env() always return a valid env
  perf build-id: Fix spelling mistake "Cant" -> "Can't"
  perf header: Fix spelling mistake "could't" -> "couldn't"
  perf script: Add 'brstackinsnlen' for branch stacks
  perf parse-events: Move slots only with topdown
  perf ftrace latency: Update documentation
  perf ftrace latency: Add -n/--use-nsec option
  perf tools: Fix version kernel tag
  ...
This commit is contained in:
Linus Torvalds
2022-03-27 13:42:32 -07:00
329 changed files with 94225 additions and 77611 deletions

View File

@@ -26,6 +26,8 @@
#include "util.h"
#include "llvm-utils.h"
#include "c++/clang-c.h"
#include "hashmap.h"
#include "asm/bug.h"
#include <internal/xyarray.h>
@@ -49,8 +51,54 @@ struct bpf_prog_priv {
int *type_mapping;
};
struct bpf_perf_object {
struct list_head list;
struct bpf_object *obj;
};
static LIST_HEAD(bpf_objects_list);
static struct hashmap *bpf_program_hash;
static struct hashmap *bpf_map_hash;
static struct bpf_perf_object *
bpf_perf_object__next(struct bpf_perf_object *prev)
{
struct bpf_perf_object *next;
if (!prev)
next = list_first_entry(&bpf_objects_list,
struct bpf_perf_object,
list);
else
next = list_next_entry(prev, list);
/* Empty list is noticed here so don't need checking on entry. */
if (&next->list == &bpf_objects_list)
return NULL;
return next;
}
#define bpf_perf_object__for_each(perf_obj, tmp) \
for ((perf_obj) = bpf_perf_object__next(NULL), \
(tmp) = bpf_perf_object__next(perf_obj); \
(perf_obj) != NULL; \
(perf_obj) = (tmp), (tmp) = bpf_perf_object__next(tmp))
static bool libbpf_initialized;
static int bpf_perf_object__add(struct bpf_object *obj)
{
struct bpf_perf_object *perf_obj = zalloc(sizeof(*perf_obj));
if (perf_obj) {
INIT_LIST_HEAD(&perf_obj->list);
perf_obj->obj = obj;
list_add_tail(&perf_obj->list, &bpf_objects_list);
}
return perf_obj ? 0 : -ENOMEM;
}
struct bpf_object *
bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
{
@@ -68,9 +116,21 @@ bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
return ERR_PTR(-EINVAL);
}
if (bpf_perf_object__add(obj)) {
bpf_object__close(obj);
return ERR_PTR(-ENOMEM);
}
return obj;
}
static void bpf_perf_object__close(struct bpf_perf_object *perf_obj)
{
list_del(&perf_obj->list);
bpf_object__close(perf_obj->obj);
free(perf_obj);
}
struct bpf_object *bpf__prepare_load(const char *filename, bool source)
{
LIBBPF_OPTS(bpf_object_open_opts, opts, .object_name = filename);
@@ -102,29 +162,25 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
llvm__dump_obj(filename, obj_buf, obj_buf_sz);
free(obj_buf);
} else
} else {
obj = bpf_object__open(filename);
}
if (IS_ERR_OR_NULL(obj)) {
pr_debug("bpf: failed to load %s\n", filename);
return obj;
}
if (bpf_perf_object__add(obj)) {
bpf_object__close(obj);
return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
}
return obj;
}
void bpf__clear(void)
{
struct bpf_object *obj, *tmp;
bpf_object__for_each_safe(obj, tmp) {
bpf__unprobe(obj);
bpf_object__close(obj);
}
}
static void
clear_prog_priv(struct bpf_program *prog __maybe_unused,
clear_prog_priv(const struct bpf_program *prog __maybe_unused,
void *_priv)
{
struct bpf_prog_priv *priv = _priv;
@@ -137,6 +193,83 @@ clear_prog_priv(struct bpf_program *prog __maybe_unused,
free(priv);
}
static void bpf_program_hash_free(void)
{
struct hashmap_entry *cur;
size_t bkt;
if (IS_ERR_OR_NULL(bpf_program_hash))
return;
hashmap__for_each_entry(bpf_program_hash, cur, bkt)
clear_prog_priv(cur->key, cur->value);
hashmap__free(bpf_program_hash);
bpf_program_hash = NULL;
}
static void bpf_map_hash_free(void);
void bpf__clear(void)
{
struct bpf_perf_object *perf_obj, *tmp;
bpf_perf_object__for_each(perf_obj, tmp) {
bpf__unprobe(perf_obj->obj);
bpf_perf_object__close(perf_obj);
}
bpf_program_hash_free();
bpf_map_hash_free();
}
static size_t ptr_hash(const void *__key, void *ctx __maybe_unused)
{
return (size_t) __key;
}
static bool ptr_equal(const void *key1, const void *key2,
void *ctx __maybe_unused)
{
return key1 == key2;
}
static void *program_priv(const struct bpf_program *prog)
{
void *priv;
if (IS_ERR_OR_NULL(bpf_program_hash))
return NULL;
if (!hashmap__find(bpf_program_hash, prog, &priv))
return NULL;
return priv;
}
static int program_set_priv(struct bpf_program *prog, void *priv)
{
void *old_priv;
/*
* Should not happen, we warn about it in the
* caller function - config_bpf_program
*/
if (IS_ERR(bpf_program_hash))
return PTR_ERR(bpf_program_hash);
if (!bpf_program_hash) {
bpf_program_hash = hashmap__new(ptr_hash, ptr_equal, NULL);
if (IS_ERR(bpf_program_hash))
return PTR_ERR(bpf_program_hash);
}
old_priv = program_priv(prog);
if (old_priv) {
clear_prog_priv(prog, old_priv);
return hashmap__set(bpf_program_hash, prog, priv, NULL, NULL);
}
return hashmap__add(bpf_program_hash, prog, priv);
}
static int
prog_config__exec(const char *value, struct perf_probe_event *pev)
{
@@ -378,7 +511,7 @@ config_bpf_program(struct bpf_program *prog)
pr_debug("bpf: config '%s' is ok\n", config_str);
set_priv:
err = bpf_program__set_priv(prog, priv, clear_prog_priv);
err = program_set_priv(prog, priv);
if (err) {
pr_debug("Failed to set priv for program '%s'\n", config_str);
goto errout;
@@ -419,7 +552,7 @@ preproc_gen_prologue(struct bpf_program *prog, int n,
struct bpf_insn *orig_insns, int orig_insns_cnt,
struct bpf_prog_prep_result *res)
{
struct bpf_prog_priv *priv = bpf_program__priv(prog);
struct bpf_prog_priv *priv = program_priv(prog);
struct probe_trace_event *tev;
struct perf_probe_event *pev;
struct bpf_insn *buf;
@@ -570,7 +703,7 @@ static int map_prologue(struct perf_probe_event *pev, int *mapping,
static int hook_load_preprocessor(struct bpf_program *prog)
{
struct bpf_prog_priv *priv = bpf_program__priv(prog);
struct bpf_prog_priv *priv = program_priv(prog);
struct perf_probe_event *pev;
bool need_prologue = false;
int err, i;
@@ -646,7 +779,7 @@ int bpf__probe(struct bpf_object *obj)
if (err)
goto out;
priv = bpf_program__priv(prog);
priv = program_priv(prog);
if (IS_ERR_OR_NULL(priv)) {
if (!priv)
err = -BPF_LOADER_ERRNO__INTERNAL;
@@ -698,7 +831,7 @@ int bpf__unprobe(struct bpf_object *obj)
struct bpf_program *prog;
bpf_object__for_each_program(prog, obj) {
struct bpf_prog_priv *priv = bpf_program__priv(prog);
struct bpf_prog_priv *priv = program_priv(prog);
int i;
if (IS_ERR_OR_NULL(priv) || priv->is_tp)
@@ -754,7 +887,7 @@ int bpf__foreach_event(struct bpf_object *obj,
int err;
bpf_object__for_each_program(prog, obj) {
struct bpf_prog_priv *priv = bpf_program__priv(prog);
struct bpf_prog_priv *priv = program_priv(prog);
struct probe_trace_event *tev;
struct perf_probe_event *pev;
int i, fd;
@@ -850,7 +983,7 @@ bpf_map_priv__purge(struct bpf_map_priv *priv)
}
static void
bpf_map_priv__clear(struct bpf_map *map __maybe_unused,
bpf_map_priv__clear(const struct bpf_map *map __maybe_unused,
void *_priv)
{
struct bpf_map_priv *priv = _priv;
@@ -859,6 +992,53 @@ bpf_map_priv__clear(struct bpf_map *map __maybe_unused,
free(priv);
}
static void *map_priv(const struct bpf_map *map)
{
void *priv;
if (IS_ERR_OR_NULL(bpf_map_hash))
return NULL;
if (!hashmap__find(bpf_map_hash, map, &priv))
return NULL;
return priv;
}
static void bpf_map_hash_free(void)
{
struct hashmap_entry *cur;
size_t bkt;
if (IS_ERR_OR_NULL(bpf_map_hash))
return;
hashmap__for_each_entry(bpf_map_hash, cur, bkt)
bpf_map_priv__clear(cur->key, cur->value);
hashmap__free(bpf_map_hash);
bpf_map_hash = NULL;
}
static int map_set_priv(struct bpf_map *map, void *priv)
{
void *old_priv;
if (WARN_ON_ONCE(IS_ERR(bpf_map_hash)))
return PTR_ERR(bpf_program_hash);
if (!bpf_map_hash) {
bpf_map_hash = hashmap__new(ptr_hash, ptr_equal, NULL);
if (IS_ERR(bpf_map_hash))
return PTR_ERR(bpf_map_hash);
}
old_priv = map_priv(map);
if (old_priv) {
bpf_map_priv__clear(map, old_priv);
return hashmap__set(bpf_map_hash, map, priv, NULL, NULL);
}
return hashmap__add(bpf_map_hash, map, priv);
}
static int
bpf_map_op_setkey(struct bpf_map_op *op, struct parse_events_term *term)
{
@@ -958,7 +1138,7 @@ static int
bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op)
{
const char *map_name = bpf_map__name(map);
struct bpf_map_priv *priv = bpf_map__priv(map);
struct bpf_map_priv *priv = map_priv(map);
if (IS_ERR(priv)) {
pr_debug("Failed to get private from map %s\n", map_name);
@@ -973,7 +1153,7 @@ bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op)
}
INIT_LIST_HEAD(&priv->ops_list);
if (bpf_map__set_priv(map, priv, bpf_map_priv__clear)) {
if (map_set_priv(map, priv)) {
free(priv);
return -BPF_LOADER_ERRNO__INTERNAL;
}
@@ -1305,7 +1485,7 @@ bpf_map_config_foreach_key(struct bpf_map *map,
int err, map_fd, type;
struct bpf_map_op *op;
const char *name = bpf_map__name(map);
struct bpf_map_priv *priv = bpf_map__priv(map);
struct bpf_map_priv *priv = map_priv(map);
if (IS_ERR(priv)) {
pr_debug("ERROR: failed to get private from map %s\n", name);
@@ -1494,11 +1674,11 @@ apply_obj_config_object(struct bpf_object *obj)
int bpf__apply_obj_config(void)
{
struct bpf_object *obj, *tmp;
struct bpf_perf_object *perf_obj, *tmp;
int err;
bpf_object__for_each_safe(obj, tmp) {
err = apply_obj_config_object(obj);
bpf_perf_object__for_each(perf_obj, tmp) {
err = apply_obj_config_object(perf_obj->obj);
if (err)
return err;
}
@@ -1506,27 +1686,25 @@ int bpf__apply_obj_config(void)
return 0;
}
#define bpf__for_each_map(pos, obj, objtmp) \
bpf_object__for_each_safe(obj, objtmp) \
bpf_object__for_each_map(pos, obj)
#define bpf__perf_for_each_map(map, pobj, tmp) \
bpf_perf_object__for_each(pobj, tmp) \
bpf_object__for_each_map(map, pobj->obj)
#define bpf__for_each_map_named(pos, obj, objtmp, name) \
bpf__for_each_map(pos, obj, objtmp) \
if (bpf_map__name(pos) && \
(strcmp(name, \
bpf_map__name(pos)) == 0))
#define bpf__perf_for_each_map_named(map, pobj, pobjtmp, name) \
bpf__perf_for_each_map(map, pobj, pobjtmp) \
if (bpf_map__name(map) && (strcmp(name, bpf_map__name(map)) == 0))
struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name)
{
struct bpf_map_priv *tmpl_priv = NULL;
struct bpf_object *obj, *tmp;
struct bpf_perf_object *perf_obj, *tmp;
struct evsel *evsel = NULL;
struct bpf_map *map;
int err;
bool need_init = false;
bpf__for_each_map_named(map, obj, tmp, name) {
struct bpf_map_priv *priv = bpf_map__priv(map);
bpf__perf_for_each_map_named(map, perf_obj, tmp, name) {
struct bpf_map_priv *priv = map_priv(map);
if (IS_ERR(priv))
return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL);
@@ -1561,8 +1739,8 @@ struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name)
evsel = evlist__last(evlist);
}
bpf__for_each_map_named(map, obj, tmp, name) {
struct bpf_map_priv *priv = bpf_map__priv(map);
bpf__perf_for_each_map_named(map, perf_obj, tmp, name) {
struct bpf_map_priv *priv = map_priv(map);
if (IS_ERR(priv))
return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL);
@@ -1574,7 +1752,7 @@ struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name)
if (!priv)
return ERR_PTR(-ENOMEM);
err = bpf_map__set_priv(map, priv, bpf_map_priv__clear);
err = map_set_priv(map, priv);
if (err) {
bpf_map_priv__clear(map, priv);
return ERR_PTR(err);